Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1980,10 +1980,6 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::Function *Fn, const FunctionArgList &Args) { - if (CurCodeDecl && CurCodeDecl->hasAttr()) - // Naked functions don't have prologues. - return; - // If this is an implicit-return-zero function, go ahead and // initialize the return value. TODO: it might be nice to have // a more general mechanism for this that didn't require synthesized @@ -2553,12 +2549,6 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc, SourceLocation EndLoc) { - if (CurCodeDecl && CurCodeDecl->hasAttr()) { - // Naked functions don't have epilogues. - Builder.CreateUnreachable(); - return; - } - // Functions with no result always return void. if (!ReturnValue.isValid()) { Builder.CreateRetVoid(); Index: lib/CodeGen/CGStmt.cpp =================================================================== --- lib/CodeGen/CGStmt.cpp +++ lib/CodeGen/CGStmt.cpp @@ -1887,9 +1887,10 @@ } } - // If this is a Microsoft-style asm blob, store the return registers (EAX:EDX) - // to the return value slot. Only do this when returning in registers. - if (isa(&S)) { + // If this is a Microsoft-style asm blob that is not naked, store the return + // registers (EAX:EDX) to the return value slot. Only do this when returning + // in registers. + if (isa(&S) && !isNakedFunction()) { const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo(); if (RetAI.isDirect() || RetAI.isExtend()) { // Make a fake lvalue for the return value slot. Index: lib/CodeGen/CGVTables.cpp =================================================================== --- lib/CodeGen/CGVTables.cpp +++ lib/CodeGen/CGVTables.cpp @@ -467,6 +467,10 @@ CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn); + // Remove attribute Naked that was passed on to the thunk. + if (GD.getDecl()->hasAttr()) + ThunkFn->removeFnAttr(llvm::Attribute::Naked); + if (ThunkFn->isVarArg()) { // Varargs thunks are special; we can't just generate a call because // we can't copy the varargs. Our implementation is rather Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -3132,6 +3132,13 @@ llvm::Value *emitBuiltinObjectSize(const Expr *E, unsigned Type, llvm::IntegerType *ResType); + /// Return true if CurCodeDecl has attribute Naked. + bool isNakedFunction() const; + + /// Clean up naked functions removing allocas and their users and all blocks + /// except the entry. + void cleanupNakedFunction(); + public: #ifndef NDEBUG // Determine whether the given argument is an Objective-C method Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -355,6 +355,9 @@ CGBuilderTy(*this, AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs); } + if (isNakedFunction()) + cleanupNakedFunction(); + // Remove the AllocaInsertPt instruction, which is just a convenience for us. llvm::Instruction *Ptr = AllocaInsertPt; AllocaInsertPt = nullptr; @@ -1011,7 +1014,8 @@ // If the '}' that terminates a function is reached, and the value of the // function call is used by the caller, the behavior is undefined. if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() && !SawAsmBlock && - !FD->getReturnType()->isVoidType() && Builder.GetInsertBlock()) { + !FD->getReturnType()->isVoidType() && Builder.GetInsertBlock() && + !isNakedFunction()) { if (SanOpts.has(SanitizerKind::Return)) { SanitizerScope SanScope(this); llvm::Value *IsFalse = Builder.getFalse(); @@ -1967,3 +1971,42 @@ IRB.SetCurrentDebugLocation(Builder.getCurrentDebugLocation()); CGM.getSanStats().create(IRB, SSK); } + +bool CodeGenFunction::isNakedFunction() const { + return CurCodeDecl && CurCodeDecl->hasAttr(); +} + +void CodeGenFunction::cleanupNakedFunction() { + llvm::BasicBlock *EntryBB = &CurFn->getEntryBlock(); + llvm::SmallPtrSet InstrsToKeep; + + // Erase all instructions except inline-asm instructions and AllocaInsertPt. + for (auto BI = CurFn->begin(), BE = CurFn->end(); BI != BE; ++BI) + for (auto I = BI->begin(), E = BI->end(); I != E; ++I) { + auto *C = dyn_cast(&*I); + + if ((C && C->isInlineAsm()) || &*I == &*AllocaInsertPt) { + InstrsToKeep.insert(&*I); + continue; + } + + I->dropAllReferences(); + } + + for (auto BI = CurFn->begin(), BE = CurFn->end(); BI != BE;) { + if (&*BI == EntryBB) { + for (auto I = BI->begin(), E = BI->end(); I != E;) { + if (!InstrsToKeep.count(&*I)) + I = I->eraseFromParent(); + else + ++I; + } + ++BI; + } else + BI = BI->eraseFromParent(); + } + + // Insert an unreachable at the end of the entry block. + Builder.SetInsertPoint(EntryBB, EntryBB->end()); + Builder.CreateUnreachable(); +} Index: test/CodeGen/attr-naked.c =================================================================== --- test/CodeGen/attr-naked.c +++ test/CodeGen/attr-naked.c @@ -17,7 +17,7 @@ // Make sure not to generate prolog or epilog for naked functions. __attribute((naked)) void t3(int x) { -// CHECK: define void @t3(i32) +// CHECK: define void @t3(i32 %x) // CHECK-NOT: alloca // CHECK-NOT: store // CHECK: unreachable Index: test/CodeGenCXX/attr-naked.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/attr-naked.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -triple=x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s | FileCheck %s +// REQUIRES: asserts + +// CHECK: define internal i32 @"_ZZ4foo1iP6Class1ENK3$_0clEv"(%class.anon* %this) [[ATTR1:#[0-9]]] +// CHECK-NEXT: entry: +// CHECK-NEXT: call void asm sideeffect "retq +// CHECK-NEXT: unreachable +// CHECK-NEXT: } + +// CHECK: define linkonce_odr i32 @_ZN6Class12m2Ev(%class.Class1* %this) [[ATTR2:#[0-9]]] +// CHECK-NEXT: entry: +// CHECK-NEXT: call void asm sideeffect "retq +// CHECK-NEXT: unreachable +// CHECK-NEXT: } + +// CHECK: define linkonce_odr void @_ZN6Class12m1Ev(%class.Class1* %this) [[ATTR2]] +// CHECK-NEXT: entry: +// CHECK-NEXT: call void asm sideeffect "retq +// CHECK-NEXT: unreachable +// CHECK-NEXT: } + +class Class1 { +public: + void __attribute__((naked)) m1() { __asm__ volatile("retq"); } + int __attribute__((naked)) m2() { __asm__ volatile("retq"); } +}; + +int foo1(int a, Class1 *c1) { + auto Fn = []() __attribute__((naked))->int { + __asm__ volatile("retq"); + }; + + if (a < 0) + return Fn(); + + if (a > 0) + return c1->m2(); + + c1->m1(); + return 1; +} + +// Check for the absence of llvm.trap. + +// CHECK: define i32 @_Z4foo2i(i32 %a) [[ATTR2]] +// CHECK-NEXT: entry: +// CHECK-NEXT: call void asm sideeffect "retq +// CHECK-NEXT: unreachable +// CHECK-NEXT: } + +int __attribute__((naked)) foo2(int a) { + __asm__ volatile("retq"); +} + +// Make sure attaching "naked" to D0::m1 doesn't remove the thunk. + +// CHECK: define linkonce_odr void @_ZThn8_N2D02m1Ev(%struct.D0* %this) unnamed_addr [[ATTR3:#[0-9]]] + +struct B0 { + virtual void m1(); +}; + +struct B1 { + virtual void m1(); +}; + +struct D0 : B0, B1 { + void __attribute__((naked)) m1() { __asm__ volatile("retq"); } +}; + +void foo3() { + D0 d0; + B1 *b1 = &d0; + b1->m1(); +} + +// CHECK: attributes [[ATTR1]] = { {{.*}}naked{{.*}} } +// CHECK: attributes [[ATTR2]] = { {{.*}}naked{{.*}} } +// CHECK-NOT: attributes [[ATTR3]] = { {{.*}}naked{{.*}} } Index: test/CodeGenCXX/ms-inline-asm-return.cpp =================================================================== --- test/CodeGenCXX/ms-inline-asm-return.cpp +++ test/CodeGenCXX/ms-inline-asm-return.cpp @@ -1,5 +1,5 @@ // REQUIRES: x86-registered-target -// RUN: %clang_cc1 %s -triple i686-pc-windows-msvc -emit-llvm -o - -fasm-blocks | FileCheck %s +// RUN: %clang_cc1 %s -triple i686-pc-windows-msvc -emit-llvm -o - -fasm-blocks -fms-compatibility | FileCheck %s // Check that we take EAX or EAX:EDX and return it from these functions for MSVC // compatibility. @@ -98,3 +98,17 @@ // CHECK-LABEL: define i32 @main() // CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "xor eax, eax", "={eax},{{.*}}" // CHECK: ret i32 %[[r]] + +// Don't set the return value if the function is marked as naked. +__declspec(naked) int nakedFunc(int a, int b) +{ + __asm { + ret + } +} + +// CHECK: define i32 @{{.*}}nakedFunc +// CHECK-NEXT: entry: +// CHECK-NEXT: call void asm sideeffect inteldialect "ret +// CHECK-NEXT: unreachable +// CHECK-NEXT: }