Skip to content

Commit 464a7ee

Browse files
authored
[CodeGen] Generalize trap emission after SP check fail (#109744)
Generalize and improve some target-specific code that emits traps after stack protector failure in SelectionDAG & GlobalIsel.
1 parent 4c25a53 commit 464a7ee

File tree

8 files changed

+179
-22
lines changed

8 files changed

+179
-22
lines changed

llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3913,16 +3913,11 @@ bool IRTranslator::emitSPDescriptorFailure(StackProtectorDescriptor &SPD,
39133913
return false;
39143914
}
39153915

3916-
// On PS4/PS5, the "return address" must still be within the calling
3917-
// function, even if it's at the very end, so emit an explicit TRAP here.
3918-
// WebAssembly needs an unreachable instruction after a non-returning call,
3919-
// because the function return type can be different from __stack_chk_fail's
3920-
// return type (void).
3921-
const TargetMachine &TM = MF->getTarget();
3922-
if (TM.getTargetTriple().isPS() || TM.getTargetTriple().isWasm()) {
3923-
LLVM_DEBUG(dbgs() << "Unhandled trap emission for stack protector fail\n");
3924-
return false;
3925-
}
3916+
// Emit a trap instruction if we are required to do so.
3917+
const TargetOptions &TargetOpts = TLI->getTargetMachine().Options;
3918+
if (TargetOpts.TrapUnreachable && !TargetOpts.NoTrapAfterNoreturn)
3919+
CurBuilder->buildInstr(TargetOpcode::G_TRAP);
3920+
39263921
return true;
39273922
}
39283923

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3183,15 +3183,10 @@ SelectionDAGBuilder::visitSPDescriptorFailure(StackProtectorDescriptor &SPD) {
31833183
SDValue Chain = TLI.makeLibCall(DAG, RTLIB::STACKPROTECTOR_CHECK_FAIL,
31843184
MVT::isVoid, {}, CallOptions, getCurSDLoc())
31853185
.second;
3186-
// On PS4/PS5, the "return address" must still be within the calling
3187-
// function, even if it's at the very end, so emit an explicit TRAP here.
3188-
// Passing 'true' for doesNotReturn above won't generate the trap for us.
3189-
if (TM.getTargetTriple().isPS())
3190-
Chain = DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, Chain);
3191-
// WebAssembly needs an unreachable instruction after a non-returning call,
3192-
// because the function return type can be different from __stack_chk_fail's
3193-
// return type (void).
3194-
if (TM.getTargetTriple().isWasm())
3186+
3187+
// Emit a trap instruction if we are required to do so.
3188+
const TargetOptions &TargetOpts = DAG.getTarget().Options;
3189+
if (TargetOpts.TrapUnreachable && !TargetOpts.NoTrapAfterNoreturn)
31953190
Chain = DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, Chain);
31963191

31973192
DAG.setRoot(Chain);

llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
133133
// WebAssembly type-checks instructions, but a noreturn function with a return
134134
// type that doesn't match the context will cause a check failure. So we lower
135135
// LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
136-
// 'unreachable' instructions which is meant for that case.
136+
// 'unreachable' instructions which is meant for that case. Formerly, we also
137+
// needed to add checks to SP failure emission in the instruction selection
138+
// backends, but this has since been tied to TrapUnreachable and is no longer
139+
// necessary.
137140
this->Options.TrapUnreachable = true;
138141
this->Options.NoTrapAfterNoreturn = false;
139142

llvm/lib/Target/X86/X86TargetMachine.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,10 @@ X86TargetMachine::X86TargetMachine(const Target &T, const Triple &TT,
242242
OL),
243243
TLOF(createTLOF(getTargetTriple())), IsJIT(JIT) {
244244
// On PS4/PS5, the "return address" of a 'noreturn' call must still be within
245-
// the calling function, and TrapUnreachable is an easy way to get that.
245+
// the calling function. Note that this also includes __stack_chk_fail,
246+
// so there was some target-specific logic in the instruction selectors
247+
// to handle that. That code has since been generalized, so the only thing
248+
// needed is to set TrapUnreachable here.
246249
if (TT.isPS() || TT.isOSBinFormatMachO()) {
247250
this->Options.TrapUnreachable = true;
248251
this->Options.NoTrapAfterNoreturn = TT.isOSBinFormatMachO();
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
; RUN: llc -mtriple=aarch64 -global-isel -stop-after=irtranslator -verify-machineinstrs \
3+
; RUN: -trap-unreachable=false -o - %s | FileCheck -check-prefix=NO_TRAP_UNREACHABLE %s
4+
; RUN: llc -mtriple=aarch64 -global-isel -stop-after=irtranslator -verify-machineinstrs \
5+
; RUN: -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck -check-prefix=NO_TRAP_UNREACHABLE %s
6+
; RUN: llc -mtriple=aarch64 -global-isel -stop-after=irtranslator -verify-machineinstrs \
7+
; RUN: -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck -check-prefix=TRAP_UNREACHABLE %s
8+
9+
;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
10+
11+
define void @test() nounwind ssp {
12+
; NO_TRAP_UNREACHABLE-LABEL: name: test
13+
; NO_TRAP_UNREACHABLE: bb.1.entry:
14+
; NO_TRAP_UNREACHABLE-NEXT: successors: %bb.2(0x7ffff800), %bb.3(0x00000800)
15+
; NO_TRAP_UNREACHABLE-NEXT: {{ $}}
16+
; NO_TRAP_UNREACHABLE-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.StackGuardSlot
17+
; NO_TRAP_UNREACHABLE-NEXT: [[LOAD_STACK_GUARD:%[0-9]+]]:gpr64sp(p0) = LOAD_STACK_GUARD :: (dereferenceable invariant load (p0) from @__stack_chk_guard)
18+
; NO_TRAP_UNREACHABLE-NEXT: [[LOAD_STACK_GUARD1:%[0-9]+]]:gpr64sp(p0) = LOAD_STACK_GUARD :: (dereferenceable invariant load (p0) from @__stack_chk_guard)
19+
; NO_TRAP_UNREACHABLE-NEXT: G_STORE [[LOAD_STACK_GUARD1]](p0), [[FRAME_INDEX]](p0) :: (volatile store (p0) into %stack.0.StackGuardSlot)
20+
; NO_TRAP_UNREACHABLE-NEXT: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1.buf
21+
; NO_TRAP_UNREACHABLE-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
22+
; NO_TRAP_UNREACHABLE-NEXT: $x0 = COPY [[FRAME_INDEX1]](p0)
23+
; NO_TRAP_UNREACHABLE-NEXT: BL @callee, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0, implicit-def $w0
24+
; NO_TRAP_UNREACHABLE-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
25+
; NO_TRAP_UNREACHABLE-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
26+
; NO_TRAP_UNREACHABLE-NEXT: [[FRAME_INDEX2:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.StackGuardSlot
27+
; NO_TRAP_UNREACHABLE-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX2]](p0) :: (volatile load (s64) from %stack.0.StackGuardSlot)
28+
; NO_TRAP_UNREACHABLE-NEXT: [[LOAD_STACK_GUARD2:%[0-9]+]]:gpr64sp(s64) = LOAD_STACK_GUARD :: (dereferenceable invariant load (p0) from @__stack_chk_guard)
29+
; NO_TRAP_UNREACHABLE-NEXT: [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(ne), [[LOAD_STACK_GUARD2]](s64), [[LOAD]]
30+
; NO_TRAP_UNREACHABLE-NEXT: G_BRCOND [[ICMP]](s1), %bb.3
31+
; NO_TRAP_UNREACHABLE-NEXT: G_BR %bb.2
32+
; NO_TRAP_UNREACHABLE-NEXT: {{ $}}
33+
; NO_TRAP_UNREACHABLE-NEXT: bb.3.entry:
34+
; NO_TRAP_UNREACHABLE-NEXT: successors:
35+
; NO_TRAP_UNREACHABLE-NEXT: {{ $}}
36+
; NO_TRAP_UNREACHABLE-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
37+
; NO_TRAP_UNREACHABLE-NEXT: BL &__stack_chk_fail, csr_aarch64_aapcs, implicit-def $lr, implicit $sp
38+
; NO_TRAP_UNREACHABLE-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
39+
; NO_TRAP_UNREACHABLE-NEXT: {{ $}}
40+
; NO_TRAP_UNREACHABLE-NEXT: bb.2.entry:
41+
; NO_TRAP_UNREACHABLE-NEXT: RET_ReallyLR
42+
;
43+
; TRAP_UNREACHABLE-LABEL: name: test
44+
; TRAP_UNREACHABLE: bb.1.entry:
45+
; TRAP_UNREACHABLE-NEXT: successors: %bb.2(0x7ffff800), %bb.3(0x00000800)
46+
; TRAP_UNREACHABLE-NEXT: {{ $}}
47+
; TRAP_UNREACHABLE-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.StackGuardSlot
48+
; TRAP_UNREACHABLE-NEXT: [[LOAD_STACK_GUARD:%[0-9]+]]:gpr64sp(p0) = LOAD_STACK_GUARD :: (dereferenceable invariant load (p0) from @__stack_chk_guard)
49+
; TRAP_UNREACHABLE-NEXT: [[LOAD_STACK_GUARD1:%[0-9]+]]:gpr64sp(p0) = LOAD_STACK_GUARD :: (dereferenceable invariant load (p0) from @__stack_chk_guard)
50+
; TRAP_UNREACHABLE-NEXT: G_STORE [[LOAD_STACK_GUARD1]](p0), [[FRAME_INDEX]](p0) :: (volatile store (p0) into %stack.0.StackGuardSlot)
51+
; TRAP_UNREACHABLE-NEXT: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1.buf
52+
; TRAP_UNREACHABLE-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
53+
; TRAP_UNREACHABLE-NEXT: $x0 = COPY [[FRAME_INDEX1]](p0)
54+
; TRAP_UNREACHABLE-NEXT: BL @callee, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0, implicit-def $w0
55+
; TRAP_UNREACHABLE-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
56+
; TRAP_UNREACHABLE-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
57+
; TRAP_UNREACHABLE-NEXT: [[FRAME_INDEX2:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.StackGuardSlot
58+
; TRAP_UNREACHABLE-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX2]](p0) :: (volatile load (s64) from %stack.0.StackGuardSlot)
59+
; TRAP_UNREACHABLE-NEXT: [[LOAD_STACK_GUARD2:%[0-9]+]]:gpr64sp(s64) = LOAD_STACK_GUARD :: (dereferenceable invariant load (p0) from @__stack_chk_guard)
60+
; TRAP_UNREACHABLE-NEXT: [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(ne), [[LOAD_STACK_GUARD2]](s64), [[LOAD]]
61+
; TRAP_UNREACHABLE-NEXT: G_BRCOND [[ICMP]](s1), %bb.3
62+
; TRAP_UNREACHABLE-NEXT: G_BR %bb.2
63+
; TRAP_UNREACHABLE-NEXT: {{ $}}
64+
; TRAP_UNREACHABLE-NEXT: bb.3.entry:
65+
; TRAP_UNREACHABLE-NEXT: successors:
66+
; TRAP_UNREACHABLE-NEXT: {{ $}}
67+
; TRAP_UNREACHABLE-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
68+
; TRAP_UNREACHABLE-NEXT: BL &__stack_chk_fail, csr_aarch64_aapcs, implicit-def $lr, implicit $sp
69+
; TRAP_UNREACHABLE-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
70+
; TRAP_UNREACHABLE-NEXT: G_TRAP
71+
; TRAP_UNREACHABLE-NEXT: {{ $}}
72+
; TRAP_UNREACHABLE-NEXT: bb.2.entry:
73+
; TRAP_UNREACHABLE-NEXT: RET_ReallyLR
74+
entry:
75+
%buf = alloca [8 x i8]
76+
%result = call i32(ptr) @callee(ptr %buf) nounwind
77+
ret void
78+
}
79+
80+
declare i32 @callee(ptr) nounwind
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
2+
3+
; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
4+
; RUN: -trap-unreachable=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
5+
; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
6+
; RUN: -trap-unreachable -no-trap-after-noreturn -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
7+
; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
8+
; RUN: -trap-unreachable -no-trap-after-noreturn=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,TRAP_UNREACHABLE %s
9+
10+
;; Make sure FastISel doesn't break anything.
11+
; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs -print-after=finalize-isel \
12+
; RUN: -trap-unreachable=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
13+
; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs -print-after=finalize-isel \
14+
; RUN: -trap-unreachable -no-trap-after-noreturn -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
15+
; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs -print-after=finalize-isel \
16+
; RUN: -trap-unreachable -no-trap-after-noreturn=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,TRAP_UNREACHABLE %s
17+
18+
; CHECK-LABEL: Machine code for function test
19+
; CHECK: bb.0.entry:
20+
; CHECK: BL {{.}}__stack_chk_fail
21+
; CHECK-NEXT: ADJCALLSTACKUP
22+
; TRAP_UNREACHABLE-NEXT: BRK 1
23+
; NO_TRAP_UNREACHABLE-NOT: BRK 1
24+
; NO_TRAP_UNREACHABLE-EMPTY:
25+
26+
define void @test() nounwind ssp {
27+
entry:
28+
%buf = alloca [8 x i8]
29+
%result = call i32(ptr) @callee(ptr %buf) nounwind
30+
ret void
31+
}
32+
33+
declare i32 @callee(ptr) nounwind
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
2+
3+
; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
4+
; RUN: -trap-unreachable=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
5+
; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
6+
; RUN: -trap-unreachable -no-trap-after-noreturn -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
7+
; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
8+
; RUN: -trap-unreachable -no-trap-after-noreturn=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,TRAP_UNREACHABLE %s
9+
10+
; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
11+
; RUN: -trap-unreachable=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
12+
; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
13+
; RUN: -trap-unreachable -no-trap-after-noreturn -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
14+
; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
15+
; RUN: -trap-unreachable -no-trap-after-noreturn=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,TRAP_UNREACHABLE %s
16+
17+
;; Make sure FastISel doesn't break anything.
18+
; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
19+
; RUN: -trap-unreachable=false --o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
20+
; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
21+
; RUN: -trap-unreachable -no-trap-after-noreturn -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,NO_TRAP_UNREACHABLE %s
22+
; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs -print-after=finalize-isel \
23+
; RUN: -trap-unreachable -no-trap-after-noreturn=false -o /dev/null 2>&1 %s | FileCheck --check-prefixes=CHECK,TRAP_UNREACHABLE %s
24+
25+
; CHECK-LABEL: Machine code for function test
26+
; CHECK: bb.0.entry:
27+
; CHECK: CALL64{{.*}}__stack_chk_fail
28+
; CHECK-NEXT: ADJCALLSTACKUP64
29+
; TRAP_UNREACHABLE-NEXT: TRAP
30+
; NO_TRAP_UNREACHABLE-NOT: TRAP
31+
; NO_TRAP_UNREACHABLE-EMPTY:
32+
33+
define void @test() nounwind ssp {
34+
entry:
35+
%buf = alloca [8 x i8]
36+
%result = call i32(ptr) @callee(ptr %buf) nounwind
37+
ret void
38+
}
39+
40+
declare i32 @callee(ptr) nounwind

llvm/test/CodeGen/X86/unreachable-trap.ll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
; RUN: llc -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK
22
; RUN: llc -o - %s -mtriple=x86_64-windows-msvc | FileCheck %s --check-prefixes=CHECK
3-
; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
43
; RUN: llc -o - %s -mtriple=x86_64-apple-darwin | FileCheck %s --check-prefixes=CHECK,NO_TRAP_AFTER_NORETURN
4+
5+
; On PS4/PS5, always emit trap instructions regardless of of trap-unreachable or no-trap-after-noreturn.
6+
; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
7+
; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
8+
; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
9+
; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
10+
; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable -no-trap-after-noreturn=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
11+
; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable -no-trap-after-noreturn=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
12+
513
; RUN: llc --trap-unreachable -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
614
; RUN: llc --trap-unreachable -global-isel -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
715
; RUN: llc --trap-unreachable -fast-isel -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN

0 commit comments

Comments
 (0)