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);

View file

@ -222,10 +222,16 @@ void applyAttrLLVMAttr(StructLiteralExp *sle, llvm::Function *func) {
const auto kind = llvm::getAttrKindFromName(key);
if (kind != llvm::Attribute::None) {
func->addFnAttr(kind);
return;
}
#else
// no getAttrKindFromName(); just detect `naked` for now
if (key == "naked") {
func->addFnAttr(llvm::Attribute::Naked);
}
#endif
else {
func->addFnAttr(key);
}
} else {
func->addFnAttr(key, value);
}

@ -1 +1 @@
Subproject commit 6378c56b2f114866f2c2efe3b78c086965e1729d
Subproject commit 4cc2de28e47beb24f95830371ca8b349042a4beb

View file

@ -0,0 +1,31 @@
// REQUIRES: target_X86
// RUN: %ldc -mtriple=x86_64-pc-linux-gnu -O -output-s -of=%t.s %s && FileCheck %s < %t.s
import ldc.attributes;
import ldc.llvmasm;
// Without -O, LLVM (6) dumps the 2 params to stack for Linux x64 (but doesn't for Win64).
// Clang is no different though.
// CHECK: withParams:
extern(C) int withParams(int param1, void* param2) @naked
{
// CHECK-NEXT: .cfi_startproc
// CHECK-NEXT: #APP
// CHECK-NEXT: xorl %eax, %eax
// CHECK-NEXT: #NO_APP
// CHECK-NEXT: retq
return __asm!int("xor %eax, %eax", "={eax}");
}
// CHECK: _D10attr_naked8noReturnFZv:
void noReturn() @naked
{
// CHECK-NEXT: .cfi_startproc
// CHECK-NEXT: #APP
// CHECK-NEXT: jmpq *%rax
// CHECK-NEXT: #NO_APP
__asm("jmp *%rax", "");
// CHECK-NOT: retq
// CHECK: .cfi_endproc
}