Skip to content

Commit

Permalink
try
Browse files Browse the repository at this point in the history
  • Loading branch information
JanJecmen committed May 26, 2022
1 parent 0fd9acb commit 6e67f62
Show file tree
Hide file tree
Showing 15 changed files with 301 additions and 191 deletions.
23 changes: 5 additions & 18 deletions rir/src/compiler/analysis/verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class TheVerifier {
std::unordered_set<BB*> seenPreds;

void operator()() {
Visitor::run(f->entry, [&](BB* bb) { return verify(bb, false); });
Visitor::run(f->entry, [&](BB* bb) { return verify(bb); });
Visitor::run(f->entry, [&](BB* bb) { seenPreds.erase(bb); });
if (!seenPreds.empty()) {
std::cerr << "The following preds are not reachable from entry: ";
Expand Down Expand Up @@ -98,7 +98,7 @@ class TheVerifier {
return doms.at(c);
}

void verify(BB* bb, bool inPromise) {
void verify(BB* bb) {
if (bb->id >= bb->owner->nextBBId) {
std::cout << "BB" << bb->id << " id is bigger than max ("
<< bb->owner->nextBBId << ")\n";
Expand All @@ -121,7 +121,7 @@ class TheVerifier {
}

for (auto i : *bb) {
verify(i, bb, inPromise);
verify(i, bb);
}
/* This check verifies that our graph is in edge-split format.
Currently we do not rely on this property, however we should
Expand Down Expand Up @@ -196,10 +196,10 @@ class TheVerifier {
}

void verify(Promise* p) {
Visitor::run(p->entry, [&](BB* bb) { verify(bb, true); });
Visitor::run(p->entry, [&](BB* bb) { verify(bb); });
}

void verify(Instruction* i, BB* bb, bool inPromise) {
void verify(Instruction* i, BB* bb) {
if (i->bb() != bb) {
std::cerr << "Error: instruction '";
i->print(std::cerr);
Expand Down Expand Up @@ -269,19 +269,6 @@ class TheVerifier {
});
}

if (i->frameState()) {
if (!inPromise) {
auto fs = i->frameState();
while (fs->next())
fs = fs->next();
if (fs->inPromise) {
std::cerr << "Error: instruction '";
i->print(std::cerr);
std::cerr << "' outermost fs inPromis in body code\n";
ok = false;
}
}
}
if (auto assume = Assume::Cast(i)) {
if (IsType::Cast(assume->arg(0).val())) {
if (!assume->reason.pc()) {
Expand Down
2 changes: 1 addition & 1 deletion rir/src/compiler/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ void Compiler::compileClosure(Closure* closure, rir::Function* optFunction,
auto arg = closure->formals().defaultArgs()[idx];
assert(rir::Code::check(arg) && "Default arg not compiled");
auto code = rir::Code::unpack(arg);
auto res = rir2pir.tryCreateArg(code, builder, false);
auto res = rir2pir.tryCreateArg(code, builder);
if (!res) {
failedToCompileDefaultArgs = true;
return;
Expand Down
55 changes: 43 additions & 12 deletions rir/src/compiler/native/builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,8 +828,8 @@ static SEXP deoptSentinelContainer = []() {
return store;
}();

void deoptImpl(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
bool leakedEnv, DeoptReason* deoptReason, SEXP deoptTrigger) {
SEXP deopt(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
bool leakedEnv, DeoptReason* deoptReason, SEXP deoptTrigger) {
deoptReason->record(deoptTrigger);

assert(m->numFrames >= 1);
Expand All @@ -854,8 +854,9 @@ void deoptImpl(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
auto le = LazyEnvironment::check(env);
if (deoptless && m->numFrames == 1 && cls != deoptlessRecursion &&
((le && !le->materialized()) ||
(!le && (!leakedEnv || !deoptlessNoLeakedEnvs)))) {
assert(m->frames[0].inPromise == false);
(!le && (!leakedEnv || !deoptlessNoLeakedEnvs))) &&
/* TODO: support deoptless when outermost frame is a promise */
!m->frames[0].inPromise) {

size_t envSize = le ? le->nargs : Rf_length(FRAME(env));
if (envSize <= DeoptContext::MAX_ENV &&
Expand Down Expand Up @@ -932,8 +933,8 @@ void deoptImpl(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,

Rf_findcontext(CTXT_BROWSER | CTXT_FUNCTION,
originalCntxt->cloenv, res);
assert(false);
return;
assert(false && "unreachable after deoptless");
return nullptr;
}
}
}
Expand All @@ -945,13 +946,35 @@ void deoptImpl(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
if (f->body() == c)
Pool::patch(idx, deoptSentinelContainer);

CallContext call(ArglistOrder::NOT_REORDERED, c, cls,
/* nargs */ -1, src_pool_at(c->src), args,
(Immediate*)nullptr, env, R_NilValue, Context());
if (cls) {
CallContext call(ArglistOrder::NOT_REORDERED, c, cls,
/* nargs */ -1, src_pool_at(c->src), args,
(Immediate*)nullptr, env, R_NilValue, Context());

deoptFramesWithContext(&call, m, R_NilValue, m->numFrames - 1, stackHeight,
(RCNTXT*)R_GlobalContext);
assert(false);
// Deopt in a function longjumps to its context
deoptFramesWithContext(&call, m, R_NilValue, m->numFrames - 1,
stackHeight, (RCNTXT*)R_GlobalContext);
assert(false && "unreachable after deopt");
return nullptr;
} else {
// Deopt in a promise has nowhere to longjump, so it leaves the result
// on the TOS and returns here, this is immediately returned as the
// result of the promise
deoptFramesWithContext(nullptr, m, R_NilValue, m->numFrames - 1,
stackHeight, (RCNTXT*)R_GlobalContext);
return ostack_pop();
}
}

void deoptImpl(rir::Code* c, SEXP cls, DeoptMetadata* m, R_bcstack_t* args,
bool leakedEnv, DeoptReason* deoptReason, SEXP deoptTrigger) {
deopt(c, cls, m, args, leakedEnv, deoptReason, deoptTrigger);
}

SEXP deoptPromImpl(rir::Code* c, DeoptMetadata* m, R_bcstack_t* args,
bool leakedEnv, DeoptReason* deoptReason,
SEXP deoptTrigger) {
return deopt(c, nullptr, m, args, leakedEnv, deoptReason, deoptTrigger);
}

void recordTypefeedbackImpl(Opcode* pos, rir::Code* code, SEXP value) {
Expand Down Expand Up @@ -2437,6 +2460,14 @@ void NativeBuiltins::initializeBuiltins() {
t::DeoptReasonPtr, t::SEXP},
false),
{llvm::Attribute::NoReturn}};
get_(Id::deoptProm) = {
"deoptProm",
(void*)&deoptPromImpl,
llvm::FunctionType::get(t::SEXP,
{t::voidPtr, t::voidPtr, t::stackCellPtr, t::i1,
t::DeoptReasonPtr, t::SEXP},
false),
{}};
get_(Id::assertFail) = {"assertFail",
(void*)&assertFailImpl,
t::void_voidPtr,
Expand Down
1 change: 1 addition & 0 deletions rir/src/compiler/native/builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ struct NativeBuiltins {
length,
recordTypefeedback,
deopt,
deoptProm,
assertFail,
printValue,
extract11,
Expand Down
42 changes: 32 additions & 10 deletions rir/src/compiler/native/lower_function_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2112,6 +2112,7 @@ void LowerFunctionLLVM::compile() {
stack({container(paramCode())});
additionalStackSlots++;
}

{
SmallSet<std::pair<Value*, SEXP>> bindings;
Visitor::run(code->entry, [&](Instruction* i) {
Expand Down Expand Up @@ -3555,21 +3556,42 @@ void LowerFunctionLLVM::compile() {
args.push_back(fs->arg(pos).val());
args.push_back(fs->env());
m->frames[frameNr--] = {fs->pc, fs->code, fs->stackSize,
fs->inPromise};
fs->inPromise, fs->patch};
}

target->addExtraPoolEntry(store);
}

withCallFrame(args, [&]() {
return call(NativeBuiltins::get(NativeBuiltins::Id::deopt),
{paramCode(), paramClosure(),
convertToPointer(m, t::i8, true), paramArgs(),
c(deopt->escapedEnv, 1),
load(deopt->deoptReason()),
loadSxp(deopt->deoptTrigger())});
});
builder.CreateUnreachable();
// Deopt only returns if the outermost frame is a promise.
// In that case, the result is the returned value and we simply
// return it from here.
if (code->isPromise()) {
auto res = withCallFrame(
args,
[&]() {
return call(NativeBuiltins::get(
NativeBuiltins::Id::deoptProm),
{paramCode(),
convertToPointer(m, t::i8, true),
paramArgs(), c(deopt->escapedEnv, 1),
load(deopt->deoptReason()),
loadSxp(deopt->deoptTrigger())});
},
false);
exitBlocks.push_back(builder.GetInsertBlock());
builder.CreateRet(res);
} else {
withCallFrame(args, [&]() {
return call(
NativeBuiltins::get(NativeBuiltins::Id::deopt),
{paramCode(), paramClosure(),
convertToPointer(m, t::i8, true), paramArgs(),
c(deopt->escapedEnv, 1),
load(deopt->deoptReason()),
loadSxp(deopt->deoptTrigger())});
});
builder.CreateUnreachable();
}
break;
}

Expand Down
9 changes: 8 additions & 1 deletion rir/src/compiler/opt/force_dominance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,14 @@ bool ForceDominance::apply(Compiler&, ClosureVersion* cls, Code* code,
Value* eager = mkarg->eagerArg();
f->replaceUsesWith(eager);
next = bb->remove(ip);
} else if (toInline.count(f)) {
} else if (toInline.count(f) &&
// Can't inline a promise with Assumes if the
// dominating Force doesn't have a Framestate
(f->frameState() ||
Visitor::check(mkarg->prom()->entry,
[](Instruction* i) {
return !Assume::Cast(i);
}))) {
anyChange = true;
Promise* prom = mkarg->prom();
BB* split =
Expand Down
4 changes: 2 additions & 2 deletions rir/src/compiler/pir/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ void Builder::add(Instruction* i) {
}

FrameState* Builder::registerFrameState(rir::Code* srcCode, Opcode* pos,
const RirStack& stack, bool inPromise) {
auto sp = new FrameState(env, srcCode, pos, stack, inPromise);
const RirStack& stack, bool inPromise, int8_t patch) {
auto sp = new FrameState(env, srcCode, pos, stack, inPromise, patch);
add(sp);
return sp;
}
Expand Down
2 changes: 1 addition & 1 deletion rir/src/compiler/pir/builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Builder {
void setBranch(BB* bb1, BB* bb2);

FrameState* registerFrameState(rir::Code* srcCode, Opcode* pos,
const RirStack& stack, bool inPromise);
const RirStack& stack, bool inPromise, int8_t patch = -1);
Checkpoint* emitCheckpoint(rir::Code* srcCode, Opcode* pos,
const RirStack& stack, bool inPromise);
Checkpoint* emitCheckpoint(FrameState* fs);
Expand Down
2 changes: 2 additions & 0 deletions rir/src/compiler/pir/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Code {
virtual rir::Code* rirSrc() const = 0;
virtual void printName(std::ostream&) const = 0;

virtual bool isPromise() const { return false; }

friend std::ostream& operator<<(std::ostream& out, const Code& e) {
e.printName(out);
return out;
Expand Down
5 changes: 3 additions & 2 deletions rir/src/compiler/pir/instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,7 @@ class VLIE(FrameState, Effects() | Effect::ReadsEnv) {
rir::Code* code;
size_t stackSize;
bool inPromise;
int8_t patch;

size_t gvnBase() const override {
return hash_combine(
Expand All @@ -937,9 +938,9 @@ class VLIE(FrameState, Effects() | Effect::ReadsEnv) {
}

FrameState(Value* env, rir::Code* code, Opcode* pc, const RirStack& stack,
bool inPromise)
bool inPromise, int8_t patch)
: VarLenInstructionWithEnvSlot(NativeType::frameState, env), pc(pc),
code(code), stackSize(stack.size()), inPromise(inPromise) {
code(code), stackSize(stack.size()), inPromise(inPromise), patch(patch) {
for (auto& v : stack)
pushArg(v, PirType::any());
}
Expand Down
2 changes: 2 additions & 0 deletions rir/src/compiler/pir/promise.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class Promise : public Code {

void printName(std::ostream& out) const override;

bool isPromise() const override final { return true; }

private:
rir::Code* rirSrc_;
const unsigned srcPoolIdx_;
Expand Down
Loading

0 comments on commit 6e67f62

Please sign in to comment.