[llvm] [CodeGen] Generalize trap emission after SP check fail (PR #109744)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 24 20:03:51 PDT 2024
https://github.com/duk-37 updated https://github.com/llvm/llvm-project/pull/109744
>From 8f5a1e7336bd793307267cb5b882555f8ae067b8 Mon Sep 17 00:00:00 2001
From: duk <37 at cmail.nu>
Date: Tue, 24 Sep 2024 21:22:46 -0400
Subject: [PATCH] [CodeGen] Generalize trap instruction emission after SP check
fail
Generalize some target-specific code that emits traps after stack protector failure in SelectionDAG/GlobalIsel and add some tests.
---
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 15 +++----
.../SelectionDAG/SelectionDAGBuilder.cpp | 13 ++----
...slator-stack-protector-trap-unreachable.ll | 28 ++++++++++++
.../stack-protector-trap-unreachable.ll | 36 ++++++++++++++++
.../X86/stack-protector-trap-unreachable.ll | 43 +++++++++++++++++++
llvm/test/CodeGen/X86/unreachable-trap.ll | 10 ++++-
6 files changed, 125 insertions(+), 20 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-trap-unreachable.ll
create mode 100644 llvm/test/CodeGen/AArch64/stack-protector-trap-unreachable.ll
create mode 100644 llvm/test/CodeGen/X86/stack-protector-trap-unreachable.ll
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 8e860a1f740295..8486d9a1477eb6 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -3807,16 +3807,11 @@ bool IRTranslator::emitSPDescriptorFailure(StackProtectorDescriptor &SPD,
return false;
}
- // On PS4/PS5, the "return address" must still be within the calling
- // function, even if it's at the very end, so emit an explicit TRAP here.
- // WebAssembly needs an unreachable instruction after a non-returning call,
- // because the function return type can be different from __stack_chk_fail's
- // return type (void).
- const TargetMachine &TM = MF->getTarget();
- if (TM.getTargetTriple().isPS() || TM.getTargetTriple().isWasm()) {
- LLVM_DEBUG(dbgs() << "Unhandled trap emission for stack protector fail\n");
- return false;
- }
+ // Emit a trap instruction if we are required to do so.
+ const TargetOptions &TargetOpts = TLI->getTargetMachine().Options;
+ if (TargetOpts.TrapUnreachable && !TargetOpts.NoTrapAfterNoreturn)
+ CurBuilder->buildInstr(TargetOpcode::G_TRAP);
+
return true;
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 25213f587116d5..5004756c0ab9c1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3183,15 +3183,10 @@ SelectionDAGBuilder::visitSPDescriptorFailure(StackProtectorDescriptor &SPD) {
SDValue Chain = TLI.makeLibCall(DAG, RTLIB::STACKPROTECTOR_CHECK_FAIL,
MVT::isVoid, {}, CallOptions, getCurSDLoc())
.second;
- // On PS4/PS5, the "return address" must still be within the calling
- // function, even if it's at the very end, so emit an explicit TRAP here.
- // Passing 'true' for doesNotReturn above won't generate the trap for us.
- if (TM.getTargetTriple().isPS())
- Chain = DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, Chain);
- // WebAssembly needs an unreachable instruction after a non-returning call,
- // because the function return type can be different from __stack_chk_fail's
- // return type (void).
- if (TM.getTargetTriple().isWasm())
+
+ // Emit a trap instruction if we are required to do so.
+ const TargetOptions &TargetOpts = DAG.getTarget().Options;
+ if (TargetOpts.TrapUnreachable && !TargetOpts.NoTrapAfterNoreturn)
Chain = DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, Chain);
DAG.setRoot(Chain);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-trap-unreachable.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-trap-unreachable.ll
new file mode 100644
index 00000000000000..23cd168fd48e3e
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-trap-unreachable.ll
@@ -0,0 +1,28 @@
+; NOTE: Do not autogenerate, we'd lose the .Lfunc_end0 -NEXT checks otherwise.
+;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
+
+; RUN: llc -mtriple=aarch64 -global-isel -verify-machineinstrs \
+; RUN: -trap-unreachable=false -o - %s | FileCheck -check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -global-isel -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck -check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -global-isel -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck -check-prefix=TRAP_UNREACHABLE %s
+
+define void @test() nounwind ssp {
+; NO_TRAP_UNREACHABLE-LABEL: test:
+; NO_TRAP_UNREACHABLE: bl __stack_chk_fail
+; NO_TRAP_UNREACHABLE-NOT: brk #0x1
+; NO_TRAP_UNREACHABLE-NEXT: .Lfunc_end0
+;
+; TRAP_UNREACHABLE-LABEL: test:
+; TRAP_UNREACHABLE: bl __stack_chk_fail
+; TRAP_UNREACHABLE-NEXT: brk #0x1
+; TRAP_UNREACHABLE-NEXT: .Lfunc_end0
+
+entry:
+ %buf = alloca [8 x i8]
+ %2 = call i32(ptr) @callee(ptr %buf) nounwind
+ ret void
+}
+
+declare i32 @callee(ptr) nounwind
diff --git a/llvm/test/CodeGen/AArch64/stack-protector-trap-unreachable.ll b/llvm/test/CodeGen/AArch64/stack-protector-trap-unreachable.ll
new file mode 100644
index 00000000000000..0aeb962f7c3e13
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/stack-protector-trap-unreachable.ll
@@ -0,0 +1,36 @@
+; NOTE: Do not autogenerate, we'd lose the .Lfunc_end0 -NEXT checks otherwise.
+;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
+
+; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+;; Make sure FastISel doesn't break anything.
+; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs \
+; RUN: -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+define void @test() nounwind ssp {
+; NO_TRAP_UNREACHABLE-LABEL: test:
+; NO_TRAP_UNREACHABLE: bl __stack_chk_fail
+; NO_TRAP_UNREACHABLE-NOT: brk #0x1
+; NO_TRAP_UNREACHABLE-NEXT: .Lfunc_end0
+;
+; TRAP_UNREACHABLE-LABEL: test:
+; TRAP_UNREACHABLE: bl __stack_chk_fail
+; TRAP_UNREACHABLE-NEXT: brk #0x1
+; TRAP_UNREACHABLE-NEXT: .Lfunc_end0
+
+entry:
+ %buf = alloca [8 x i8]
+ %2 = call i32(ptr) @callee(ptr %buf) nounwind
+ ret void
+}
+
+declare i32 @callee(ptr) nounwind
diff --git a/llvm/test/CodeGen/X86/stack-protector-trap-unreachable.ll b/llvm/test/CodeGen/X86/stack-protector-trap-unreachable.ll
new file mode 100644
index 00000000000000..f24e9b1cc3740a
--- /dev/null
+++ b/llvm/test/CodeGen/X86/stack-protector-trap-unreachable.ll
@@ -0,0 +1,43 @@
+; NOTE: Do not autogenerate, we'd lose the .Lfunc_end0 -NEXT checks otherwise.
+;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
+
+; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+;; Make sure FastISel doesn't break anything.
+; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs \
+; RUN: -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+define void @test() nounwind ssp {
+; NO_TRAP_UNREACHABLE-LABEL: test:
+; NO_TRAP_UNREACHABLE: callq __stack_chk_fail
+; NO_TRAP_UNREACHABLE-NOT: ud2
+; NO_TRAP_UNREACHABLE-NEXT: .Lfunc_end0
+
+; TRAP_UNREACHABLE-LABEL: test:
+; TRAP_UNREACHABLE: callq __stack_chk_fail
+; TRAP_UNREACHABLE-NEXT: ud2
+; TRAP_UNREACHABLE-NEXT: .Lfunc_end0
+
+entry:
+ %buf = alloca [8 x i8]
+ %2 = call i32(ptr) @callee(ptr %buf) nounwind
+ ret void
+}
+
+declare i32 @callee(ptr) nounwind
diff --git a/llvm/test/CodeGen/X86/unreachable-trap.ll b/llvm/test/CodeGen/X86/unreachable-trap.ll
index d2704bf7b46205..486ee0f7a0e246 100644
--- a/llvm/test/CodeGen/X86/unreachable-trap.ll
+++ b/llvm/test/CodeGen/X86/unreachable-trap.ll
@@ -1,7 +1,15 @@
; RUN: llc -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK
; RUN: llc -o - %s -mtriple=x86_64-windows-msvc | FileCheck %s --check-prefixes=CHECK
-; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
; RUN: llc -o - %s -mtriple=x86_64-apple-darwin | FileCheck %s --check-prefixes=CHECK,NO_TRAP_AFTER_NORETURN
+
+; On PS4/PS5, always emit trap instructions regardless of of trap-unreachable or no-trap-after-noreturn.
+; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable -no-trap-after-noreturn=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable -no-trap-after-noreturn=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+
; RUN: llc --trap-unreachable -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
; RUN: llc --trap-unreachable -global-isel -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
; RUN: llc --trap-unreachable -fast-isel -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
More information about the llvm-commits
mailing list