From ef19c01cb7db8b400b75fa79c143d03f0037cbc8 Mon Sep 17 00:00:00 2001 From: Graeme Geldenhuys Date: Mon, 22 Jun 2026 14:16:21 +0100 Subject: [PATCH] fix(codegen): QBE stores float to implicit-Self field with stored/stores Assigning a float value to a class field via an implicit Self reference (e.g. `V := d` in a method/constructor where V: Double) emitted a hardcoded `storel` on a `d`/`s` SSA value, which QBE rejects ("invalid type for first operand in storel"). The implicit-Self field-store path in EmitAssignment fell through to a literal `storel` instead of StoreInstrFor(field type), and lacked the d<->s width coercion the EmitFieldAssignment path already has. Use StoreInstrFor(ISFld.TypeDesc) (-> stored/stores for tyDouble/tySingle) and add the Single<->Double truncd/exts coercion before the store. Surfaced by the new float-constructor e2e tests, which run on both backends. --- .../src/main/pascal/blaise.codegen.qbe.pas | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/compiler/src/main/pascal/blaise.codegen.qbe.pas b/compiler/src/main/pascal/blaise.codegen.qbe.pas index 871e53e..d28a126 100644 --- a/compiler/src/main/pascal/blaise.codegen.qbe.pas +++ b/compiler/src/main/pascal/blaise.codegen.qbe.pas @@ -4056,7 +4056,24 @@ begin EmitLine(Format(' call $_ClassAddRef(l %s)', [ValTemp])); EmitLine(Format(' call $_ClassRelease(l %s)', [OldTemp])); end; - EmitLine(Format(' storel %s, %s', [ValTemp, ObjTemp])); + { Float-width coercion before the store: a real-typed RHS lands in the + SSA as 'd' even when the field is a 32-bit Single ('s'), and vice + versa. Without this an implicit-Self 'V := d' float-field store + emitted 'storel' on a 'd' value — a QBE type error. } + if (QType = 's') and (QbeTypeOf(AAssign.Expr.ResolvedType) = 'd') then + begin + ExtTemp := AllocTemp(); + EmitLine(Format(' %s =s truncd %s', [ExtTemp, ValTemp])); + ValTemp := ExtTemp; + end + else if (QType = 'd') and (QbeTypeOf(AAssign.Expr.ResolvedType) = 's') then + begin + ExtTemp := AllocTemp(); + EmitLine(Format(' %s =d exts %s', [ExtTemp, ValTemp])); + ValTemp := ExtTemp; + end; + EmitLine(Format(' %s %s, %s', + [StoreInstrFor(ISFld.TypeDesc), ValTemp, ObjTemp])); end; Exit; end;