Skip to content

Commit 730a009

Browse files
committed
[Heavy] Improve rename envs
1 parent 957187e commit 730a009

File tree

13 files changed

+117
-87
lines changed

13 files changed

+117
-87
lines changed

heavy/include/heavy/Context.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ class Context : public ContinuationStack<Context>,
186186
EnvStack = E;
187187
}
188188

189+
EnvFrame* GetLocalEnvFrame(Value Stack, bool IsLambdaScope = false);
189190
Value& GetLocalEnvStack(Value Stack = nullptr);
190191
// Provide a hashable value for checking for duplicate identifiers.
191192
std::pair<uintptr_t, uintptr_t> GetIdentifierUniqueId(Value V);
@@ -232,7 +233,8 @@ class Context : public ContinuationStack<Context>,
232233

233234
// PushEnvFrame - Creates and pushes an EnvFrame to the
234235
// current environment (EnvStack)
235-
EnvFrame* PushEnvFrame(llvm::ArrayRef<Value> Names = {});
236+
EnvFrame* PushEnvFrame(llvm::ArrayRef<Value> Names = {},
237+
bool IsLambdaScope = false);
236238
void PopEnvFrame(EnvFrame*);
237239
void PushLocalBinding(Binding* B);
238240
void PushEnv(Value V, Value Env);
@@ -355,8 +357,8 @@ class Context : public ContinuationStack<Context>,
355357
Vector* CreateVector(ArrayRef<Value> Xs);
356358
Vector* CreateVector(unsigned N, Value Default = Undefined());
357359
ByteVector* CreateByteVector(llvm::ArrayRef<Value> Xs);
358-
EnvFrame* CreateEnvFrame(llvm::ArrayRef<Value> Names);
359-
EnvFrame* CreateEnvFrame(unsigned N);
360+
EnvFrame* CreateEnvFrame(llvm::ArrayRef<Value> Names, bool IsLambdaScope);
361+
EnvFrame* CreateEnvFrame(unsigned N, bool IsLambdaScope = false);
360362

361363
template <typename T>
362364
Any* CreateAny(T Obj) {

heavy/include/heavy/OpGen.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ class OpGen : public ValueVisitor<OpGen, mlir::Value> {
159159

160160
void InsertTopLevelCommandOp(SourceLocation Loc);
161161
bool WalkDefineInits(Value Env, IdSet& LocalNames);
162-
bool FinishLocalDefines();
162+
void FinishLocalDefines();
163163

164164
public:
165165
explicit OpGen(heavy::Context& C, heavy::Symbol* ModulePrefix = nullptr);

heavy/include/heavy/Ops.td

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,25 @@ def heavy_RenameGlobalOp : HeavyOp<"rename_global"> {
535535
];
536536
}
537537

538+
def heavy_RenameEnvOp : HeavyOp<"rename_env"> {
539+
let description = [{
540+
RenameEnvOp creates a new EnvFrame with $bindings
541+
which serves as the tail of a new environment stack
542+
with the most local EnvFrame from $env on top.
543+
544+
The local EnvFrame holds the local stack so any syntax closure
545+
created will be topped with any newly added local variables
546+
or EnvFrames automatically.
547+
}];
548+
549+
let arguments = (ins HeavyValue:$env, Variadic<HeavyValue>:$bindings);
550+
let results = (outs HeavyValue: $result);
551+
let builders = [
552+
OpBuilder<(ins "::mlir::Value":$env,
553+
"::llvm::ArrayRef<::mlir::Value>":$args)>
554+
];
555+
}
556+
538557
def heavy_SourceLocOp : HeavyOp<"source-loc"> {
539558
let summary = "source-loc";
540559
let description = [{
@@ -640,22 +659,6 @@ def heavy_VectorOp : HeavyOp<"vector"> {
640659
];
641660
}
642661

643-
def heavy_EnvFrameOp : HeavyOp<"env_frame"> {
644-
let description = [{
645-
EnvFrameOp creates a vector-like object of bindings.
646-
647-
Since it serves to define lexical scopes in the
648-
environment, it exists apart from VectorOp so that
649-
the bindings do not get unwrapped during evaluation.
650-
}];
651-
652-
let arguments = (ins Variadic<HeavyValue>:$args);
653-
let results = (outs HeavyValue: $result);
654-
let builders = [
655-
OpBuilder<(ins "::llvm::ArrayRef<::mlir::Value>":$args)>
656-
];
657-
}
658-
659662
def heavy_UndefinedOp : HeavyOp<"undefined", [Pure]> {
660663
let summary = "undefined";
661664
let description = [{

heavy/include/heavy/Value.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,7 @@ class EnvFrame final
15251525
friend class Context;
15261526
friend class CopyCollector;
15271527

1528+
bool IsLambdaScope;
15281529
unsigned NumBindings;
15291530
size_t numTrailingObjects(OverloadToken<Binding*> const) const {
15301531
return NumBindings;
@@ -1535,12 +1536,15 @@ class EnvFrame final
15351536

15361537
public:
15371538

1538-
EnvFrame(unsigned NumBindings)
1539+
EnvFrame(unsigned NumBindings, bool IsLambdaScope)
15391540
: ValueBase(ValueKind::EnvFrame),
1541+
IsLambdaScope(IsLambdaScope),
15401542
NumBindings(NumBindings),
15411543
LocalStack(Empty())
15421544
{ }
15431545

1546+
bool isLambdaScope() const { return IsLambdaScope; }
1547+
15441548
llvm::ArrayRef<Binding*> getBindings() const {
15451549
return llvm::ArrayRef<Binding*>(
15461550
getTrailingObjects<Binding*>(), NumBindings);

heavy/lib/Context.cpp

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ EnvFrame* Context::PushLambdaFormals(Value Formals,
161161
}
162162
}
163163

164-
return PushEnvFrame(Ids);
164+
return PushEnvFrame(Ids, /*IsLambdaScope=*/true);
165165
}
166166

167167
std::pair<uintptr_t, uintptr_t> Context::GetIdentifierUniqueId(Value V) {
@@ -175,40 +175,38 @@ std::pair<uintptr_t, uintptr_t> Context::GetIdentifierUniqueId(Value V) {
175175
Env.getOpaqueValue()};
176176
}
177177

178+
// Get the localiest EnvFrame.
179+
EnvFrame* Context::GetLocalEnvFrame(Value Stack, bool IsLambdaScope) {
180+
EnvFrame* MostLocalEF = nullptr;
181+
for (Value EnvNode : Stack) {
182+
if (auto* EF = dyn_cast<EnvFrame>(EnvNode)) {
183+
if (auto* NestedEF = GetLocalEnvFrame(EF->getLocalStack(),
184+
IsLambdaScope))
185+
return NestedEF;
186+
if (!IsLambdaScope || EF->isLambdaScope())
187+
MostLocalEF = EF;
188+
}
189+
}
190+
return MostLocalEF;
191+
}
192+
178193
// Get the localiest EnvFrame->LocalStack or this->EnvStack.
179194
Value& Context::GetLocalEnvStack(Value Stack) {
180195
if (!Stack)
181196
Stack = this->EnvStack;
182-
EnvFrame* CurEF = nullptr;
183-
if (auto* EnvPair = dyn_cast<Pair>(Stack)) {
184-
if (auto* EF = dyn_cast<EnvFrame>(EnvPair->Car)) {
185-
Stack = EF->LocalStack;
186-
CurEF = EF;
187-
}
188-
}
189-
return CurEF ? CurEF->LocalStack : this->EnvStack;
197+
EnvFrame* MostLocalEF = GetLocalEnvFrame(Stack);
198+
return MostLocalEF ? MostLocalEF->LocalStack : this->EnvStack;
190199
}
191200

192-
EnvFrame* Context::PushEnvFrame(llvm::ArrayRef<Value> Ids) {
193-
EnvFrame* E = CreateEnvFrame(Ids);
201+
EnvFrame* Context::PushEnvFrame(llvm::ArrayRef<Value> Ids,
202+
bool IsLambdaScope) {
203+
EnvFrame* E = CreateEnvFrame(Ids, IsLambdaScope);
194204
PushEnv(E, this->EnvStack);
195-
196-
// Push to any syntax closures not in the current EnvStack.
197-
for (Value Id : Ids) {
198-
if (auto* SC = dyn_cast<SyntaxClosure>(Id)) {
199-
if (this->EnvStack != SC->Env)
200-
PushEnv(E, SC->Env);
201-
}
202-
}
203-
204205
return E;
205206
}
206207

207208
void Context::PushLocalBinding(Binding* B) {
208209
PushEnv(B, this->EnvStack);
209-
if (auto* SC = dyn_cast<SyntaxClosure>(B->getIdentifier()))
210-
if (this->EnvStack != SC->Env)
211-
PushEnv(B, SC->Env);
212210
}
213211

214212
void Context::PushEnv(Value V, Value Env) {
@@ -480,15 +478,18 @@ class Writer : public ValueVisitor<Writer> {
480478
}
481479

482480
void VisitEnvFrame(EnvFrame* E) {
483-
OS << "#<EnvFrame {Bindings: {";
481+
OS << "#<EnvFrame {";
482+
if (E->isLambdaScope())
483+
OS << "IsLambda, ";
484+
OS << "Bindings: {";
484485
// Print the name of each binding.
485486
llvm::interleaveComma(E->getBindings(), OS,
486487
[&](Value B) {
487488
VisitBinding(cast<Binding>(B));
488489
});
489490
OS << "} LocalStack: {";
490491
Visit(E->getLocalStack());
491-
OS << "}>";
492+
OS << "}}>";
492493

493494
}
494495

@@ -1636,14 +1637,14 @@ ByteVector* Context::CreateByteVector(ArrayRef<Value> Xs) {
16361637
return BV;
16371638
}
16381639

1639-
EnvFrame* Context::CreateEnvFrame(unsigned N) {
1640+
EnvFrame* Context::CreateEnvFrame(unsigned N, bool IsLambdaScope) {
16401641
unsigned MemSize = EnvFrame::sizeToAlloc(N);
16411642
void* Mem = Allocate(MemSize, alignof(EnvFrame));
1642-
return new (Mem) EnvFrame(N);
1643+
return new (Mem) EnvFrame(N, IsLambdaScope);
16431644
}
16441645

1645-
EnvFrame* Context::CreateEnvFrame(llvm::ArrayRef<Value> Ids) {
1646-
EnvFrame* E = CreateEnvFrame(Ids.size());
1646+
EnvFrame* Context::CreateEnvFrame(llvm::ArrayRef<Value> Ids, bool IsLambdaScope) {
1647+
EnvFrame* E = CreateEnvFrame(Ids.size(), IsLambdaScope);
16471648
auto Bindings = E->getBindings();
16481649
for (unsigned i = 0; i < Bindings.size(); i++)
16491650
Bindings[i] = CreateBinding(Ids[i], CreateUndefined());

heavy/lib/Dialect.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,10 @@ void VectorOp::build(mlir::OpBuilder& B, mlir::OperationState& OpState,
263263
VectorOp::build(B, OpState, HeavyValueT, args);
264264
}
265265

266-
void EnvFrameOp::build(mlir::OpBuilder& B, mlir::OperationState& OpState,
267-
llvm::ArrayRef<mlir::Value> args) {
266+
void RenameEnvOp::build(mlir::OpBuilder& B, mlir::OperationState& OpState,
267+
mlir::Value Env, llvm::ArrayRef<mlir::Value> Bindings) {
268268
mlir::Type HeavyValueT = B.getType<HeavyValueTy>();
269-
EnvFrameOp::build(B, OpState, HeavyValueT, args);
269+
RenameEnvOp::build(B, OpState, HeavyValueT, Env, Bindings);
270270
}
271271

272272
void UndefinedOp::build(mlir::OpBuilder& B, mlir::OperationState& OpState) {

heavy/lib/Heap.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,13 @@ class CopyCollector : private ValueVisitor<CopyCollector, heavy::Value> {
103103
// EnvFrame
104104
heavy::Value VisitEnvFrame(heavy::EnvFrame* EnvFrame) {
105105
llvm::ArrayRef<heavy::Binding*> Bindings = EnvFrame->getBindings();
106+
bool IsLambdaScope = EnvFrame->isLambdaScope();
106107
unsigned MemSize = EnvFrame::sizeToAlloc(Bindings.size());
107108

108109
void* Mem = NewHeap.Allocate(MemSize, alignof(heavy::EnvFrame));
109110

110-
heavy::EnvFrame* NewE = new (Mem) heavy::EnvFrame(Bindings.size());
111+
heavy::EnvFrame* NewE = new (Mem) heavy::EnvFrame(Bindings.size(),
112+
IsLambdaScope);
111113
auto NewBindings = NewE->getBindings();
112114
for (unsigned i = 0; i < Bindings.size(); i++) {
113115
NewBindings[i] = cast<heavy::Binding>(Visit(Bindings[i]));

heavy/lib/OpEval.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ class OpEvalImpl {
176176
else if (isa<MatchIdOp>(Op)) return Visit(cast<MatchIdOp>(Op));
177177
else if (isa<RenameOp>(Op)) return Visit(cast<RenameOp>(Op));
178178
else if (isa<RenameGlobalOp>(Op)) return Visit(cast<RenameGlobalOp>(Op));
179-
else if (isa<EnvFrameOp>(Op)) return Visit(cast<EnvFrameOp>(Op));
179+
else if (isa<RenameEnvOp>(Op)) return Visit(cast<RenameEnvOp>(Op));
180180
else if (isa<ToVectorOp>(Op)) return Visit(cast<ToVectorOp>(Op));
181181
else if (isa<VectorOp>(Op)) return Visit(cast<VectorOp>(Op));
182182
else if (isa<LoadModuleOp>(Op)) return Visit(cast<LoadModuleOp>(Op));
@@ -552,15 +552,21 @@ class OpEvalImpl {
552552
return next(Op);
553553
}
554554

555-
BlockItrTy Visit(EnvFrameOp Op) {
556-
unsigned Size = Op.getArgs().size();
557-
heavy::EnvFrame* EnvFrame = Context.CreateEnvFrame(Size);
555+
BlockItrTy Visit(RenameEnvOp Op) {
556+
unsigned NumBindings = Op.getBindings().size();
557+
heavy::EnvFrame* EnvFrame = Context.CreateEnvFrame(NumBindings);
558558
llvm::MutableArrayRef<Binding*> Bindings = EnvFrame->getBindings();
559-
auto Vals = Op.getArgs();
560-
for (unsigned I = 0; I < Size; ++I)
559+
auto Vals = Op.getBindings();
560+
for (unsigned I = 0; I < NumBindings; ++I)
561561
Bindings[I] = cast<Binding>(getBindingOrValue(Vals[I]));
562562

563-
setValue(Op, EnvFrame);
563+
// Add the local environment on top of EnvFrame.
564+
heavy::Value Env = getValue(Op.getEnv());
565+
heavy::EnvFrame* LocalEnvFrame = Context.GetLocalEnvFrame(Env);
566+
// EnvFrame is the tail.
567+
heavy::Value NewEnv = Context.CreatePair(LocalEnvFrame, EnvFrame);
568+
569+
setValue(Op, NewEnv);
564570
return next(Op);
565571
}
566572

heavy/lib/OpGen.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -876,21 +876,27 @@ mlir::Value OpGen::createSequence(SourceLocation Loc, Value Body) {
876876
// been inserted by the `define` syntax. They are
877877
// initialized to "undefined" and their corresponding
878878
// heavy::Bindings placed in the EnvStack.
879-
// Walk the EnvStack up to the nearest EnvFrame and
880-
// collect these and insert the lazy initializers via SetOp
879+
// Walk the EnvStack owned by the EnvFrame of the current lambda scope.
880+
// Collect these and insert the lazy initializers via SetOp
881881
// in the lexical order that they were defined.
882882
bool OpGen::WalkDefineInits(Value Env, IdSet& LocalIds) {
883883
Pair* P = dyn_cast<Pair>(Env);
884884
if (!P) return false;
885-
if (isa<EnvFrame>(P->Car)) return false;
886-
if (WalkDefineInits(P->Cdr, LocalIds)) return true;
885+
// Walk the defines before this.
886+
if (WalkDefineInits(P->Cdr, LocalIds))
887+
return true;
888+
// Walk any defines in nested scopes.
889+
if (auto* EF = dyn_cast<EnvFrame>(P->Car)) {
890+
assert(!EF->isLambdaScope() &&
891+
"should not have any nested lambda scopes");
892+
return WalkDefineInits(EF->getLocalStack(), LocalIds);
893+
}
887894

888895
// Check for duplicate names.
889896
Binding* B = cast<Binding>(P->Car);
890897
Value Id = B->getIdentifier();
891-
bool IsNameInserted;
892-
std::tie(std::ignore, IsNameInserted) =
893-
LocalIds.insert(Context.GetIdentifierUniqueId(Id));
898+
std::pair<uintptr_t, uintptr_t> UniqueId = Context.GetIdentifierUniqueId(Id);
899+
auto [_, IsNameInserted] = LocalIds.insert(UniqueId);
894900
if (!IsNameInserted) {
895901
SetError("local variable has duplicate definitions", Id);
896902
return true;
@@ -916,14 +922,18 @@ bool OpGen::WalkDefineInits(Value Env, IdSet& LocalIds) {
916922
return false;
917923
}
918924

919-
bool OpGen::FinishLocalDefines() {
925+
void OpGen::FinishLocalDefines() {
920926
TailPosScope TPS(*this);
921927
IsTailPos = false;
922928
IsLocalDefineAllowed = false;
923929
IdSet LocalIds;
924-
// Get the localiest EnvFrame.
925-
Value EnvStack = Context.GetLocalEnvStack();
926-
return WalkDefineInits(EnvStack, LocalIds);
930+
// Get the most local EnvFrame that is a lambda scope.
931+
EnvFrame* EF = Context.GetLocalEnvFrame(Context.EnvStack,
932+
/*IsLambdaScope=*/true);
933+
assert(EF && "expecting a lambda scope env frame");
934+
if (!EF)
935+
return;
936+
WalkDefineInits(EF->getLocalStack(), LocalIds);
927937
}
928938

929939
mlir::Value OpGen::createBody(SourceLocation Loc, Value Body) {
@@ -1304,14 +1314,14 @@ mlir::Value OpGen::createContinuation(mlir::Operation* CallOp) {
13041314
}
13051315

13061316
mlir::Value OpGen::CallSyntax(Value Operator, Pair* P) {
1307-
Context.EnsureEnvFrame();
13081317
switch (Operator.getKind()) {
13091318
case ValueKind::BuiltinSyntax: {
13101319
Context.setLoc(P->getSourceLocation());
13111320
BuiltinSyntax* BS = cast<BuiltinSyntax>(Operator);
13121321
return BS->Fn(*this, P);
13131322
}
13141323
case ValueKind::Syntax: {
1324+
EnvFrame* EF = Context.PushEnvFrame();
13151325
heavy::Context& Context = this->Context;
13161326
Context.setLoc(P->getSourceLocation());
13171327
Value Input = P;
@@ -1325,6 +1335,7 @@ mlir::Value OpGen::CallSyntax(Value Operator, Pair* P) {
13251335
assert(OpGen == Context.OpGen && "OpGen should not unwind itself");
13261336
if (auto ResultErr = dyn_cast_or_null<heavy::Error>(Result))
13271337
SetError(ResultErr);
1338+
Context.PopEnvFrame(EF);
13281339
return toValue(Result);
13291340
}
13301341
default: {

heavy/lib/PatternTemplate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class PatternTemplate : ValueVisitor<PatternTemplate, mlir::Value> {
8686
}
8787

8888
if (!OpGen.CheckError()) {
89-
TemplateGen TG(OpGen, Keyword, PatternVars, Ellipsis);
89+
TemplateGen TG(OpGen, EnvArg, Keyword, PatternVars, Ellipsis);
9090
TG.BuildTemplate(Template);
9191
}
9292

0 commit comments

Comments
 (0)