refactor(codegen): hoist symbol mangler to blaise.codegen (F5)
QBEMangle (TCodeGenQBE method) and NativeMangle (native free function) applied the same metacharacter mapping: '<' ',' ' ' -> '_', drop '>', and '$' '@' '^' -> '_D_' '_V_' '_P_'. Two copies of the symbol-naming rule is a link-time-breakage risk if one side gains a case the other lacks. Hoist a single CodegenMangle into blaise.codegen (distinct name, per the F4 method-binding gotcha); both backends delegate. The shared version keeps QBEMangle's clean-name fast-path (no per-character concat when no metacharacter is present) and reads bytes via StrAt — so NativeMangle now also uses the stage-stable StrAt instead of the Ord(S[i]) idiom the house rules warn against. Cross-backend dedup, no behaviour change: native .s AND QBE IR both byte-identical on a generics + overload program (TList<Integer>, TList<string>, Show$i/Show$S → TList_Integer_*, Show_D_i/Show_D_S). All four fixpoints — which mangle the entire compiler's generic/overload symbol set — and the full suite on both test runners are unchanged.
This commit is contained in:
parent
1e0b7fc46a
commit
1c250fb13e
|
|
@ -1670,25 +1670,10 @@ end;
|
|||
{ Mangle a name for use as an assembly label: replace characters that are
|
||||
invalid in label names with underscores, matching QBE backend's QBEMangle. }
|
||||
function NativeMangle(const AName: string): string;
|
||||
var
|
||||
I, C: Integer;
|
||||
begin
|
||||
Result := '';
|
||||
for I := 0 to Length(AName) - 1 do
|
||||
begin
|
||||
C := Ord(AName[I]);
|
||||
case C of
|
||||
60: Result := Result + '_'; { '<' }
|
||||
62: ; { '>' — skip }
|
||||
44: Result := Result + '_'; { ',' }
|
||||
32: Result := Result + '_'; { ' ' — e.g. 'class of T' }
|
||||
36: Result := Result + '_D_'; { '$' }
|
||||
64: Result := Result + '_V_'; { '@' }
|
||||
94: Result := Result + '_P_'; { '^' }
|
||||
else
|
||||
Result := Result + Chr(C);
|
||||
end;
|
||||
end;
|
||||
{ Delegates to the shared backend-neutral mangler in blaise.codegen
|
||||
(formerly a per-character twin of the QBE backend's QBEMangle). }
|
||||
Result := CodegenMangle(AName);
|
||||
end;
|
||||
|
||||
function TX86_64Backend.ClassSymName(const AClassName: string): string;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ unit blaise.codegen;
|
|||
interface
|
||||
|
||||
uses
|
||||
uAST, uSymbolTable, uDebugFacts, blaise.codegen.target;
|
||||
uAST, uSymbolTable, uDebugFacts, blaise.codegen.target, uStrCompat;
|
||||
|
||||
type
|
||||
TRecReturnClass = (
|
||||
|
|
@ -133,6 +133,13 @@ function RecretClassify(ARec: TRecordTypeDesc;
|
|||
twins ExprOwnsRef / NativeExprOwnsRef). }
|
||||
function ArcExprOwnsRef(AExpr: TASTExpr): Boolean;
|
||||
|
||||
{ Mangle a Blaise symbol name into an assembler-legal identifier, shared by
|
||||
both backends (formerly QBEMangle / NativeMangle). Replaces the generic/
|
||||
overload metacharacters '<' ',' ' ' -> '_', drops '>', and maps the type-code
|
||||
sigils '$' '@' '^' to '_D_' '_V_' '_P_'. A clean name (no metacharacter) is
|
||||
returned unchanged via a fast pre-scan that avoids per-character concat. }
|
||||
function CodegenMangle(const AName: string): string;
|
||||
|
||||
implementation
|
||||
|
||||
function RecretManagedClean(ARec: TRecordTypeDesc): Boolean;
|
||||
|
|
@ -357,4 +364,43 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function CodegenMangle(const AName: string): string;
|
||||
var
|
||||
I, C: Integer;
|
||||
Clean: Boolean;
|
||||
begin
|
||||
{ Fast path: the overwhelming majority of names contain none of the mangled
|
||||
characters — return the input unchanged instead of rebuilding it with one
|
||||
concat (and its ARC churn) per character. }
|
||||
Clean := True;
|
||||
for I := 0 to Length(AName) - 1 do
|
||||
begin
|
||||
C := StrAt(AName, I);
|
||||
if (C = 60) or (C = 62) or (C = 44) or (C = 36) or (C = 64) or
|
||||
(C = 94) or (C = 32) then
|
||||
begin
|
||||
Clean := False;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if Clean then
|
||||
Exit(AName);
|
||||
Result := '';
|
||||
for I := 0 to Length(AName) - 1 do
|
||||
begin
|
||||
C := StrAt(AName, I);
|
||||
case C of
|
||||
60: Result := Result + '_'; { '<' }
|
||||
62: ; { '>' — skip }
|
||||
44: Result := Result + '_'; { ',' }
|
||||
32: Result := Result + '_'; { ' ' — e.g. 'class of T' }
|
||||
36: Result := Result + '_D_'; { '$' — overload delimiter }
|
||||
64: Result := Result + '_V_'; { '@' — var-param prefix }
|
||||
94: Result := Result + '_P_'; { '^' — pointer prefix }
|
||||
else
|
||||
Result := Result + Chr(C);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
|
|||
|
|
@ -13382,43 +13382,10 @@ begin
|
|||
end;
|
||||
|
||||
function TCodeGenQBE.QBEMangle(const AName: string): string;
|
||||
var
|
||||
I: Integer;
|
||||
C: Integer;
|
||||
Clean: Boolean;
|
||||
begin
|
||||
{ Fast path: the overwhelming majority of names contain none of the
|
||||
mangled characters — return the input unchanged instead of rebuilding
|
||||
it with one concat (and its ARC churn) per character. }
|
||||
Clean := True;
|
||||
for I := 0 to Length(AName) - 1 do
|
||||
begin
|
||||
C := StrAt(AName, I);
|
||||
if (C = 60) or (C = 62) or (C = 44) or (C = 36) or (C = 64) or
|
||||
(C = 94) or (C = 32) then
|
||||
begin
|
||||
Clean := False;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if Clean then
|
||||
Exit(AName);
|
||||
Result := '';
|
||||
for I := 0 to Length(AName) - 1 do
|
||||
begin
|
||||
C := StrAt(AName, I);
|
||||
case C of
|
||||
60: Result := Result + '_'; { '<' }
|
||||
62: ; { '>' — skip }
|
||||
44: Result := Result + '_'; { ',' }
|
||||
32: Result := Result + '_'; { ' ' — e.g. 'class of T' }
|
||||
36: Result := Result + '_D_'; { '$' — overload delimiter }
|
||||
64: Result := Result + '_V_'; { '@' — var-param prefix }
|
||||
94: Result := Result + '_P_'; { '^' — pointer prefix }
|
||||
else
|
||||
Result := Result + Chr(C);
|
||||
end;
|
||||
end;
|
||||
{ Delegates to the shared backend-neutral mangler in blaise.codegen
|
||||
(formerly a per-character twin of the native backend's NativeMangle). }
|
||||
Result := CodegenMangle(AName);
|
||||
end;
|
||||
|
||||
function TCodeGenQBE.MethodEmitName(AMDecl: TMethodDecl;
|
||||
|
|
|
|||
Loading…
Reference in a new issue