Resolved cyclic dependencies between environment and compiler stages
This commit is contained in:
@@ -5,27 +5,55 @@ interface
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Generics.Collections,
|
||||
System.Generics.Defaults,
|
||||
Myc.Data.Value,
|
||||
Myc.Ast,
|
||||
Myc.Ast.Types,
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Visitor,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.Environment,
|
||||
Myc.Ast.RTL;
|
||||
Myc.Ast.RTL,
|
||||
Myc.Ast.Compiler.Binder;
|
||||
|
||||
type
|
||||
IAstSpecializer = interface(IAstVisitor)
|
||||
function Execute(const RootNode: IAstNode): IAstNode;
|
||||
end;
|
||||
|
||||
// --- Monomorphization Cache Definitions ---
|
||||
|
||||
TMonoCacheKey = record
|
||||
public
|
||||
Address: TResolvedAddress;
|
||||
ArgTypes: TArray<IStaticType>;
|
||||
Func: TDataValue.TFunc;
|
||||
constructor Create(const AAddress: TResolvedAddress; const AArgTypes: TArray<IStaticType>);
|
||||
end;
|
||||
|
||||
IMonomorphCache = interface
|
||||
function TryGetFunction(const Key: TMonoCacheKey; out Func: TSpecializedMethod): Boolean;
|
||||
procedure Add(const Key: TMonoCacheKey; const Func: TSpecializedMethod);
|
||||
end;
|
||||
|
||||
TCompiledFunction = record
|
||||
public
|
||||
Func: TDataValue.TFunc;
|
||||
StaticType: IStaticType;
|
||||
IsPure: Boolean;
|
||||
constructor Create(const AFunc: TDataValue.TFunc; const AStaticType: IStaticType; AIsPure: Boolean);
|
||||
end;
|
||||
|
||||
// This transformer runs *after* TypeChecker.
|
||||
// It specializes all statically resolvable function calls (RTL and user-defined)
|
||||
// by replacing them with nodes that have a direct StaticTarget.
|
||||
// It propagates Purity information but does NOT perform Constant Folding yet.
|
||||
TStaticSpecializer = class(TAstTransformer, IAstSpecializer)
|
||||
type
|
||||
TCompileFunc = reference to function(const Node: IFunctionDefinition; const ArgTypes: TArray<IStaticType>): TCompiledFunction;
|
||||
private
|
||||
FEnvironment: IEnvironment;
|
||||
FMonomorphCache: IMonomorphCache;
|
||||
FFunctionRegistry: IFunctionDefinitionRegistry;
|
||||
FCompileFunc: TCompileFunc;
|
||||
|
||||
function GetStaticRtlFunction(const AName: string; const AArgTypes: TArray<IStaticType>): TSpecializedMethod;
|
||||
|
||||
@@ -33,26 +61,48 @@ type
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override;
|
||||
|
||||
public
|
||||
constructor Create(const AEnvironment: IEnvironment);
|
||||
constructor Create(
|
||||
const AMonomorphCache: IMonomorphCache;
|
||||
const AFunctionRegistry: IFunctionDefinitionRegistry;
|
||||
const ACompileFunc: TCompileFunc
|
||||
);
|
||||
function Execute(const RootNode: IAstNode): IAstNode;
|
||||
|
||||
class function Specialize(const AEnvironment: IEnvironment; const RootNode: IAstNode): IAstNode; static;
|
||||
class function Specialize(
|
||||
const RootNode: IAstNode;
|
||||
const AMonomorphCache: IMonomorphCache;
|
||||
const AFunctionRegistry: IFunctionDefinitionRegistry;
|
||||
const ACompileFunc: TCompileFunc
|
||||
): IAstNode; static;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Hash;
|
||||
|
||||
{ TStaticSpecializer }
|
||||
|
||||
constructor TStaticSpecializer.Create(const AEnvironment: IEnvironment);
|
||||
constructor TStaticSpecializer.Create(
|
||||
const AMonomorphCache: IMonomorphCache;
|
||||
const AFunctionRegistry: IFunctionDefinitionRegistry;
|
||||
const ACompileFunc: TCompileFunc
|
||||
);
|
||||
begin
|
||||
inherited Create;
|
||||
Assert(Assigned(AEnvironment));
|
||||
FEnvironment := AEnvironment;
|
||||
FMonomorphCache := AMonomorphCache;
|
||||
FFunctionRegistry := AFunctionRegistry;
|
||||
FCompileFunc := ACompileFunc;
|
||||
end;
|
||||
|
||||
class function TStaticSpecializer.Specialize(const AEnvironment: IEnvironment; const RootNode: IAstNode): IAstNode;
|
||||
class function TStaticSpecializer.Specialize(
|
||||
const RootNode: IAstNode;
|
||||
const AMonomorphCache: IMonomorphCache;
|
||||
const AFunctionRegistry: IFunctionDefinitionRegistry;
|
||||
const ACompileFunc: TCompileFunc
|
||||
): IAstNode;
|
||||
begin
|
||||
var specializer := TStaticSpecializer.Create(AEnvironment) as IAstSpecializer;
|
||||
var specializer := TStaticSpecializer.Create(AMonomorphCache, AFunctionRegistry, ACompileFunc) as IAstSpecializer;
|
||||
Result := specializer.Execute(RootNode);
|
||||
end;
|
||||
|
||||
@@ -125,7 +175,7 @@ begin
|
||||
// 4. Check the Environment (Instance) Cache
|
||||
key := TMonoCacheKey.Create(calleeIdent.Address, argTypes);
|
||||
|
||||
if FEnvironment.MonomorphCache.TryGetValue(key, specializedMethod) then
|
||||
if FMonomorphCache.TryGetFunction(key, specializedMethod) then
|
||||
begin
|
||||
// 4a. Cache Hit (Environment)
|
||||
// Propagate IsPure flag from cache to AST node
|
||||
@@ -146,7 +196,7 @@ begin
|
||||
if Assigned(specializedMethod.Target) then
|
||||
begin
|
||||
// 5a. Cache Hit (RTL)
|
||||
FEnvironment.MonomorphCache.Add(key, specializedMethod);
|
||||
FMonomorphCache.Add(key, specializedMethod);
|
||||
|
||||
// Propagate IsPure flag from RTL definition to AST node
|
||||
Result :=
|
||||
@@ -162,7 +212,7 @@ begin
|
||||
end;
|
||||
|
||||
// 6. Cache Miss (User Code)
|
||||
funcDef := FEnvironment.FunctionRegistry.Resolve(calleeIdent.Address);
|
||||
funcDef := FFunctionRegistry.Resolve(calleeIdent.Address);
|
||||
|
||||
if (funcDef <> nil) then
|
||||
begin
|
||||
@@ -179,13 +229,13 @@ begin
|
||||
|
||||
// 6a. Compile func with KNOWN TYPES
|
||||
// This recursively triggers Bind -> Check -> Specialize -> Purity Inference for the callee body!
|
||||
var compiled := FEnvironment.Compile(funcDef, argTypes);
|
||||
var compiled := FCompileFunc(funcDef, argTypes);
|
||||
|
||||
// 6b. Store in cache
|
||||
// Get the return type from the *full function type* returned by Compile
|
||||
var returnType := compiled.StaticType.Signatures[0].ReturnType;
|
||||
specializedMethod := TSpecializedMethod.Create(compiled.Func, returnType, compiled.IsPure);
|
||||
FEnvironment.MonomorphCache.Add(key, specializedMethod);
|
||||
FMonomorphCache.Add(key, specializedMethod);
|
||||
|
||||
// 6c. Return the new node
|
||||
// Propagate the inferred IsPure flag to the AST node
|
||||
@@ -200,4 +250,21 @@ begin
|
||||
Result := TAst.FunctionCall(newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil);
|
||||
end;
|
||||
|
||||
{ TMonoCacheKey }
|
||||
|
||||
constructor TMonoCacheKey.Create(const AAddress: TResolvedAddress; const AArgTypes: TArray<IStaticType>);
|
||||
begin
|
||||
Address := AAddress;
|
||||
ArgTypes := AArgTypes;
|
||||
end;
|
||||
|
||||
{ TCompiledFunction }
|
||||
|
||||
constructor TCompiledFunction.Create(const AFunc: TDataValue.TFunc; const AStaticType: IStaticType; AIsPure: Boolean);
|
||||
begin
|
||||
Func := AFunc;
|
||||
StaticType := AStaticType;
|
||||
IsPure := AIsPure;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user