mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-12 05:47:11 +03:00
Add @naked UDA
Adding the LLVM `naked` function attribute and disabling LDC's prologue/epilogue too.
This commit is contained in:
parent
f2c718d7a4
commit
c10cf86403
4 changed files with 69 additions and 13 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
31
tests/codegen/attr_naked.d
Normal file
31
tests/codegen/attr_naked.d
Normal 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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue