refactor(codegen): hoist record-return ABI classifier into shared blaise.codegen
The SysV/Win64 record-return classifier — ClassifyRecordReturn plus its five leaf predicates (IsRecordManagedClean, IsRecordAllIntegerLeaves, IsRecordAllFloatLeaves, IsRecordAllIntOrFloatLeaves, EightbyteIsSSE) — existed as byte-identical twins in TCodeGenQBE and TNativeBackend (~145 lines each). This is a drift-prone ABI decision table that both backends must keep in lockstep; a divergence would silently misclassify a record return on one backend only. Move the logic to free functions in blaise.codegen (Recret* — renamed to avoid colliding with the backend methods, since Blaise resolves an unqualified call inside a method to the method, not the unit function). Only the top-level classifier consults the target OS (the Win64 aggregate rule), so it takes a TTargetDesc parameter; the leaf predicates are target-independent pure type walks. Each backend keeps its method as a one-line delegator, so every existing Self.X call site is unchanged. Validated behaviour-preserving: native .s AND QBE IR are byte-identical pre/post for a record-return program exercising every return class (rcInt1/rcInt2/rcSSE1/rcSSE2/rcIntSSE/rcSSEInt/rcSret/rcWin64-clean). All four self-host fixpoints (QBE, native, internal-assembler, warm-cache) pass; full suite OK (3853 tests) on both QBE-built and native-built test runners. Implements item F4 of Andrew's native-codegen de-duplication plan — the highest-value, lowest-risk cross-backend hoist.
This commit is contained in:
parent
6b99e4db79
commit
c8faf1ed24
|
|
@ -163,164 +163,38 @@ begin
|
|||
FAsm.AppendLine;
|
||||
end;
|
||||
|
||||
{ The record-return ABI classifier and its leaf predicates now live as shared
|
||||
free functions in blaise.codegen (byte-identical to the QBE backend's former
|
||||
twin). These methods delegate so existing Self.X call sites are unchanged. }
|
||||
function TNativeBackend.IsRecordManagedClean(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyString, tyClass, tyInterface, tyDynArray:
|
||||
Exit;
|
||||
tyRecord:
|
||||
if not Self.IsRecordManagedClean(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
Result := RecretManagedClean(ARec);
|
||||
end;
|
||||
|
||||
function TNativeBackend.IsRecordAllIntegerLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyInteger, tyInt64, tyUInt32, tyUInt64,
|
||||
tySmallInt, tyWord, tyByte, tyBoolean,
|
||||
tyEnum, tyPointer, tyProcedural, tyMetaClass:
|
||||
;
|
||||
tyRecord:
|
||||
if not Self.IsRecordAllIntegerLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
Result := RecretAllIntegerLeaves(ARec);
|
||||
end;
|
||||
|
||||
function TNativeBackend.IsRecordAllFloatLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyDouble, tySingle: ;
|
||||
tyRecord:
|
||||
if not Self.IsRecordAllFloatLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
Result := RecretAllFloatLeaves(ARec);
|
||||
end;
|
||||
|
||||
function TNativeBackend.IsRecordAllIntOrFloatLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyInteger, tyInt64, tyUInt32, tyUInt64,
|
||||
tySmallInt, tyWord, tyByte, tyBoolean,
|
||||
tyEnum, tyPointer, tyProcedural, tyMetaClass,
|
||||
tyDouble, tySingle: ;
|
||||
tyRecord:
|
||||
if not Self.IsRecordAllIntOrFloatLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
Result := RecretAllIntOrFloatLeaves(ARec);
|
||||
end;
|
||||
|
||||
function TNativeBackend.EightbyteIsSSE(ARec: TRecordTypeDesc;
|
||||
AStartByte: Integer): Boolean;
|
||||
var
|
||||
I, Off: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
Off := F.Offset;
|
||||
if (Off < AStartByte) or (Off >= AStartByte + 8) then Continue;
|
||||
case F.TypeDesc.Kind of
|
||||
tyDouble, tySingle:
|
||||
Exit(True);
|
||||
tyRecord:
|
||||
if Self.EightbyteIsSSE(TRecordTypeDesc(F.TypeDesc),
|
||||
AStartByte - Off) then Exit(True);
|
||||
end;
|
||||
end;
|
||||
Result := RecretEightbyteIsSSE(ARec, AStartByte);
|
||||
end;
|
||||
|
||||
function TNativeBackend.ClassifyRecordReturn(ARec: TRecordTypeDesc): TRecReturnClass;
|
||||
var
|
||||
Sz: Integer;
|
||||
Eb0SSE, Eb1SSE: Boolean;
|
||||
begin
|
||||
Result := rcSret;
|
||||
if (ARec = nil) or (ARec.Kind <> tyRecord) then Exit;
|
||||
if ARec.Fields.Count = 0 then Exit;
|
||||
if not Self.IsRecordManagedClean(ARec) then Exit;
|
||||
Sz := ARec.TotalSize();
|
||||
|
||||
if FTarget.OS = osWindows then
|
||||
begin
|
||||
if Self.IsRecordAllIntOrFloatLeaves(ARec) then
|
||||
Result := rcWin64Agg;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if Self.IsRecordAllIntegerLeaves(ARec) then
|
||||
begin
|
||||
case Sz of
|
||||
1, 2, 4, 8: Result := rcInt1;
|
||||
9, 10, 11, 12, 13, 14, 15, 16: Result := rcInt2;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if Self.IsRecordAllFloatLeaves(ARec) then
|
||||
begin
|
||||
case Sz of
|
||||
4, 8: Result := rcSSE1;
|
||||
9, 10, 11, 12, 13, 14, 15, 16: Result := rcSSE2;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if not Self.IsRecordAllIntOrFloatLeaves(ARec) then Exit;
|
||||
case Sz of
|
||||
9, 10, 11, 12, 13, 14, 15, 16:
|
||||
begin
|
||||
Eb0SSE := Self.EightbyteIsSSE(ARec, 0);
|
||||
Eb1SSE := Self.EightbyteIsSSE(ARec, 8);
|
||||
if (not Eb0SSE) and Eb1SSE then Result := rcIntSSE
|
||||
else if Eb0SSE and (not Eb1SSE) then Result := rcSSEInt;
|
||||
end;
|
||||
end;
|
||||
Result := RecretClassify(ARec, FTarget);
|
||||
end;
|
||||
|
||||
function TNativeBackend.GenerateProgram(AProg: TProgram): string;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ unit blaise.codegen;
|
|||
interface
|
||||
|
||||
uses
|
||||
uAST, uSymbolTable, uDebugFacts;
|
||||
uAST, uSymbolTable, uDebugFacts, blaise.codegen.target;
|
||||
|
||||
type
|
||||
TRecReturnClass = (
|
||||
|
|
@ -91,6 +91,196 @@ type
|
|||
function GetOutput: string;
|
||||
end;
|
||||
|
||||
{ ----------------------------------------------------------------------
|
||||
Shared System V / Win64 record-return ABI classifier.
|
||||
|
||||
Both the QBE backend and the native x86-64 backend must agree, byte for
|
||||
byte, on how a record-typed return value is passed (sret vs register, and
|
||||
which register class). The decision is a pure walk over the record's field
|
||||
layout plus the target OS — no backend state — so it lives here as free
|
||||
functions that both backends call, instead of being carried as two
|
||||
drift-prone twins. Only RecretClassify consults the target (the Win64
|
||||
aggregate rule); the leaf predicates are target-independent type walks. }
|
||||
|
||||
{ True when ARec (and every nested record) contains no managed fields
|
||||
(string / class / interface / dynamic array) — a precondition for any
|
||||
register return. }
|
||||
function RecretManagedClean(ARec: TRecordTypeDesc): Boolean;
|
||||
{ True when every leaf field is an integer-class scalar (or a nested record
|
||||
thereof). }
|
||||
function RecretAllIntegerLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
{ True when every leaf field is a float (Double/Single) or a nested record
|
||||
thereof. }
|
||||
function RecretAllFloatLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
{ True when every leaf field is an integer- or float-class scalar. }
|
||||
function RecretAllIntOrFloatLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
{ True when the eightbyte starting at AStartByte holds any float leaf — i.e.
|
||||
the eightbyte is SSE-classified under the SysV mixed-class rules. }
|
||||
function RecretEightbyteIsSSE(ARec: TRecordTypeDesc; AStartByte: Integer): Boolean;
|
||||
{ Classify ARec's return-passing for ATarget's OS. }
|
||||
function RecretClassify(ARec: TRecordTypeDesc;
|
||||
const ATarget: TTargetDesc): TRecReturnClass;
|
||||
|
||||
implementation
|
||||
|
||||
function RecretManagedClean(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyString, tyClass, tyInterface, tyDynArray:
|
||||
Exit;
|
||||
tyRecord:
|
||||
if not RecretManagedClean(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function RecretAllIntegerLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyInteger, tyInt64, tyUInt32, tyUInt64,
|
||||
tySmallInt, tyWord, tyByte, tyBoolean,
|
||||
tyEnum, tyPointer, tyProcedural, tyMetaClass:
|
||||
;
|
||||
tyRecord:
|
||||
if not RecretAllIntegerLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function RecretAllFloatLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyDouble, tySingle: ;
|
||||
tyRecord:
|
||||
if not RecretAllFloatLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function RecretAllIntOrFloatLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyInteger, tyInt64, tyUInt32, tyUInt64,
|
||||
tySmallInt, tyWord, tyByte, tyBoolean,
|
||||
tyEnum, tyPointer, tyProcedural, tyMetaClass,
|
||||
tyDouble, tySingle: ;
|
||||
tyRecord:
|
||||
if not RecretAllIntOrFloatLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function RecretEightbyteIsSSE(ARec: TRecordTypeDesc; AStartByte: Integer): Boolean;
|
||||
var
|
||||
I, Off: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
Off := F.Offset;
|
||||
if (Off < AStartByte) or (Off >= AStartByte + 8) then Continue;
|
||||
case F.TypeDesc.Kind of
|
||||
tyDouble, tySingle:
|
||||
Exit(True);
|
||||
tyRecord:
|
||||
if RecretEightbyteIsSSE(TRecordTypeDesc(F.TypeDesc),
|
||||
AStartByte - Off) then Exit(True);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function RecretClassify(ARec: TRecordTypeDesc;
|
||||
const ATarget: TTargetDesc): TRecReturnClass;
|
||||
var
|
||||
Sz: Integer;
|
||||
Eb0SSE, Eb1SSE: Boolean;
|
||||
begin
|
||||
Result := rcSret;
|
||||
if (ARec = nil) or (ARec.Kind <> tyRecord) then Exit;
|
||||
if ARec.Fields.Count = 0 then Exit;
|
||||
if not RecretManagedClean(ARec) then Exit;
|
||||
Sz := ARec.TotalSize();
|
||||
|
||||
if ATarget.OS = osWindows then
|
||||
begin
|
||||
if RecretAllIntOrFloatLeaves(ARec) then
|
||||
Result := rcWin64Agg;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if RecretAllIntegerLeaves(ARec) then
|
||||
begin
|
||||
case Sz of
|
||||
1, 2, 4, 8: Result := rcInt1;
|
||||
9, 10, 11, 12, 13, 14, 15, 16: Result := rcInt2;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if RecretAllFloatLeaves(ARec) then
|
||||
begin
|
||||
case Sz of
|
||||
4, 8: Result := rcSSE1;
|
||||
9, 10, 11, 12, 13, 14, 15, 16: Result := rcSSE2;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if not RecretAllIntOrFloatLeaves(ARec) then Exit;
|
||||
case Sz of
|
||||
9, 10, 11, 12, 13, 14, 15, 16:
|
||||
begin
|
||||
Eb0SSE := RecretEightbyteIsSSE(ARec, 0);
|
||||
Eb1SSE := RecretEightbyteIsSSE(ARec, 8);
|
||||
if (not Eb0SSE) and Eb1SSE then Result := rcIntSSE
|
||||
else if Eb0SSE and (not Eb1SSE) then Result := rcSSEInt;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
|
|||
|
|
@ -5275,164 +5275,39 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
{ The record-return ABI classifier and its leaf predicates now live as shared
|
||||
free functions in blaise.codegen (byte-identical to the native backend's
|
||||
former twin). These methods delegate so existing Self.X call sites are
|
||||
unchanged. }
|
||||
function TCodeGenQBE.IsRecordManagedClean(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyString, tyClass, tyInterface, tyDynArray:
|
||||
Exit;
|
||||
tyRecord:
|
||||
if not Self.IsRecordManagedClean(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
Result := RecretManagedClean(ARec);
|
||||
end;
|
||||
|
||||
function TCodeGenQBE.IsRecordAllIntegerLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyInteger, tyInt64, tyUInt32, tyUInt64,
|
||||
tySmallInt, tyWord, tyByte, tyBoolean,
|
||||
tyEnum, tyPointer, tyProcedural, tyMetaClass:
|
||||
;
|
||||
tyRecord:
|
||||
if not Self.IsRecordAllIntegerLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
Result := RecretAllIntegerLeaves(ARec);
|
||||
end;
|
||||
|
||||
function TCodeGenQBE.IsRecordAllFloatLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyDouble, tySingle: ;
|
||||
tyRecord:
|
||||
if not Self.IsRecordAllFloatLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
Result := RecretAllFloatLeaves(ARec);
|
||||
end;
|
||||
|
||||
function TCodeGenQBE.IsRecordAllIntOrFloatLeaves(ARec: TRecordTypeDesc): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
case F.TypeDesc.Kind of
|
||||
tyInteger, tyInt64, tyUInt32, tyUInt64,
|
||||
tySmallInt, tyWord, tyByte, tyBoolean,
|
||||
tyEnum, tyPointer, tyProcedural, tyMetaClass,
|
||||
tyDouble, tySingle: ;
|
||||
tyRecord:
|
||||
if not Self.IsRecordAllIntOrFloatLeaves(TRecordTypeDesc(F.TypeDesc)) then Exit;
|
||||
else
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := True;
|
||||
Result := RecretAllIntOrFloatLeaves(ARec);
|
||||
end;
|
||||
|
||||
function TCodeGenQBE.EightbyteIsSSE(ARec: TRecordTypeDesc;
|
||||
AStartByte: Integer): Boolean;
|
||||
var
|
||||
I, Off: Integer;
|
||||
F: TFieldInfo;
|
||||
begin
|
||||
Result := False;
|
||||
if ARec = nil then Exit;
|
||||
for I := 0 to ARec.Fields.Count - 1 do
|
||||
begin
|
||||
F := TFieldInfo(ARec.Fields.Items[I]);
|
||||
Off := F.Offset;
|
||||
if (Off < AStartByte) or (Off >= AStartByte + 8) then Continue;
|
||||
case F.TypeDesc.Kind of
|
||||
tyDouble, tySingle:
|
||||
Exit(True);
|
||||
tyRecord:
|
||||
if Self.EightbyteIsSSE(TRecordTypeDesc(F.TypeDesc),
|
||||
AStartByte - Off) then Exit(True);
|
||||
end;
|
||||
end;
|
||||
Result := RecretEightbyteIsSSE(ARec, AStartByte);
|
||||
end;
|
||||
|
||||
function TCodeGenQBE.ClassifyRecordReturn(ARec: TRecordTypeDesc): TRecReturnClass;
|
||||
var
|
||||
Sz: Integer;
|
||||
Eb0SSE, Eb1SSE: Boolean;
|
||||
begin
|
||||
Result := rcSret;
|
||||
if (ARec = nil) or (ARec.Kind <> tyRecord) then Exit;
|
||||
if ARec.Fields.Count = 0 then Exit;
|
||||
if not Self.IsRecordManagedClean(ARec) then Exit;
|
||||
Sz := ARec.TotalSize();
|
||||
|
||||
if GTarget.OS = osWindows then
|
||||
begin
|
||||
if Self.IsRecordAllIntOrFloatLeaves(ARec) then
|
||||
Result := rcWin64Agg;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if Self.IsRecordAllIntegerLeaves(ARec) then
|
||||
begin
|
||||
case Sz of
|
||||
1, 2, 4, 8: Result := rcInt1;
|
||||
9, 10, 11, 12, 13, 14, 15, 16: Result := rcInt2;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if Self.IsRecordAllFloatLeaves(ARec) then
|
||||
begin
|
||||
case Sz of
|
||||
4, 8: Result := rcSSE1;
|
||||
9, 10, 11, 12, 13, 14, 15, 16: Result := rcSSE2;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if not Self.IsRecordAllIntOrFloatLeaves(ARec) then Exit;
|
||||
case Sz of
|
||||
9, 10, 11, 12, 13, 14, 15, 16:
|
||||
begin
|
||||
Eb0SSE := Self.EightbyteIsSSE(ARec, 0);
|
||||
Eb1SSE := Self.EightbyteIsSSE(ARec, 8);
|
||||
if (not Eb0SSE) and Eb1SSE then Result := rcIntSSE
|
||||
else if Eb0SSE and (not Eb1SSE) then Result := rcSSEInt;
|
||||
end;
|
||||
end;
|
||||
Result := RecretClassify(ARec, GTarget);
|
||||
end;
|
||||
|
||||
procedure TCodeGenQBE.EmitRecordReturnSignature(var ASig: string;
|
||||
|
|
|
|||
Loading…
Reference in a new issue