Commit 21b20e3b authored by Kevin Modzelewski's avatar Kevin Modzelewski

Generate cxx "fixups" on-demand

fixups aka the stubs that decref whatever's needed when an exception is thrown

I looked into this because most (75%?) of the refcounting overhead
comes from the cxx fixups.  Previously we would always generate them in
the IRGenerator, regardless of whether they were needed.  Now they are
generated in the refcounter, which knows whether they are needed or not.

Unfortunately it looks like they are usually needed, so the gains here
aren't that great (saves about 10% llvm instructions whereas cxx fixups
in general added about 400% more llvm instructions).

I think this is still a good change because it's also necessary in order to use
Marius's EH stuff.

I think the cost of the fixups is mostly related to the cost of the decrefs
that it adds, so even though most of the refcounting overhead seems to be due to
adding the cxx fixups, reducing general decref overhead might reduce cxx fixup overhead
parent 7b95f4d5
......@@ -15,6 +15,7 @@
#ifndef PYSTON_CODEGEN_IRGEN_H
#define PYSTON_CODEGEN_IRGEN_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/IR/CallSite.h"
......@@ -216,13 +217,16 @@ private:
llvm::DenseMap<llvm::Instruction*, llvm::SmallVector<llvm::Value*, 4>> refs_consumed;
llvm::DenseMap<llvm::Instruction*, llvm::SmallVector<llvm::Value*, 4>> refs_used;
llvm::ValueMap<llvm::Value*, RefcountState> vars;
llvm::DenseSet<llvm::Instruction*> may_throw;
public:
llvm::Value* setType(llvm::Value* v, RefType reftype);
llvm::Value* setNullable(llvm::Value* v, bool nullable = true);
void refConsumed(llvm::Value* v, llvm::Instruction*);
void refUsed(llvm::Value* v, llvm::Instruction*);
void setMayThrow(llvm::Instruction*);
static void addRefcounts(IRGenState* state);
bool isNullable(llvm::Value* v);
};
}
......
......@@ -447,7 +447,7 @@ private:
if (unw_info.exc_dest == NO_CXX_INTERCEPTION) {
needs_cxx_interception = false;
} else {
bool needs_refcounting_fixup = true;
bool needs_refcounting_fixup = false;
needs_cxx_interception = (target_exception_style == CXX && (needs_refcounting_fixup || unw_info.hasHandler()
|| irstate->getExceptionStyle() == CAPI));
}
......@@ -487,6 +487,9 @@ private:
} else {
llvm::CallInst* cs = getBuilder()->CreateCall(callee, args);
if (target_exception_style == CXX)
irstate->getRefcounts()->setMayThrow(cs);
if (target_exception_style == CAPI)
checkAndPropagateCapiException(unw_info, cs, capi_exc_value);
......@@ -1035,7 +1038,8 @@ private:
auto inst = emitter.createCall(UnwindInfo::cantUnwind(), g.funcs.setFrameExcInfo,
{ frame_info, converted_type->getValue(), converted_value->getValue(),
converted_traceback->getValue() });
converted_traceback->getValue() },
NOEXC);
emitter.refConsumed(converted_type->getValue(), inst);
emitter.refConsumed(converted_value->getValue(), inst);
emitter.refConsumed(converted_traceback->getValue(), inst);
......@@ -3065,31 +3069,8 @@ public:
emitter.getBuilder()->SetInsertPoint(cxx_exc_dest);
llvm::Function* _personality_func = g.stdlib_module->getFunction("__gxx_personality_v0");
assert(_personality_func);
llvm::Value* personality_func
= g.cur_module->getOrInsertFunction(_personality_func->getName(), _personality_func->getFunctionType());
assert(personality_func);
llvm::LandingPadInst* landing_pad = emitter.getBuilder()->CreateLandingPad(
llvm::StructType::create(std::vector<llvm::Type*>{ g.i8_ptr, g.i64 }), personality_func, 1);
landing_pad->addClause(getNullPtr(g.i8_ptr));
llvm::Value* cxaexc_pointer = emitter.getBuilder()->CreateExtractValue(landing_pad, { 0 });
llvm::Function* std_module_catch = g.stdlib_module->getFunction("__cxa_begin_catch");
auto begin_catch_func
= g.cur_module->getOrInsertFunction(std_module_catch->getName(), std_module_catch->getFunctionType());
assert(begin_catch_func);
llvm::Value* excinfo_pointer = emitter.getBuilder()->CreateCall(begin_catch_func, cxaexc_pointer);
llvm::Value* excinfo_pointer_casted
= emitter.getBuilder()->CreateBitCast(excinfo_pointer, g.llvm_excinfo_type->getPointerTo());
auto* builder = emitter.getBuilder();
llvm::Value* exc_type = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 0));
llvm::Value* exc_value = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 1));
llvm::Value* exc_traceback
= builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 2));
llvm::Value* exc_type, *exc_value, *exc_traceback;
std::tie(exc_type, exc_value, exc_traceback) = createLandingpad(cxx_exc_dest);
emitter.setType(exc_type, RefType::OWNED);
emitter.setType(exc_value, RefType::OWNED);
emitter.setType(exc_traceback, RefType::OWNED);
......@@ -3101,23 +3082,24 @@ public:
new ConcreteCompilerVariable(UNKNOWN, exc_value),
new ConcreteCompilerVariable(UNKNOWN, exc_traceback)));
builder->CreateBr(final_dest);
emitter.getBuilder()->CreateBr(final_dest);
} else if (irstate->getExceptionStyle() == CAPI) {
auto call_inst = builder->CreateCall3(g.funcs.PyErr_Restore, exc_type, exc_value, exc_traceback);
auto call_inst
= emitter.getBuilder()->CreateCall3(g.funcs.PyErr_Restore, exc_type, exc_value, exc_traceback);
irstate->getRefcounts()->refConsumed(exc_type, call_inst);
irstate->getRefcounts()->refConsumed(exc_value, call_inst);
irstate->getRefcounts()->refConsumed(exc_traceback, call_inst);
builder->CreateCall(g.funcs.deinitFrame, irstate->getFrameInfoVar());
builder->CreateRet(getNullPtr(g.llvm_value_type_ptr));
emitter.getBuilder()->CreateCall(g.funcs.deinitFrame, irstate->getFrameInfoVar());
emitter.getBuilder()->CreateRet(getNullPtr(g.llvm_value_type_ptr));
} else {
// auto call_inst = emitter.createCall3(UnwindInfo(unw_info.current_stmt, NO_CXX_INTERCEPTION),
// g.funcs.rawThrow, exc_type, exc_value, exc_traceback);
auto call_inst = emitter.getBuilder()->CreateCall3(g.funcs.rawThrow, exc_type, exc_value, exc_traceback);
// g.funcs.rawReraise, exc_type, exc_value, exc_traceback);
auto call_inst = emitter.getBuilder()->CreateCall3(g.funcs.rawReraise, exc_type, exc_value, exc_traceback);
irstate->getRefcounts()->refConsumed(exc_type, call_inst);
irstate->getRefcounts()->refConsumed(exc_value, call_inst);
irstate->getRefcounts()->refConsumed(exc_traceback, call_inst);
builder->CreateUnreachable();
emitter.getBuilder()->CreateUnreachable();
}
emitter.setCurrentBasicBlock(orig_block);
......@@ -3135,6 +3117,37 @@ public:
}
};
std::tuple<llvm::Value*, llvm::Value*, llvm::Value*> createLandingpad(llvm::BasicBlock* bb) {
assert(bb->begin() == bb->end());
llvm::IRBuilder<true> builder(bb);
llvm::Function* _personality_func = g.stdlib_module->getFunction("__gxx_personality_v0");
assert(_personality_func);
llvm::Value* personality_func
= g.cur_module->getOrInsertFunction(_personality_func->getName(), _personality_func->getFunctionType());
assert(personality_func);
llvm::LandingPadInst* landing_pad = builder.CreateLandingPad(
llvm::StructType::create(std::vector<llvm::Type*>{ g.i8_ptr, g.i64 }), personality_func, 1);
landing_pad->addClause(getNullPtr(g.i8_ptr));
llvm::Value* cxaexc_pointer = builder.CreateExtractValue(landing_pad, { 0 });
llvm::Function* std_module_catch = g.stdlib_module->getFunction("__cxa_begin_catch");
auto begin_catch_func
= g.cur_module->getOrInsertFunction(std_module_catch->getName(), std_module_catch->getFunctionType());
assert(begin_catch_func);
llvm::Value* excinfo_pointer = builder.CreateCall(begin_catch_func, cxaexc_pointer);
llvm::Value* excinfo_pointer_casted = builder.CreateBitCast(excinfo_pointer, g.llvm_excinfo_type->getPointerTo());
llvm::Value* exc_type = builder.CreateLoad(builder.CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 0));
llvm::Value* exc_value = builder.CreateLoad(builder.CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 1));
llvm::Value* exc_traceback = builder.CreateLoad(builder.CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 2));
return std::make_tuple(exc_type, exc_value, exc_traceback);
}
IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks,
CFGBlock* myblock, TypeAnalysis* types) {
return new IRGeneratorImpl(irstate, entry_blocks, myblock, types);
......
......@@ -172,6 +172,8 @@ public:
virtual CFGBlock* getCFGBlock() = 0;
};
std::tuple<llvm::Value*, llvm::Value*, llvm::Value*> createLandingpad(llvm::BasicBlock*);
class IREmitter;
class AST_Call;
IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRGenerator* irgenerator = NULL);
......
This diff is collapsed.
......@@ -315,7 +315,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(raise0_capi);
GET(raise3);
GET(raise3_capi);
GET(rawThrow);
GET(rawReraise);
GET(PyErr_Fetch);
GET(PyErr_NormalizeException);
GET(PyErr_Restore);
......
......@@ -51,7 +51,7 @@ struct GlobalFuncs {
llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel;
llvm::Value* __cxa_end_catch;
llvm::Value* raise0, *raise0_capi, *raise3, *raise3_capi, *rawThrow;
llvm::Value* raise0, *raise0_capi, *raise3, *raise3_capi, *rawReraise;
llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *PyErr_Restore, *caughtCapiException, *reraiseCapiExcAsCxx;
llvm::Value* deopt;
llvm::Value* checkRefs;
......
......@@ -282,8 +282,7 @@ extern "C" void reraiseCapiExcAsCxx() {
throw e;
}
// XXX rename this
extern "C" void rawThrow(Box* type, Box* value, Box* tb) {
extern "C" void rawReraise(Box* type, Box* value, Box* tb) {
startReraise();
throw ExcInfo(type, value, tb);
}
......
......@@ -130,7 +130,7 @@ void force() {
FORCE(raise0_capi);
FORCE(raise3);
FORCE(raise3_capi);
FORCE(rawThrow);
FORCE(rawReraise);
FORCE(PyErr_Fetch);
FORCE(PyErr_NormalizeException);
FORCE(PyErr_Restore);
......
......@@ -37,7 +37,7 @@ extern "C" void raise0(ExcInfo* frame_exc_info) __attribute__((__noreturn__));
extern "C" void raise0_capi(ExcInfo* frame_exc_info) noexcept;
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
extern "C" void raise3_capi(Box*, Box*, Box*) noexcept;
extern "C" void rawThrow(Box*, Box*, Box*) __attribute__((__noreturn__));
extern "C" void rawReraise(Box*, Box*, Box*) __attribute__((__noreturn__));
void raiseExc(STOLEN(Box*) exc_obj) __attribute__((__noreturn__));
void _printStacktrace();
......
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