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 @@ ...@@ -15,6 +15,7 @@
#ifndef PYSTON_CODEGEN_IRGEN_H #ifndef PYSTON_CODEGEN_IRGEN_H
#define PYSTON_CODEGEN_IRGEN_H #define PYSTON_CODEGEN_IRGEN_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"
#include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/IR/CallSite.h" #include "llvm/IR/CallSite.h"
...@@ -216,13 +217,16 @@ private: ...@@ -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_consumed;
llvm::DenseMap<llvm::Instruction*, llvm::SmallVector<llvm::Value*, 4>> refs_used; llvm::DenseMap<llvm::Instruction*, llvm::SmallVector<llvm::Value*, 4>> refs_used;
llvm::ValueMap<llvm::Value*, RefcountState> vars; llvm::ValueMap<llvm::Value*, RefcountState> vars;
llvm::DenseSet<llvm::Instruction*> may_throw;
public: public:
llvm::Value* setType(llvm::Value* v, RefType reftype); llvm::Value* setType(llvm::Value* v, RefType reftype);
llvm::Value* setNullable(llvm::Value* v, bool nullable = true); llvm::Value* setNullable(llvm::Value* v, bool nullable = true);
void refConsumed(llvm::Value* v, llvm::Instruction*); void refConsumed(llvm::Value* v, llvm::Instruction*);
void refUsed(llvm::Value* v, llvm::Instruction*); void refUsed(llvm::Value* v, llvm::Instruction*);
void setMayThrow(llvm::Instruction*);
static void addRefcounts(IRGenState* state); static void addRefcounts(IRGenState* state);
bool isNullable(llvm::Value* v);
}; };
} }
......
...@@ -447,7 +447,7 @@ private: ...@@ -447,7 +447,7 @@ private:
if (unw_info.exc_dest == NO_CXX_INTERCEPTION) { if (unw_info.exc_dest == NO_CXX_INTERCEPTION) {
needs_cxx_interception = false; needs_cxx_interception = false;
} else { } else {
bool needs_refcounting_fixup = true; bool needs_refcounting_fixup = false;
needs_cxx_interception = (target_exception_style == CXX && (needs_refcounting_fixup || unw_info.hasHandler() needs_cxx_interception = (target_exception_style == CXX && (needs_refcounting_fixup || unw_info.hasHandler()
|| irstate->getExceptionStyle() == CAPI)); || irstate->getExceptionStyle() == CAPI));
} }
...@@ -487,6 +487,9 @@ private: ...@@ -487,6 +487,9 @@ private:
} else { } else {
llvm::CallInst* cs = getBuilder()->CreateCall(callee, args); llvm::CallInst* cs = getBuilder()->CreateCall(callee, args);
if (target_exception_style == CXX)
irstate->getRefcounts()->setMayThrow(cs);
if (target_exception_style == CAPI) if (target_exception_style == CAPI)
checkAndPropagateCapiException(unw_info, cs, capi_exc_value); checkAndPropagateCapiException(unw_info, cs, capi_exc_value);
...@@ -1035,7 +1038,8 @@ private: ...@@ -1035,7 +1038,8 @@ private:
auto inst = emitter.createCall(UnwindInfo::cantUnwind(), g.funcs.setFrameExcInfo, auto inst = emitter.createCall(UnwindInfo::cantUnwind(), g.funcs.setFrameExcInfo,
{ frame_info, converted_type->getValue(), converted_value->getValue(), { frame_info, converted_type->getValue(), converted_value->getValue(),
converted_traceback->getValue() }); converted_traceback->getValue() },
NOEXC);
emitter.refConsumed(converted_type->getValue(), inst); emitter.refConsumed(converted_type->getValue(), inst);
emitter.refConsumed(converted_value->getValue(), inst); emitter.refConsumed(converted_value->getValue(), inst);
emitter.refConsumed(converted_traceback->getValue(), inst); emitter.refConsumed(converted_traceback->getValue(), inst);
...@@ -3065,31 +3069,8 @@ public: ...@@ -3065,31 +3069,8 @@ public:
emitter.getBuilder()->SetInsertPoint(cxx_exc_dest); emitter.getBuilder()->SetInsertPoint(cxx_exc_dest);
llvm::Function* _personality_func = g.stdlib_module->getFunction("__gxx_personality_v0"); llvm::Value* exc_type, *exc_value, *exc_traceback;
assert(_personality_func); std::tie(exc_type, exc_value, exc_traceback) = createLandingpad(cxx_exc_dest);
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));
emitter.setType(exc_type, RefType::OWNED); emitter.setType(exc_type, RefType::OWNED);
emitter.setType(exc_value, RefType::OWNED); emitter.setType(exc_value, RefType::OWNED);
emitter.setType(exc_traceback, RefType::OWNED); emitter.setType(exc_traceback, RefType::OWNED);
...@@ -3101,23 +3082,24 @@ public: ...@@ -3101,23 +3082,24 @@ public:
new ConcreteCompilerVariable(UNKNOWN, exc_value), new ConcreteCompilerVariable(UNKNOWN, exc_value),
new ConcreteCompilerVariable(UNKNOWN, exc_traceback))); new ConcreteCompilerVariable(UNKNOWN, exc_traceback)));
builder->CreateBr(final_dest); emitter.getBuilder()->CreateBr(final_dest);
} else if (irstate->getExceptionStyle() == CAPI) { } 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_type, call_inst);
irstate->getRefcounts()->refConsumed(exc_value, call_inst); irstate->getRefcounts()->refConsumed(exc_value, call_inst);
irstate->getRefcounts()->refConsumed(exc_traceback, call_inst); irstate->getRefcounts()->refConsumed(exc_traceback, call_inst);
builder->CreateCall(g.funcs.deinitFrame, irstate->getFrameInfoVar()); emitter.getBuilder()->CreateCall(g.funcs.deinitFrame, irstate->getFrameInfoVar());
builder->CreateRet(getNullPtr(g.llvm_value_type_ptr)); emitter.getBuilder()->CreateRet(getNullPtr(g.llvm_value_type_ptr));
} else { } else {
// auto call_inst = emitter.createCall3(UnwindInfo(unw_info.current_stmt, NO_CXX_INTERCEPTION), // auto call_inst = emitter.createCall3(UnwindInfo(unw_info.current_stmt, NO_CXX_INTERCEPTION),
// 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.rawThrow, 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_type, call_inst);
irstate->getRefcounts()->refConsumed(exc_value, call_inst); irstate->getRefcounts()->refConsumed(exc_value, call_inst);
irstate->getRefcounts()->refConsumed(exc_traceback, call_inst); irstate->getRefcounts()->refConsumed(exc_traceback, call_inst);
builder->CreateUnreachable(); emitter.getBuilder()->CreateUnreachable();
} }
emitter.setCurrentBasicBlock(orig_block); emitter.setCurrentBasicBlock(orig_block);
...@@ -3135,6 +3117,37 @@ public: ...@@ -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, IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks,
CFGBlock* myblock, TypeAnalysis* types) { CFGBlock* myblock, TypeAnalysis* types) {
return new IRGeneratorImpl(irstate, entry_blocks, myblock, types); return new IRGeneratorImpl(irstate, entry_blocks, myblock, types);
......
...@@ -172,6 +172,8 @@ public: ...@@ -172,6 +172,8 @@ public:
virtual CFGBlock* getCFGBlock() = 0; virtual CFGBlock* getCFGBlock() = 0;
}; };
std::tuple<llvm::Value*, llvm::Value*, llvm::Value*> createLandingpad(llvm::BasicBlock*);
class IREmitter; class IREmitter;
class AST_Call; class AST_Call;
IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRGenerator* irgenerator = NULL); IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRGenerator* irgenerator = NULL);
......
This diff is collapsed.
...@@ -315,7 +315,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -315,7 +315,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(raise0_capi); GET(raise0_capi);
GET(raise3); GET(raise3);
GET(raise3_capi); GET(raise3_capi);
GET(rawThrow); GET(rawReraise);
GET(PyErr_Fetch); GET(PyErr_Fetch);
GET(PyErr_NormalizeException); GET(PyErr_NormalizeException);
GET(PyErr_Restore); GET(PyErr_Restore);
......
...@@ -51,7 +51,7 @@ struct GlobalFuncs { ...@@ -51,7 +51,7 @@ struct GlobalFuncs {
llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel; llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel;
llvm::Value* __cxa_end_catch; 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* PyErr_Fetch, *PyErr_NormalizeException, *PyErr_Restore, *caughtCapiException, *reraiseCapiExcAsCxx;
llvm::Value* deopt; llvm::Value* deopt;
llvm::Value* checkRefs; llvm::Value* checkRefs;
......
...@@ -282,8 +282,7 @@ extern "C" void reraiseCapiExcAsCxx() { ...@@ -282,8 +282,7 @@ extern "C" void reraiseCapiExcAsCxx() {
throw e; throw e;
} }
// XXX rename this extern "C" void rawReraise(Box* type, Box* value, Box* tb) {
extern "C" void rawThrow(Box* type, Box* value, Box* tb) {
startReraise(); startReraise();
throw ExcInfo(type, value, tb); throw ExcInfo(type, value, tb);
} }
......
...@@ -130,7 +130,7 @@ void force() { ...@@ -130,7 +130,7 @@ void force() {
FORCE(raise0_capi); FORCE(raise0_capi);
FORCE(raise3); FORCE(raise3);
FORCE(raise3_capi); FORCE(raise3_capi);
FORCE(rawThrow); FORCE(rawReraise);
FORCE(PyErr_Fetch); FORCE(PyErr_Fetch);
FORCE(PyErr_NormalizeException); FORCE(PyErr_NormalizeException);
FORCE(PyErr_Restore); FORCE(PyErr_Restore);
......
...@@ -37,7 +37,7 @@ extern "C" void raise0(ExcInfo* frame_exc_info) __attribute__((__noreturn__)); ...@@ -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 raise0_capi(ExcInfo* frame_exc_info) noexcept;
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__)); extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
extern "C" void raise3_capi(Box*, Box*, Box*) noexcept; 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 raiseExc(STOLEN(Box*) exc_obj) __attribute__((__noreturn__));
void _printStacktrace(); 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