Index: lib/CodeGen/TargetFrameLoweringImpl.cpp =================================================================== --- lib/CodeGen/TargetFrameLoweringImpl.cpp +++ lib/CodeGen/TargetFrameLoweringImpl.cpp @@ -85,6 +85,13 @@ if (MF.getFunction().hasFnAttribute(Attribute::Naked)) return; + // Noreturn+nounwind functions never restore CSR, so no saves are needed. + // Purely noreturn functions may still return through throws, so those must + // save CSR for caller exception handlers. + if (MF.getFunction().hasFnAttribute(Attribute::NoReturn) && + MF.getFunction().hasFnAttribute(Attribute::NoUnwind)) + return; + // Functions which call __builtin_unwind_init get all their registers saved. bool CallsUnwindInit = MF.callsUnwindInit(); const MachineRegisterInfo &MRI = MF.getRegInfo(); Index: test/CodeGen/AArch64/arm64-shrink-wrapping.ll =================================================================== --- test/CodeGen/AArch64/arm64-shrink-wrapping.ll +++ test/CodeGen/AArch64/arm64-shrink-wrapping.ll @@ -281,7 +281,7 @@ ; Shift second argument by one and store into returned register. ; ENABLE: lsl w0, w1, #1 ; ENABLE: ret -define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 { +define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) nounwind { entry: %tobool = icmp eq i32 %cond, 0 br i1 %tobool, label %if.else, label %if.then @@ -355,7 +355,7 @@ ; CHECK-NEXT: lsl w0, w1, #1 ; DISABLE-NEXT: add sp, sp, #16 ; CHECK-NEXT: ret -define i32 @variadicFunc(i32 %cond, i32 %count, ...) #0 { +define i32 @variadicFunc(i32 %cond, i32 %count, ...) nounwind { entry: %ap = alloca i8*, align 8 %tobool = icmp eq i32 %cond, 0 Index: test/CodeGen/ARM/arm-shrink-wrapping.ll =================================================================== --- test/CodeGen/ARM/arm-shrink-wrapping.ll +++ test/CodeGen/ARM/arm-shrink-wrapping.ll @@ -327,7 +327,7 @@ ; DISABLE-NEXT: pop {r4, r7, pc} ; ; ENABLE-NEXT: bx lr -define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) "no-frame-pointer-elim"="true" #0 { +define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) "no-frame-pointer-elim"="true" nounwind { entry: %tobool = icmp eq i32 %cond, 0 br i1 %tobool, label %if.else, label %if.then Index: test/CodeGen/ARM/noreturn-csr-skip.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/noreturn-csr-skip.ll @@ -0,0 +1,48 @@ +; RUN: llc %s -o - | FileCheck %s --check-prefix=CHECK + +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" +target triple = "thumbv7m-none-eabi" + +; CHECK-LABEL: ret +; +; This function may return. Any CSR must be saved. +; CHECK: push {r4, lr} +; CHECK-NEXT: sub sp, #4 +; CHECK: add sp, #4 +; CHECK-NEXT: pop {r4, pc} +define internal void @ret() nounwind { +start: + %p = alloca i32 + call void asm sideeffect "", "~{r4}"() + ret void +} + +; CHECK-LABEL: throw +; +; This function may return through throws. Any CSR must be saved. +; CHECK: push {r4, lr} +; CHECK-NEXT: sub sp, #4 +; CHECK: add sp, #4 +; CHECK-NEXT: pop {r4, pc} +define internal void @throw() noreturn { +start: + %p = alloca i32 + call void asm sideeffect "", "~{r4}"() + ret void +} + +; CHECK-LABEL: noret +; +; This function does not return. We need not save any CSR, but +; other stack adjustments in the prologue are still necessary. +; CHECK-NOT: push +; CHECK: sub sp, #4 +define internal void @noret() noreturn nounwind { +start: + %p = alloca i32 + br label %bb1 + +bb1: + call void asm sideeffect "", "~{r4}"() + br label %bb1 +} Index: test/CodeGen/PowerPC/ppc-shrink-wrapping.ll =================================================================== --- test/CodeGen/PowerPC/ppc-shrink-wrapping.ll +++ test/CodeGen/PowerPC/ppc-shrink-wrapping.ll @@ -328,7 +328,7 @@ ; Shift second argument by one and store into returned register. ; ENABLE: slwi 3, 4, 1 ; ENABLE-NEXT: blr -define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 { +define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) nounwind { entry: %tobool = icmp eq i32 %cond, 0 br i1 %tobool, label %if.else, label %if.then Index: test/CodeGen/Thumb/thumb-shrink-wrapping.ll =================================================================== --- test/CodeGen/Thumb/thumb-shrink-wrapping.ll +++ test/CodeGen/Thumb/thumb-shrink-wrapping.ll @@ -374,7 +374,7 @@ ; ; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end ; ENABLE-NEXT: bx lr -define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 { +define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) nounwind { entry: %tobool = icmp eq i32 %cond, 0 br i1 %tobool, label %if.else, label %if.then Index: test/CodeGen/X86/2010-02-19-TailCallRetAddrBug.ll =================================================================== --- test/CodeGen/X86/2010-02-19-TailCallRetAddrBug.ll +++ test/CodeGen/X86/2010-02-19-TailCallRetAddrBug.ll @@ -17,10 +17,10 @@ %tupl = type [9 x i32] -declare fastcc void @l297(i32 %r10, i32 %r9, i32 %r8, i32 %r7, i32 %r6, i32 %r5, i32 %r3, i32 %r2) noreturn nounwind -declare fastcc void @l298(i32 %r10, i32 %r9, i32 %r4) noreturn nounwind +declare fastcc void @l297(i32 %r10, i32 %r9, i32 %r8, i32 %r7, i32 %r6, i32 %r5, i32 %r3, i32 %r2) nounwind +declare fastcc void @l298(i32 %r10, i32 %r9, i32 %r4) nounwind -define fastcc void @l186(%tupl* %r1) noreturn nounwind { +define fastcc void @l186(%tupl* %r1) nounwind { entry: %ptr1 = getelementptr %tupl, %tupl* %r1, i32 0, i32 0 %r2 = load i32, i32* %ptr1 @@ -44,10 +44,10 @@ br i1 %cond, label %true, label %false true: - tail call fastcc void @l297(i32 %r10, i32 %r9, i32 %r8, i32 %r7, i32 %r6, i32 %r5, i32 %r3, i32 %r2) noreturn nounwind + tail call fastcc void @l297(i32 %r10, i32 %r9, i32 %r8, i32 %r7, i32 %r6, i32 %r5, i32 %r3, i32 %r2) nounwind ret void false: - tail call fastcc void @l298(i32 %r10, i32 %r9, i32 %r4) noreturn nounwind + tail call fastcc void @l298(i32 %r10, i32 %r9, i32 %r4) nounwind ret void } Index: test/CodeGen/X86/x86-shrink-wrapping.ll =================================================================== --- test/CodeGen/X86/x86-shrink-wrapping.ll +++ test/CodeGen/X86/x86-shrink-wrapping.ll @@ -314,7 +314,7 @@ ; ENABLE: addl %esi, %esi ; ENABLE-NEXT: movl %esi, %eax ; ENABLE-NEXT: retq -define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 { +define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) nounwind { entry: %tobool = icmp eq i32 %cond, 0 br i1 %tobool, label %if.else, label %if.then