hand source: implement QBE sret convention for record-returning functions

Add the full structure-return (sret) convention to the hand source so
stage-2 generates correct IR for functions/methods that return tyRecord:

- EmitMethodDef/EmitFuncDef: declare record-returning functions as void
  with a hidden first param `l %_par__sret`; initialise %_var_Result
  from it; emit bare `ret` at exit.

- IsRecordCall / EmitRecordCallSret: detect record-returning call
  expressions (TFuncCallExpr, TMethodCallExpr, TFieldAccessExpr) and
  emit them with the sret address as the first argument.  Handles the
  IsImplicitSelf path with correct Self+offset pointer arithmetic.

- EmitRecordCopy / EmitRecordReleaseFields: field-by-field ARC-correct
  copy and release helpers for record types.

- EmitAssignment tyRecord branch: for record-typed lhs, either call
  EmitRecordCallSret (when the rhs is a call) or EmitRecordCopy.

- ImplicitSelfField tyRecord branch in EmitAssignment: same logic for
  assignments to record fields reached via implicit Self.

- TIdentExpr IsImplicitSelf tyRecord fix: return the field address
  rather than loading through it (callers need the address for copies).

- TIdentExpr local/global record variable fix: return VarRef address
  directly instead of an extra loadl.

All fixes mirror what the real multi-file source already had; this
brings the hand source to parity for record-return code generation.
This commit is contained in:
Graeme Geldenhuys 2026-04-25 19:44:30 +01:00
parent c547ab2f16
commit cf923852bd

View file

@ -8999,6 +8999,10 @@ type
procedure EmitStandaloneDefs(AProg: TProgram);
procedure EmitStandaloneDef(ADecl: TMethodDecl);
procedure EmitFuncDef(ADecl: TMethodDecl; AExported: Boolean);
function IsRecordCall(AExpr: TASTExpr): Boolean;
procedure EmitRecordCopy(ARec: TRecordTypeDesc; const ADestAddr, ASrcAddr: string);
procedure EmitRecordCallSret(AExpr: TASTExpr; const ASretAddr: string);
procedure EmitRecordReleaseFields(ARec: TRecordTypeDesc; const AAddr: string);
procedure EmitBlock(ABlock: TBlock);
procedure EmitVarAllocs(ABlock: TBlock);
procedure EmitGlobalVarData(ABlock: TBlock);
@ -9747,7 +9751,6 @@ begin
if AAssign.ImplicitSelfField <> nil then
begin
ISFld := TFieldInfo(AAssign.ImplicitSelfField);
ValTemp := EmitExpr(AAssign.Expr);
ObjTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %%_var_Self', ObjTemp));
if ISFld.Offset > 0 then
@ -9756,6 +9759,23 @@ begin
EmitLine(Format(' %s =l add %s, %d', ISAddrT, ObjTemp, ISFld.Offset));
ObjTemp := ISAddrT;
end;
if ISFld.TypeDesc.Kind = tyRecord then
begin
ClassRT := TRecordTypeDesc(ISFld.TypeDesc);
if IsRecordCall(AAssign.Expr) then
begin
EmitRecordReleaseFields(ClassRT, ObjTemp);
EmitLine(Format(' call $memset(l %s, w 0, l %d)', ObjTemp, ClassRT.TotalSize));
EmitRecordCallSret(AAssign.Expr, ObjTemp);
end
else
begin
ValTemp := EmitExpr(AAssign.Expr);
EmitRecordCopy(ClassRT, ObjTemp, ValTemp);
end;
Exit;
end;
ValTemp := EmitExpr(AAssign.Expr);
QType := QbeTypeOf(ISFld.TypeDesc);
if QType = 'w' then
EmitLine(Format(' storew %s, %s', ValTemp, ObjTemp))
@ -9868,7 +9888,6 @@ begin
if AAssign.IsVarParam then
begin
QType := QbeTypeOf(AAssign.Expr.ResolvedType);
ValTemp := EmitExpr(AAssign.Expr);
PtrTemp := AllocTemp;
@ -9877,6 +9896,22 @@ begin
else StoreInstr := 'storel';
EmitLine(Format(' %s %s, %s', StoreInstr, ValTemp, PtrTemp));
end
else if (AAssign.ResolvedLhsType <> nil) and
(AAssign.ResolvedLhsType.Kind = tyRecord) then
begin
ClassRT := TRecordTypeDesc(AAssign.ResolvedLhsType);
if IsRecordCall(AAssign.Expr) then
begin
EmitRecordReleaseFields(ClassRT, VarRef(AAssign.Name, AAssign.IsGlobal));
EmitLine(Format(' call $memset(l %s, w 0, l %d)', VarRef(AAssign.Name, AAssign.IsGlobal), ClassRT.TotalSize));
EmitRecordCallSret(AAssign.Expr, VarRef(AAssign.Name, AAssign.IsGlobal));
end
else
begin
ValTemp := EmitExpr(AAssign.Expr);
EmitRecordCopy(ClassRT, VarRef(AAssign.Name, AAssign.IsGlobal), ValTemp);
end;
end
else if AAssign.Expr.ResolvedType.IsString then
begin
@ -10506,7 +10541,13 @@ begin
if IsFunc then
begin
RetQType := QbeTypeOf(AMethod.ResolvedReturnType);
EmitLine(Format('function %s %s(%s) {', RetQType, FuncName, Sig));
if AMethod.ResolvedReturnType.Kind = tyRecord then
begin
Sig := 'l %_par__sret, ' + Sig;
EmitLine(Format('function %s(%s) {', FuncName, Sig));
end
else
EmitLine(Format('function %s %s(%s) {', RetQType, FuncName, Sig));
end
else
EmitLine(Format('function %s(%s) {', FuncName, Sig));
@ -10530,10 +10571,11 @@ begin
end;
end;
if IsFunc then
begin
if RetQType = 'w' then
if AMethod.ResolvedReturnType.Kind = tyRecord then
EmitLine(' %_var_Result =l copy %_par__sret')
else if RetQType = 'w' then
begin
EmitLine(' %_var_Result =l alloc4 1');
EmitLine(' storew 0, %_var_Result');
@ -10568,12 +10610,17 @@ begin
if IsFunc then
begin
RetTemp := AllocTemp;
if RetQType = 'w' then
EmitLine(Format(' %s =w loadw %%_var_Result', RetTemp))
if AMethod.ResolvedReturnType.Kind = tyRecord then
EmitLine(' ret')
else
EmitLine(Format(' %s =l loadl %%_var_Result', RetTemp));
EmitLine(Format(' ret %s', RetTemp));
begin
RetTemp := AllocTemp;
if RetQType = 'w' then
EmitLine(Format(' %s =w loadw %%_var_Result', RetTemp))
else
EmitLine(Format(' %s =l loadl %%_var_Result', RetTemp));
EmitLine(Format(' ret %s', RetTemp));
end;
end
else
EmitLine(' ret');
@ -10893,6 +10940,224 @@ begin
end;
end;
function TCodeGenQBE.IsRecordCall(AExpr: TASTExpr): Boolean;
var
MDecl: TMethodDecl;
FldA: TFieldAccessExpr;
begin
Result := False;
if AExpr is TFuncCallExpr then
begin
if TFuncCallExpr(AExpr).ResolvedDecl = nil then Exit;
MDecl := TMethodDecl(TFuncCallExpr(AExpr).ResolvedDecl);
Result := (MDecl.ResolvedReturnType <> nil) and
(MDecl.ResolvedReturnType.Kind = tyRecord);
end
else if AExpr is TMethodCallExpr then
begin
if TMethodCallExpr(AExpr).ResolvedMethod = nil then Exit;
MDecl := TMethodDecl(TMethodCallExpr(AExpr).ResolvedMethod);
Result := (MDecl.ResolvedReturnType <> nil) and
(MDecl.ResolvedReturnType.Kind = tyRecord);
end
else if AExpr is TFieldAccessExpr then
begin
FldA := TFieldAccessExpr(AExpr);
if not FldA.IsMethodCall then Exit;
if FldA.ResolvedMethod = nil then Exit;
MDecl := TMethodDecl(FldA.ResolvedMethod);
Result := (MDecl.ResolvedReturnType <> nil) and
(MDecl.ResolvedReturnType.Kind = tyRecord);
end;
end;
procedure TCodeGenQBE.EmitRecordReleaseFields(ARec: TRecordTypeDesc;
const AAddr: string);
var
I: Integer;
F: TFieldInfo;
FldAddr: string;
ValT: string;
begin
for I := 0 to ARec.Fields.Count - 1 do
begin
F := TFieldInfo(ARec.Fields.Get(I));
if F.TypeDesc = nil then Continue;
if not (F.TypeDesc.IsString or (F.TypeDesc.Kind = tyClass)) then Continue;
if F.Offset > 0 then
begin
FldAddr := AllocTemp;
EmitLine(Format(' %s =l add %s, %d', FldAddr, AAddr, F.Offset));
end
else
FldAddr := AAddr;
ValT := AllocTemp;
EmitLine(Format(' %s =l loadl %s', ValT, FldAddr));
if F.TypeDesc.IsString then
EmitLine(Format(' call $_StringRelease(l %s)', ValT))
else
EmitLine(Format(' call $_ClassRelease(l %s)', ValT));
end;
end;
procedure TCodeGenQBE.EmitRecordCopy(ARec: TRecordTypeDesc;
const ADestAddr, ASrcAddr: string);
var
I: Integer;
F: TFieldInfo;
SrcField: string;
DstField: string;
ValTemp: string;
OldTemp: string;
begin
for I := 0 to ARec.Fields.Count - 1 do
begin
F := TFieldInfo(ARec.Fields.Get(I));
if F.TypeDesc = nil then Continue;
if F.Offset > 0 then
begin
SrcField := AllocTemp;
EmitLine(Format(' %s =l add %s, %d', SrcField, ASrcAddr, F.Offset));
DstField := AllocTemp;
EmitLine(Format(' %s =l add %s, %d', DstField, ADestAddr, F.Offset));
end
else
begin
SrcField := ASrcAddr;
DstField := ADestAddr;
end;
if F.TypeDesc.IsString then
begin
ValTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %s', ValTemp, SrcField));
OldTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %s', OldTemp, DstField));
EmitLine(Format(' call $_StringAddRef(l %s)', ValTemp));
EmitLine(Format(' call $_StringRelease(l %s)', OldTemp));
EmitLine(Format(' storel %s, %s', ValTemp, DstField));
end
else if F.TypeDesc.Kind = tyClass then
begin
ValTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %s', ValTemp, SrcField));
OldTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %s', OldTemp, DstField));
EmitLine(Format(' call $_ClassAddRef(l %s)', ValTemp));
EmitLine(Format(' call $_ClassRelease(l %s)', OldTemp));
EmitLine(Format(' storel %s, %s', ValTemp, DstField));
end
else if QbeTypeOf(F.TypeDesc) = 'w' then
begin
ValTemp := AllocTemp;
EmitLine(Format(' %s =w loadw %s', ValTemp, SrcField));
EmitLine(Format(' storew %s, %s', ValTemp, DstField));
end
else
begin
ValTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %s', ValTemp, SrcField));
EmitLine(Format(' storel %s, %s', ValTemp, DstField));
end;
end;
end;
procedure TCodeGenQBE.EmitRecordCallSret(AExpr: TASTExpr;
const ASretAddr: string);
var
FCallExpr: TFuncCallExpr;
MCallExpr: TMethodCallExpr;
FldAccess: TFieldAccessExpr;
MDecl: TMethodDecl;
ArgLine: string;
ArgTemp: string;
SelfTemp: string;
Par: TMethodParam;
I: Integer;
FuncName: string;
Ptr: string;
begin
if AExpr is TFuncCallExpr then
begin
FCallExpr := TFuncCallExpr(AExpr);
MDecl := TMethodDecl(FCallExpr.ResolvedDecl);
if FCallExpr.IsImplicitSelfMethod then
begin
SelfTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %%_var_Self', SelfTemp));
FuncName := '$' + QBEMangle(MDecl.OwnerTypeName + '_' + FCallExpr.Name);
ArgLine := Format('l %s, l %s', ASretAddr, SelfTemp);
end
else
begin
FuncName := '$' + QBEMangle(FCallExpr.Name);
ArgLine := Format('l %s', ASretAddr);
end;
for I := 0 to FCallExpr.Args.Count - 1 do
begin
Par := TMethodParam(MDecl.Params.Get(I));
if Par.IsVarParam then
ArgLine := ArgLine + Format(', l %s', EmitVarArgAddr(TIdentExpr(TASTExpr(FCallExpr.Args.Get(I)))))
else
begin
ArgTemp := EmitExpr(TASTExpr(FCallExpr.Args.Get(I)));
ArgLine := ArgLine + Format(', %s %s', QbeTypeOf(Par.ResolvedType), ArgTemp);
end;
end;
EmitLine(Format(' call %s(%s)', FuncName, ArgLine));
end
else if AExpr is TMethodCallExpr then
begin
MCallExpr := TMethodCallExpr(AExpr);
MDecl := TMethodDecl(MCallExpr.ResolvedMethod);
SelfTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %s', SelfTemp, VarRef(MCallExpr.ObjectName, MCallExpr.IsGlobal)));
FuncName := '$' + QBEMangle(MDecl.OwnerTypeName + '_' + MCallExpr.Name);
ArgLine := Format('l %s, l %s', ASretAddr, SelfTemp);
for I := 0 to MCallExpr.Args.Count - 1 do
begin
Par := TMethodParam(MDecl.Params.Get(I));
if Par.IsVarParam then
ArgLine := ArgLine + Format(', l %s', EmitVarArgAddr(TIdentExpr(TASTExpr(MCallExpr.Args.Get(I)))))
else
begin
ArgTemp := EmitExpr(TASTExpr(MCallExpr.Args.Get(I)));
ArgLine := ArgLine + Format(', %s %s', QbeTypeOf(Par.ResolvedType), ArgTemp);
end;
end;
EmitLine(Format(' call %s(%s)', FuncName, ArgLine));
end
else if AExpr is TFieldAccessExpr then
begin
FldAccess := TFieldAccessExpr(AExpr);
MDecl := TMethodDecl(FldAccess.ResolvedMethod);
if FldAccess.IsImplicitSelf then
begin
SelfTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %%_var_Self', SelfTemp));
if FldAccess.ImplicitBaseInfo.Offset > 0 then
begin
Ptr := AllocTemp;
EmitLine(Format(' %s =l add %s, %d', Ptr, SelfTemp, FldAccess.ImplicitBaseInfo.Offset));
SelfTemp := Ptr;
end;
if FldAccess.IsClassAccess then
begin
Ptr := AllocTemp;
EmitLine(Format(' %s =l loadl %s', Ptr, SelfTemp));
SelfTemp := Ptr;
end;
end
else
begin
SelfTemp := AllocTemp;
EmitLine(Format(' %s =l loadl %s', SelfTemp, VarRef(FldAccess.RecordName, FldAccess.IsGlobal)));
end;
FuncName := '$' + QBEMangle(MDecl.OwnerTypeName + '_' + FldAccess.FieldName);
ArgLine := Format('l %s, l %s', ASretAddr, SelfTemp);
EmitLine(Format(' call %s(%s)', FuncName, ArgLine));
end;
end;
procedure TCodeGenQBE.EmitFuncDef(ADecl: TMethodDecl; AExported: Boolean);
var
Sig: string;
@ -10924,7 +11189,14 @@ begin
if IsFunc then
begin
RetQType := QbeTypeOf(ADecl.ResolvedReturnType);
EmitLine(Format('%sfunction %s %s(%s) {', Prefix, RetQType, FuncName, Sig));
if ADecl.ResolvedReturnType.Kind = tyRecord then
begin
if Sig <> '' then Sig := 'l %_par__sret, ' + Sig
else Sig := 'l %_par__sret';
EmitLine(Format('%sfunction %s(%s) {', Prefix, FuncName, Sig));
end
else
EmitLine(Format('%sfunction %s %s(%s) {', Prefix, RetQType, FuncName, Sig));
end
else
EmitLine(Format('%sfunction %s(%s) {', Prefix, FuncName, Sig));
@ -10977,7 +11249,9 @@ begin
if IsFunc then
begin
if RetQType = 'w' then
if ADecl.ResolvedReturnType.Kind = tyRecord then
EmitLine(' %_var_Result =l copy %_par__sret')
else if RetQType = 'w' then
begin
EmitLine(' %_var_Result =l alloc4 1');
EmitLine(' storew 0, %_var_Result');
@ -11019,12 +11293,17 @@ begin
if IsFunc then
begin
RetTemp := AllocTemp;
if RetQType = 'w' then
EmitLine(Format(' %s =w loadw %%_var_Result', RetTemp))
if ADecl.ResolvedReturnType.Kind = tyRecord then
EmitLine(' ret')
else
EmitLine(Format(' %s =l loadl %%_var_Result', RetTemp));
EmitLine(Format(' ret %s', RetTemp));
begin
RetTemp := AllocTemp;
if RetQType = 'w' then
EmitLine(Format(' %s =w loadw %%_var_Result', RetTemp))
else
EmitLine(Format(' %s =l loadl %%_var_Result', RetTemp));
EmitLine(Format(' ret %s', RetTemp));
end;
end
else
EmitLine(' ret');
@ -11253,6 +11532,7 @@ var
ImplFld: TFieldInfo;
SelfT: string;
PtrT: string;
SretBuf: string;
begin
if AExpr is TFuncCallExpr then
begin
@ -11511,6 +11791,20 @@ begin
MDecl := TMethodDecl(TFuncCallExpr(AExpr).ResolvedDecl);
QType := QbeTypeOf(MDecl.ResolvedReturnType);
if MDecl.ResolvedReturnType.Kind = tyRecord then
begin
RT := TRecordTypeDesc(MDecl.ResolvedReturnType);
SretBuf := AllocTemp;
if RT.MaxAlign >= 8 then
EmitLine(Format(' %s =l alloc8 %d', SretBuf, RT.TotalSize))
else
EmitLine(Format(' %s =l alloc4 %d', SretBuf, RT.TotalSize));
if RT.TotalSize > 0 then
EmitLine(Format(' call $memset(l %s, w 0, l %d)', SretBuf, RT.TotalSize));
EmitRecordCallSret(AExpr, SretBuf);
Result := SretBuf;
Exit;
end;
if TFuncCallExpr(AExpr).IsImplicitSelfMethod then
begin
ArgTemp := AllocTemp;
@ -11519,9 +11813,14 @@ begin
FuncName := '$' + MDecl.OwnerTypeName + '_' + TFuncCallExpr(AExpr).Name;
for I := 0 to TFuncCallExpr(AExpr).Args.Count - 1 do
begin
Par := TMethodParam(MDecl.Params.Get(I));
ArgTemp := EmitExpr(TASTExpr(TFuncCallExpr(AExpr).Args.Get(I)));
ArgLine := ArgLine + Format(', %s %s', QbeTypeOf(Par.ResolvedType), ArgTemp);
Par := TMethodParam(MDecl.Params.Get(I));
if Par.IsVarParam then
ArgLine := ArgLine + Format(', l %s', EmitVarArgAddr(TIdentExpr(TASTExpr(TFuncCallExpr(AExpr).Args.Get(I)))))
else
begin
ArgTemp := EmitExpr(TASTExpr(TFuncCallExpr(AExpr).Args.Get(I)));
ArgLine := ArgLine + Format(', %s %s', QbeTypeOf(Par.ResolvedType), ArgTemp);
end;
end;
T := AllocTemp;
EmitLine(Format(' %s =%s call %s(%s)', T, QType, FuncName, ArgLine));
@ -11532,10 +11831,15 @@ begin
ArgLine := '';
for I := 0 to TFuncCallExpr(AExpr).Args.Count - 1 do
begin
Par := TMethodParam(MDecl.Params.Get(I));
ArgTemp := EmitExpr(TASTExpr(TFuncCallExpr(AExpr).Args.Get(I)));
Par := TMethodParam(MDecl.Params.Get(I));
if ArgLine <> '' then ArgLine := ArgLine + ', ';
ArgLine := ArgLine + Format('%s %s', QbeTypeOf(Par.ResolvedType), ArgTemp);
if Par.IsVarParam then
ArgLine := ArgLine + Format('l %s', EmitVarArgAddr(TIdentExpr(TASTExpr(TFuncCallExpr(AExpr).Args.Get(I)))))
else
begin
ArgTemp := EmitExpr(TASTExpr(TFuncCallExpr(AExpr).Args.Get(I)));
ArgLine := ArgLine + Format('%s %s', QbeTypeOf(Par.ResolvedType), ArgTemp);
end;
end;
T := AllocTemp;
EmitLine(Format(' %s =%s call %s(%s)', T, QType, FuncName, ArgLine));
@ -11617,8 +11921,20 @@ begin
else
FuncName := '$' + RT.Name + '_' + MCallExpr.Name;
QType := QbeTypeOf(MDecl.ResolvedReturnType);
if MDecl.ResolvedReturnType.Kind = tyRecord then
begin
RT := TRecordTypeDesc(MDecl.ResolvedReturnType);
SretBuf := AllocTemp;
if RT.MaxAlign >= 8 then
EmitLine(Format(' %s =l alloc8 %d', SretBuf, RT.TotalSize))
else
EmitLine(Format(' %s =l alloc4 %d', SretBuf, RT.TotalSize));
if RT.TotalSize > 0 then
EmitLine(Format(' call $memset(l %s, w 0, l %d)', SretBuf, RT.TotalSize));
EmitRecordCallSret(AExpr, SretBuf);
Result := SretBuf;
Exit;
end;
if MCallExpr.ObjExpr <> nil then
SelfTemp := EmitExpr(MCallExpr.ObjExpr)
@ -11688,13 +12004,28 @@ begin
begin
if FldAccess.IsMethodCall then
begin
L := EmitInstancePtr(FldAccess.Base);
L := EmitInstancePtr(FldAccess.Base);
MDecl := TMethodDecl(FldAccess.ResolvedMethod);
QType := QbeTypeOf(MDecl.ResolvedReturnType);
T := AllocTemp;
EmitLine(Format(' %s =%s call $%s_%s(l %s)', T, QType, MDecl.OwnerTypeName, FldAccess.FieldName, L));
Result := T;
if MDecl.ResolvedReturnType.Kind = tyRecord then
begin
RT := TRecordTypeDesc(MDecl.ResolvedReturnType);
SretBuf := AllocTemp;
if RT.MaxAlign >= 8 then
EmitLine(Format(' %s =l alloc8 %d', SretBuf, RT.TotalSize))
else
EmitLine(Format(' %s =l alloc4 %d', SretBuf, RT.TotalSize));
if RT.TotalSize > 0 then
EmitLine(Format(' call $memset(l %s, w 0, l %d)', SretBuf, RT.TotalSize));
EmitLine(Format(' call $%s_%s(l %s, l %s)', MDecl.OwnerTypeName, FldAccess.FieldName, SretBuf, L));
Result := SretBuf;
end
else
begin
QType := QbeTypeOf(MDecl.ResolvedReturnType);
T := AllocTemp;
EmitLine(Format(' %s =%s call $%s_%s(l %s)', T, QType, MDecl.OwnerTypeName, FldAccess.FieldName, L));
Result := T;
end;
Exit;
end;
L := EmitInstancePtr(FldAccess.Base);
@ -11734,12 +12065,27 @@ begin
end;
if FldAccess.IsMethodCall then
begin
MDecl := TMethodDecl(FldAccess.ResolvedMethod);
QType := QbeTypeOf(MDecl.ResolvedReturnType);
T := AllocTemp;
EmitLine(Format(' %s =%s call $%s_%s(l %s)', T, QType, MDecl.OwnerTypeName, FldAccess.FieldName, L));
Result := T;
if MDecl.ResolvedReturnType.Kind = tyRecord then
begin
RT := TRecordTypeDesc(MDecl.ResolvedReturnType);
SretBuf := AllocTemp;
if RT.MaxAlign >= 8 then
EmitLine(Format(' %s =l alloc8 %d', SretBuf, RT.TotalSize))
else
EmitLine(Format(' %s =l alloc4 %d', SretBuf, RT.TotalSize));
if RT.TotalSize > 0 then
EmitLine(Format(' call $memset(l %s, w 0, l %d)', SretBuf, RT.TotalSize));
EmitLine(Format(' call $%s_%s(l %s, l %s)', MDecl.OwnerTypeName, FldAccess.FieldName, SretBuf, L));
Result := SretBuf;
end
else
begin
QType := QbeTypeOf(MDecl.ResolvedReturnType);
T := AllocTemp;
EmitLine(Format(' %s =%s call $%s_%s(l %s)', T, QType, MDecl.OwnerTypeName, FldAccess.FieldName, L));
Result := T;
end;
Exit;
end;
if FldAccess.FieldInfo.Offset > 0 then
@ -11759,12 +12105,28 @@ begin
else if FldAccess.IsMethodCall then
begin
MDecl := TMethodDecl(FldAccess.ResolvedMethod);
L := AllocTemp;
EmitLine(Format(' %s =l loadl %s', L, VarRef(FldAccess.RecordName, FldAccess.IsGlobal)));
QType := QbeTypeOf(MDecl.ResolvedReturnType);
T := AllocTemp;
EmitLine(Format(' %s =%s call $%s_%s(l %s)', T, QType, MDecl.OwnerTypeName, FldAccess.FieldName, L));
Result := T;
if MDecl.ResolvedReturnType.Kind = tyRecord then
begin
RT := TRecordTypeDesc(MDecl.ResolvedReturnType);
SretBuf := AllocTemp;
if RT.MaxAlign >= 8 then
EmitLine(Format(' %s =l alloc8 %d', SretBuf, RT.TotalSize))
else
EmitLine(Format(' %s =l alloc4 %d', SretBuf, RT.TotalSize));
if RT.TotalSize > 0 then
EmitLine(Format(' call $memset(l %s, w 0, l %d)', SretBuf, RT.TotalSize));
EmitRecordCallSret(AExpr, SretBuf);
Result := SretBuf;
end
else
begin
L := AllocTemp;
EmitLine(Format(' %s =l loadl %s', L, VarRef(FldAccess.RecordName, FldAccess.IsGlobal)));
QType := QbeTypeOf(MDecl.ResolvedReturnType);
T := AllocTemp;
EmitLine(Format(' %s =%s call $%s_%s(l %s)', T, QType, MDecl.OwnerTypeName, FldAccess.FieldName, L));
Result := T;
end;
end
else if FldAccess.IsConstructorCall then
begin
@ -11830,10 +12192,21 @@ begin
T := AllocTemp;
if TIdentExpr(AExpr).IsImplicitSelf then
begin
ImplFld := TFieldInfo(TIdentExpr(AExpr).ImplicitFieldInfo);
SelfT := AllocTemp;
EmitLine(Format(' %s =l loadl %%_var_Self', SelfT));
if (AExpr.ResolvedType <> nil) and (AExpr.ResolvedType.Kind = tyRecord) then
begin
if ImplFld.Offset > 0 then
begin
PtrT := AllocTemp;
EmitLine(Format(' %s =l add %s, %d', PtrT, SelfT, ImplFld.Offset));
Result := PtrT;
end
else
Result := SelfT;
Exit;
end;
T := AllocTemp;
QType := QbeTypeOf(AExpr.ResolvedType);
if ImplFld.Offset > 0 then
@ -11902,9 +12275,13 @@ begin
else
EmitLine(Format(' %s =w loadw %s', T, Ptr));
end
else if (AExpr.ResolvedType <> nil) and (AExpr.ResolvedType.Kind = tyRecord) then
begin
Result := VarRef(TIdentExpr(AExpr).Name, TIdentExpr(AExpr).IsGlobal);
Exit;
end
else if TIdentExpr(AExpr).IsGlobal then
begin
if (AExpr.ResolvedType <> nil) and (QbeTypeOf(AExpr.ResolvedType) = 'w') then
EmitLine(Format(' %s =w loadw $%s', T, TIdentExpr(AExpr).Name))
else