Commit 7fe28ae0 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Refactor some common control-flow-creation code (NFC)

parent 7e8ba275
This diff is collapsed.
......@@ -68,6 +68,7 @@ public:
virtual IRBuilder* getBuilder() = 0;
virtual GCBuilder* getGC() = 0;
virtual CompiledFunction* currentFunction() = 0;
virtual llvm::BasicBlock* createBasicBlock(const char* name = "") = 0;
virtual llvm::Value* getScratch(int num_bytes) = 0;
virtual void releaseScratch(llvm::Value*) = 0;
......@@ -96,6 +97,25 @@ bool isIsDefinedName(const std::string& name);
CompiledFunction* doCompile(SourceInfo* source, const OSREntryDescriptor* entry_descriptor,
EffortLevel::EffortLevel effort, FunctionSpecialization* spec, std::string nameprefix);
// A common pattern is to branch based off whether a variable is defined but only if it is
// potentially-undefined. If it is potentially-undefined, we have to generate control-flow
// that branches on the is_defined variable and then generate different code on those two paths;
// if the variable is guaranteed to be defined, we just want to emit the when_defined version.
//
// I suppose we could always emit both and let the LLVM optimizer fix it up for us, but for now
// do it the hard (and hopefully faster) way.
//
// - is_defined_var is allowed to be NULL, signifying that the variable is always defined.
// Otherwise it should be a BOOL variable that signifies if the variable is defined or not.
// - speculate_undefined means whether or not we should execute the when_undefined code generator
// in the current block (the one that we're in when calling this function); if set to true we will
// avoid generating a BB for the undefined case, which is useful if the "codegen" just returns
// an existing value or a constant.
llvm::Value* handlePotentiallyUndefined(ConcreteCompilerVariable* is_defined_var, llvm::Type* rtn_type,
llvm::BasicBlock*& cur_block, IREmitter& emitter, bool speculate_undefined,
std::function<llvm::Value*(IREmitter&)> when_defined,
std::function<llvm::Value*(IREmitter&)> when_undefined);
class TypeRecorder;
class OpInfo {
private:
......
......@@ -118,6 +118,10 @@ private:
}
}
llvm::BasicBlock* createBasicBlock(const char* name) override {
return llvm::BasicBlock::Create(g.context, name, irstate->getLLVMFunction());
}
llvm::CallSite emitPatchpoint(llvm::Type* return_type, const ICSetupInfo* pp, llvm::Value* func,
const std::vector<llvm::Value*>& args,
const std::vector<llvm::Value*>& ic_stackmap_args, UnwindInfo unw_info) {
......@@ -837,33 +841,15 @@ private:
if (is_defined_var) {
// classdefs have different scoping rules than functions:
if (irstate->getSourceInfo()->ast->type == AST_TYPE::ClassDef) {
llvm::BasicBlock* from_local
= llvm::BasicBlock::Create(g.context, "from_local", irstate->getLLVMFunction());
llvm::BasicBlock* from_global
= llvm::BasicBlock::Create(g.context, "from_global", irstate->getLLVMFunction());
llvm::BasicBlock* join = llvm::BasicBlock::Create(g.context, "join", irstate->getLLVMFunction());
emitter.getBuilder()->CreateCondBr(i1FromBool(emitter, is_defined_var), from_local, from_global);
emitter.getBuilder()->SetInsertPoint(from_local);
curblock = from_local;
CompilerVariable* local = symbol_table[node->id];
ConcreteCompilerVariable* converted_local = local->makeConverted(emitter, local->getBoxType());
// don't decvref local here, because are manufacturing a new vref
emitter.getBuilder()->CreateBr(join);
emitter.getBuilder()->SetInsertPoint(from_global);
curblock = from_global;
ConcreteCompilerVariable* global = _getGlobal(node, unw_info);
emitter.getBuilder()->CreateBr(join);
emitter.getBuilder()->SetInsertPoint(join);
curblock = join;
llvm::PHINode* phi = emitter.getBuilder()->CreatePHI(g.llvm_value_type_ptr, 2, node->id);
phi->addIncoming(converted_local->getValue(), from_local);
phi->addIncoming(global->getValue(), from_global);
return new ConcreteCompilerVariable(UNKNOWN, phi, true);
llvm::Value* v = handlePotentiallyUndefined(
is_defined_var, g.llvm_value_type_ptr, curblock, emitter, false,
[=](IREmitter& emitter) {
CompilerVariable* local = symbol_table[node->id];
return local->makeConverted(emitter, local->getBoxType())->getValue();
},
[=](IREmitter& emitter) { return _getGlobal(node, unw_info)->getValue(); });
return new ConcreteCompilerVariable(UNKNOWN, v, true);
}
emitter.createCall(unw_info, g.funcs.assertNameDefined,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment