Skip to content

Add inlining for #to:do: loops #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/compiler/BytecodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,14 @@ void EmitRETURNNONLOCAL(MethodGenerationContext& mgenc) {
Emit1(mgenc, BC_RETURN_NON_LOCAL, 0);
}

void EmitINC(MethodGenerationContext& mgenc) {
Emit1(mgenc, BC_INC, 0);
}

void EmitDupSecond(MethodGenerationContext& mgenc) {
Emit1(mgenc, BC_DUP_SECOND, 1);
}

size_t EmitJumpOnBoolWithDummyOffset(MethodGenerationContext& mgenc,
bool isIfTrue, bool needsPop) {
// Remember: true and false seem flipped here.
Expand Down Expand Up @@ -285,6 +293,13 @@ size_t EmitJumpWithDumyOffset(MethodGenerationContext& mgenc) {
return idx;
}

size_t EmitJumpIfGreaterWithDummyOffset(MethodGenerationContext& mgenc) {
Emit1(mgenc, BC_JUMP_IF_GREATER, 0);
size_t idx = mgenc.AddBytecodeArgumentAndGetIndex(0);
mgenc.AddBytecodeArgument(0);
return idx;
}

void EmitJumpBackwardWithOffset(MethodGenerationContext& mgenc,
size_t jumpOffset) {
uint8_t jumpBytecode =
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/BytecodeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,13 @@ void EmitSUPERSEND(MethodGenerationContext& mgenc, VMSymbol* msg);
void EmitRETURNLOCAL(MethodGenerationContext& mgenc);
void EmitRETURNNONLOCAL(MethodGenerationContext& mgenc);

void EmitINC(MethodGenerationContext& mgenc);
void EmitDupSecond(MethodGenerationContext& mgenc);

size_t EmitJumpOnBoolWithDummyOffset(MethodGenerationContext& mgenc,
bool isIfTrue, bool needsPop);
size_t EmitJumpWithDumyOffset(MethodGenerationContext& mgenc);
size_t EmitJumpIfGreaterWithDummyOffset(MethodGenerationContext& mgenc);
void EmitJumpBackwardWithOffset(MethodGenerationContext& mgenc,
size_t jumpOffset);
size_t Emit3WithDummy(MethodGenerationContext& mgenc, uint8_t bytecode,
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/LexicalScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ class LexicalScope {
locals.push_back(var);
}

const Variable* GetArgument(size_t index, size_t contextLevel) {
if (contextLevel > 0) {
return outer->GetArgument(index, contextLevel - 1);
}

return &arguments.at(index);
}

const Variable* GetLocal(size_t index, uint8_t ctxLevel) {
if (ctxLevel > 0) {
return outer->GetLocal(index, ctxLevel - 1);
Expand Down
61 changes: 53 additions & 8 deletions src/compiler/MethodGenerationContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,26 +439,71 @@ bool MethodGenerationContext::InlineAndOr(bool isOr) {
return true;
}

bool MethodGenerationContext::InlineToDo() {
// HACK: We do assume that the receiver on the stack is a integer,
// HACK: similar to the other inlined messages.
// HACK: We don't support anything but integer at the moment.
assert(Bytecode::GetBytecodeLength(BC_PUSH_BLOCK) == 2);
if (!hasOneLiteralBlockArgument()) {
return false;
}

VMMethod* toBeInlined =
static_cast<VMMethod*>(extractBlockMethodAndRemoveBytecode());

toBeInlined->MergeScopeInto(*this);

const Variable* blockArg = toBeInlined->GetArgument(1, 0);
uint8_t iVarIdx = GetInlinedLocalIdx(blockArg);

isCurrentlyInliningABlock = true;
EmitDupSecond(*this);

size_t loopBeginIdx = OffsetOfNextInstruction();
size_t jumpOffsetIdxToEnd = EmitJumpIfGreaterWithDummyOffset(*this);

EmitDUP(*this);

EmitPOPLOCAL(*this, iVarIdx, 0);

toBeInlined->InlineInto(*this, false);

EmitPOP(*this);
EmitINC(*this);

EmitBackwardsJumpOffsetToTarget(loopBeginIdx);

PatchJumpOffsetToPointToNextInstruction(jumpOffsetIdxToEnd);

isCurrentlyInliningABlock = false;

return true;
}

void MethodGenerationContext::CompleteLexicalScope() {
lexicalScope = new LexicalScope(
outerGenc == nullptr ? nullptr : outerGenc->lexicalScope, arguments,
locals);
}

void MethodGenerationContext::MergeIntoScope(LexicalScope& scopeToBeInlined) {
assert(scopeToBeInlined.GetNumberOfArguments() == 1);
size_t numLocals = scopeToBeInlined.GetNumberOfLocals();
if (numLocals > 0) {
inlineLocals(scopeToBeInlined);
if (scopeToBeInlined.GetNumberOfArguments() > 1) {
inlineAsLocals(scopeToBeInlined.arguments);
}

if (scopeToBeInlined.GetNumberOfLocals() > 0) {
inlineAsLocals(scopeToBeInlined.locals);
}
}

void MethodGenerationContext::inlineLocals(LexicalScope& scopeToBeInlined) {
for (const Variable& local : scopeToBeInlined.locals) {
Variable freshCopy = local.CopyForInlining(this->locals.size());
void MethodGenerationContext::inlineAsLocals(vector<Variable>& vars) {
for (const Variable& var : vars) {
Variable freshCopy = var.CopyForInlining(this->locals.size());
if (freshCopy.IsValid()) {
assert(!freshCopy.IsArgument());

// freshCopy can be invalid, because we don't need the $blockSelf
std::string qualifiedName = local.MakeQualifiedName();
std::string qualifiedName = var.MakeQualifiedName();
assert(!Contains(this->locals, qualifiedName));
lexicalScope->AddInlinedLocal(freshCopy);
this->locals.push_back(freshCopy);
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/MethodGenerationContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class MethodGenerationContext {
bool InlineIfTrueOrIfFalse(bool isIfTrue);
bool InlineIfTrueFalse(bool isIfTrue);
bool InlineAndOr(bool isOr);
bool InlineToDo();

inline size_t OffsetOfNextInstruction() { return bytecode.size(); }

Expand All @@ -120,7 +121,7 @@ class MethodGenerationContext {

void completeJumpsAndEmitReturningNil(Parser& parser, size_t loopBeginIdx,
size_t jumpOffsetIdxToSkipLoopBody);
void inlineLocals(LexicalScope& scopeToBeInlined);
void inlineAsLocals(vector<Variable>& vars);
void checkJumpOffset(size_t jumpOffset, uint8_t bytecode);
void resetLastBytecodeBuffer();

Expand Down
7 changes: 4 additions & 3 deletions src/compiler/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,8 @@ void Parser::binaryMessage(MethodGenerationContext& mgenc, bool super) {

binaryOperand(mgenc);

if (!super && (msgSelector == "||" && mgenc.InlineAndOr(true)) ||
(msgSelector == "&&" && mgenc.InlineAndOr(false))) {
if (!super && ((msgSelector == "||" && mgenc.InlineAndOr(true)) ||
(msgSelector == "&&" && mgenc.InlineAndOr(false)))) {
return;
}

Expand Down Expand Up @@ -645,7 +645,8 @@ void Parser::keywordMessage(MethodGenerationContext& mgenc, bool super) {

if (numParts == 2 &&
((kw == "ifTrue:ifFalse:" && mgenc.InlineIfTrueFalse(true)) ||
(kw == "ifFalse:ifTrue:" && mgenc.InlineIfTrueFalse(false)))) {
(kw == "ifFalse:ifTrue:" && mgenc.InlineIfTrueFalse(false)) ||
(kw == "to:do:" && mgenc.InlineToDo()))) {
return;
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/Variable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ std::string Variable::MakeQualifiedName() const {
Variable Variable::CopyForInlining(size_t newIndex) const {
if (isArgument) {
if (name == strBlockSelf) {
// that's invalid
return Variable();
}
return Variable(this, newIndex, true);
}
// arguments that are inlined need to turn into variables, too
return Variable(this, newIndex, false);
}
2 changes: 2 additions & 0 deletions src/compiler/Variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Variable {

Variable CopyForInlining(size_t newIndex) const;

bool IsArgument() const { return isArgument; }

protected:
std::string name;
uint8_t index;
Expand Down
34 changes: 34 additions & 0 deletions src/interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "../interpreter/bytecodes.h" // NOLINT(misc-include-cleaner) it's required for InterpreterLoop.h
#include "../memory/Heap.h"
#include "../misc/defs.h"
#include "../vm/Globals.h"
#include "../vm/IsValidObject.h"
#include "../vm/Universe.h"
#include "../vmobjects/IntegerBox.h"
Expand All @@ -42,6 +43,7 @@
#include "../vmobjects/VMArray.h"
#include "../vmobjects/VMBlock.h"
#include "../vmobjects/VMClass.h"
#include "../vmobjects/VMDouble.h"
#include "../vmobjects/VMFrame.h"
#include "../vmobjects/VMInvokable.h"
#include "../vmobjects/VMMethod.h"
Expand Down Expand Up @@ -407,6 +409,38 @@ void Interpreter::doReturnNonLocal() {
popFrameAndPushResult(result);
}

void Interpreter::doInc() {
vm_oop_t val = GetFrame()->Top();

if (IS_TAGGED(val) || CLASS_OF(val) == load_ptr(integerClass)) {
int64_t result = (int64_t)INT_VAL(val) + 1;
val = NEW_INT(result);
} else if (CLASS_OF(val) == load_ptr(doubleClass)) {
double d = static_cast<VMDouble*>(val)->GetEmbeddedDouble();
val = GetUniverse()->NewDouble(d + 1.0);
} else {
GetUniverse()->ErrorExit("unsupported");
}

GetFrame()->SetTop(store_root(val));
}

bool Interpreter::checkIsGreater() {
vm_oop_t top = GetFrame()->Top();
vm_oop_t top2 = GetFrame()->Top2();

if ((IS_TAGGED(top) || CLASS_OF(top) == load_ptr(integerClass)) &&
(IS_TAGGED(top2) || CLASS_OF(top2) == load_ptr(integerClass))) {
return INT_VAL(top) > INT_VAL(top2);
} else if ((CLASS_OF(top) == load_ptr(doubleClass)) &&
(CLASS_OF(top2) == load_ptr(doubleClass))) {
return static_cast<VMDouble*>(top)->GetEmbeddedDouble() >
static_cast<VMDouble*>(top2)->GetEmbeddedDouble();
}

return false;
}

void Interpreter::WalkGlobals(walk_heap_fn walk) {
method = load_ptr(static_cast<GCMethod*>(walk(tmp_ptr(method))));

Expand Down
2 changes: 2 additions & 0 deletions src/interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class Interpreter {
void doSuperSend(long bytecodeIndex);
void doReturnLocal();
void doReturnNonLocal();
void doInc();
bool checkIsGreater();
};

inline VMFrame* Interpreter::GetFrame() const {
Expand Down
41 changes: 41 additions & 0 deletions src/interpreter/InterpreterLoop.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ vm_oop_t Start() {

void* loopTargets[] = {&&LABEL_BC_HALT,
&&LABEL_BC_DUP,
&&LABEL_BC_DUP_SECOND,
&&LABEL_BC_PUSH_LOCAL,
&&LABEL_BC_PUSH_LOCAL_0,
&&LABEL_BC_PUSH_LOCAL_1,
Expand Down Expand Up @@ -40,17 +41,20 @@ vm_oop_t Start() {
&&LABEL_BC_SUPER_SEND,
&&LABEL_BC_RETURN_LOCAL,
&&LABEL_BC_RETURN_NON_LOCAL,
&&LABEL_BC_INC,
&&LABEL_BC_JUMP,
&&LABEL_BC_JUMP_ON_FALSE_POP,
&&LABEL_BC_JUMP_ON_TRUE_POP,
&&LABEL_BC_JUMP_ON_FALSE_TOP_NIL,
&&LABEL_BC_JUMP_ON_TRUE_TOP_NIL,
&&LABEL_BC_JUMP_IF_GREATER,
&&LABEL_BC_JUMP_BACKWARD,
&&LABEL_BC_JUMP2,
&&LABEL_BC_JUMP2_ON_FALSE_POP,
&&LABEL_BC_JUMP2_ON_TRUE_POP,
&&LABEL_BC_JUMP2_ON_FALSE_TOP_NIL,
&&LABEL_BC_JUMP2_ON_TRUE_TOP_NIL,
&&LABEL_BC_JUMP2_IF_GREATER,
&&LABEL_BC_JUMP2_BACKWARD};

goto* loopTargets[currentBytecodes[bytecodeIndexGlobal]];
Expand All @@ -66,6 +70,14 @@ vm_oop_t Start() {
doDup();
DISPATCH_NOGC();

LABEL_BC_DUP_SECOND:
PROLOGUE(1);
{
vm_oop_t elem = GetFrame()->GetStackElement(1);
GetFrame()->Push(elem);
}
DISPATCH_NOGC();

LABEL_BC_PUSH_LOCAL:
PROLOGUE(3);
doPushLocal(bytecodeIndexGlobal - 3);
Expand Down Expand Up @@ -249,6 +261,11 @@ vm_oop_t Start() {
doReturnNonLocal();
DISPATCH_NOGC();

LABEL_BC_INC:
PROLOGUE(1);
doInc();
DISPATCH_NOGC();

LABEL_BC_JUMP: {
uint8_t offset = currentBytecodes[bytecodeIndexGlobal + 1];
bytecodeIndexGlobal += offset;
Expand Down Expand Up @@ -305,6 +322,17 @@ LABEL_BC_JUMP_ON_TRUE_TOP_NIL: {
}
DISPATCH_NOGC();

LABEL_BC_JUMP_IF_GREATER: {
if (checkIsGreater()) {
bytecodeIndexGlobal += currentBytecodes[bytecodeIndexGlobal + 1];
GetFrame()->Pop();
GetFrame()->Pop();
} else {
bytecodeIndexGlobal += 3;
}
}
DISPATCH_NOGC();

LABEL_BC_JUMP_BACKWARD: {
uint8_t offset = currentBytecodes[bytecodeIndexGlobal + 1];
bytecodeIndexGlobal -= offset;
Expand Down Expand Up @@ -376,6 +404,19 @@ LABEL_BC_JUMP2_ON_TRUE_TOP_NIL: {
}
DISPATCH_NOGC();

LABEL_BC_JUMP2_IF_GREATER: {
if (checkIsGreater()) {
bytecodeIndexGlobal +=
ComputeOffset(currentBytecodes[bytecodeIndexGlobal + 1],
currentBytecodes[bytecodeIndexGlobal + 2]);
GetFrame()->Pop();
GetFrame()->Pop();
} else {
bytecodeIndexGlobal += 3;
}
}
DISPATCH_NOGC();

LABEL_BC_JUMP2_BACKWARD: {
uint16_t offset = ComputeOffset(currentBytecodes[bytecodeIndexGlobal + 1],
currentBytecodes[bytecodeIndexGlobal + 2]);
Expand Down
Loading