Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1822,10 +1822,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 @@ -2372,12 +2368,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/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -3122,6 +3122,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; @@ -1008,7 +1011,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(); @@ -1956,6 +1960,47 @@ } } +bool CodeGenFunction::isNakedFunction() const { + return CurCodeDecl && CurCodeDecl->hasAttr(); +} + +void CodeGenFunction::cleanupNakedFunction() { + llvm::SmallPtrSet InstrsToRemove; + llvm::BasicBlock *EntryBB = AllocaInsertPt->getParent(); + + // Erase all allocas and their users. + for (auto I = EntryBB->begin(); &*I != &*AllocaInsertPt; ++I) + if (auto Alloca = dyn_cast(&*I)) + InstrsToRemove.insert(Alloca); + + while (!InstrsToRemove.empty()) { + auto *I = *InstrsToRemove.begin(); + + for (auto *U : I->users()) + InstrsToRemove.insert(cast(U)); + + I->replaceAllUsesWith(llvm::UndefValue::get(I->getType())); + I->eraseFromParent(); + InstrsToRemove.erase(I); + } + + // Erase all blocks except the entry. + for (auto BB = CurFn->begin(); BB != CurFn->end();) { + if (&*BB == EntryBB) + ++BB; + else + BB++->eraseFromParent(); + } + + // Erase terminator of the entry block. + if (auto *T = EntryBB->getTerminator()) + T->eraseFromParent(); + + // Insert an unreachable at the end of the entry block. + Builder.SetInsertPoint(EntryBB, EntryBB->end()); + Builder.CreateUnreachable(); +} + void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) { if (!CGM.getCodeGenOpts().SanitizeStats) return; 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,55 @@ +// RUN: %clang_cc1 -triple=x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s | FileCheck %s + +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. +int __attribute__((naked)) foo2(int a) { + __asm__ volatile("retq"); +} + +// 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: } + +// CHECK: define i32 @_Z4foo2i(i32 %a) [[ATTR2]] +// CHECK-NEXT: entry: +// CHECK-NEXT: call void asm sideeffect "retq +// CHECK-NEXT: unreachable +// CHECK-NEXT: } + +// CHECK: attributes [[ATTR1]] = { {{.*}}naked{{.*}} } +// CHECK: attributes [[ATTR2]] = { {{.*}}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: }