Add @naked UDA

Adding the LLVM `naked` function attribute and disabling LDC's
prologue/epilogue too.
This commit is contained in:
Martin Kinkelin 2018-07-12 00:01:44 +02:00
parent f2c718d7a4
commit c10cf86403
4 changed files with 69 additions and 13 deletions

View file

@ -827,6 +827,18 @@ void emitDMDStyleFunctionTrace(IRState &irs, FuncDeclaration *fd,
}
}
// If the specified block is trivially unreachable, erases it and returns true.
// This is a common case because it happens when 'return' is the last statement
// in a function.
bool eraseDummyAfterReturnBB(llvm::BasicBlock *bb) {
if (pred_begin(bb) == pred_end(bb) &&
bb != &bb->getParent()->getEntryBlock()) {
bb->eraseFromParent();
return true;
}
return false;
}
} // anonymous namespace
void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
@ -1034,6 +1046,9 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
llvm::BasicBlock::Create(gIR->context(), "", func);
gIR->scopes.push_back(IRScope(beginbb));
SCOPE_EXIT {
gIR->scopes.pop_back();
};
// Set the FastMath options for this function scope.
#if LDC_LLVM_VER >= 308
@ -1042,6 +1057,18 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
gIR->scopes.back().builder.SetFastMathFlags(irFunc->FMF);
#endif
// @naked: emit body and return, no prologue/epilogue
if (func->hasFnAttribute(llvm::Attribute::Naked)) {
Statement_toIR(fd->fbody, gIR);
const bool wasDummy = eraseDummyAfterReturnBB(gIR->scopebb());
if (!wasDummy && !gIR->scopereturned()) {
// this is what clang does to prevent LLVM complaining about
// non-terminated function
gIR->ir->CreateUnreachable();
}
return;
}
// create alloca point
// this gets erased when the function is complete, so alignment etc does not
// matter at all
@ -1163,14 +1190,8 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
funcGen.scopes.popCleanups(0);
}
llvm::BasicBlock *bb = gIR->scopebb();
if (pred_begin(bb) == pred_end(bb) &&
bb != &bb->getParent()->getEntryBlock()) {
// This block is trivially unreachable, so just delete it.
// (This is a common case because it happens when 'return'
// is the last statement in a function)
bb->eraseFromParent();
} else if (!gIR->scopereturned()) {
const bool wasDummy = eraseDummyAfterReturnBB(gIR->scopebb());
if (!wasDummy && !gIR->scopereturned()) {
// llvm requires all basic blocks to end with a TerminatorInst but DMD does
// not put a return statement in automatically, so we do it here.
@ -1201,8 +1222,6 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
allocaPoint = nullptr;
}
gIR->scopes.pop_back();
if (gIR->dcomputetarget && hasKernelAttr(fd)) {
auto fn = gIR->module.getFunction(fd->mangleString);
gIR->dcomputetarget->addKernelMetadata(fd, fn);