This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG0fbb17458a01: [ARM] Implement setjmp BTI placement for 
PACBTI-M (authored by stuij).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112427/new/

https://reviews.llvm.org/D112427

Files:
  clang/docs/ClangCommandLineReference.rst
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/ARM.cpp
  clang/test/Driver/arm-bti-return-twice.c
  llvm/lib/Target/ARM/ARM.td
  llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
  llvm/lib/Target/ARM/ARMISelLowering.cpp
  llvm/lib/Target/ARM/ARMISelLowering.h
  llvm/lib/Target/ARM/ARMInstrThumb2.td
  llvm/lib/Target/ARM/ARMSubtarget.h
  llvm/test/CodeGen/ARM/setjmp-bti-basic.ll
  llvm/test/CodeGen/ARM/setjmp-bti-outliner.ll

Index: llvm/test/CodeGen/ARM/setjmp-bti-outliner.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/ARM/setjmp-bti-outliner.ll
@@ -0,0 +1,92 @@
+; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -enable-machine-outliner < %s | \
+; RUN: FileCheck %s --check-prefix=BTI
+; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -enable-machine-outliner -mattr=+no-bti-at-return-twice < %s | FileCheck %s --check-prefix=NOBTI
+
+; C source
+; --------
+; jmp_buf buf;
+;
+; extern void h(int a, int b, int *c);
+;
+; int f(int a, int b, int c, int d) {
+;   if (setjmp(buf) != 0)
+;     return -1;
+;   h(a, b, &a);
+;   return 2 + a * (a + b) / (c + d);
+; }
+;
+; int g(int a, int b, int c, int d) {
+;   if (setjmp(buf) != 0)
+;     return -1;
+;   h(a, b, &a);
+;   return 1 + a * (a + b) / (c + d);
+; }
+
+@buf = global [20 x i64] zeroinitializer, align 8
+
+define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) {
+; BTI-LABEL: f:
+; BTI:       bl OUTLINED_FUNCTION_0
+; BTI-NEXT:  bti
+; NOBTI-LABEL: f:
+; NOBTI:       bl OUTLINED_FUNCTION_0
+; NOBTI-NEXT:   cbz	r0, .LBB0_2
+entry:
+  %a.addr = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  %call = call i32 @setjmp(i64* getelementptr inbounds ([20 x i64], [20 x i64]* @buf, i32 0, i32 0)) #0
+  %cmp.not = icmp eq i32 %call, 0
+  br i1 %cmp.not, label %if.end, label %return
+
+if.end:                                           ; preds = %entry
+  call void @h(i32 %a, i32 %b, i32* nonnull %a.addr)
+  %0 = load i32, i32* %a.addr, align 4
+  %add = add nsw i32 %0, %b
+  %mul = mul nsw i32 %add, %0
+  %add1 = add nsw i32 %d, %c
+  %div = sdiv i32 %mul, %add1
+  %add2 = add nsw i32 %div, 2
+  br label %return
+
+return:                                           ; preds = %entry, %if.end
+  %retval.0 = phi i32 [ %add2, %if.end ], [ -1, %entry ]
+  ret i32 %retval.0
+}
+
+define i32 @g(i32 %a, i32 %b, i32 %c, i32 %d) {
+; BTI-LABEL: g:
+; BTI:       bl OUTLINED_FUNCTION_0
+; BTI-NEXT:  bti
+; NOBTI-LABEL: g:
+; NOBTI:       bl OUTLINED_FUNCTION_0
+; NOBTI-NEXT:  cbz	r0, .LBB1_2
+entry:
+  %a.addr = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  %call = call i32 @setjmp(i64* getelementptr inbounds ([20 x i64], [20 x i64]* @buf, i32 0, i32 0)) #0
+  %cmp.not = icmp eq i32 %call, 0
+  br i1 %cmp.not, label %if.end, label %return
+
+if.end:                                           ; preds = %entry
+  call void @h(i32 %a, i32 %b, i32* nonnull %a.addr)
+  %0 = load i32, i32* %a.addr, align 4
+  %add = add nsw i32 %0, %b
+  %mul = mul nsw i32 %add, %0
+  %add1 = add nsw i32 %d, %c
+  %div = sdiv i32 %mul, %add1
+  %add2 = add nsw i32 %div, 1
+  br label %return
+
+return:                                           ; preds = %entry, %if.end
+  %retval.0 = phi i32 [ %add2, %if.end ], [ -1, %entry ]
+  ret i32 %retval.0
+}
+
+declare void @h(i32, i32, i32*)
+declare i32 @setjmp(i64*) #0
+
+attributes #0 = { returns_twice }
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"branch-target-enforcement", i32 1}
Index: llvm/test/CodeGen/ARM/setjmp-bti-basic.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/ARM/setjmp-bti-basic.ll
@@ -0,0 +1,50 @@
+; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi < %s | FileCheck %s --check-prefix=BTI
+; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+no-bti-at-return-twice < %s | \
+; RUN: FileCheck %s --check-prefix=NOBTI
+
+; C source
+; --------
+; jmp_buf buf;
+;
+; extern void bar(int x);
+;
+; int foo(int x) {
+;   if (setjmp(buf))
+;     x = 0;
+;   else
+;     bar(x);
+;   return x;
+; }
+
+@buf = global [20 x i64] zeroinitializer, align 8
+
+define i32 @foo(i32 %x) {
+; BTI-LABEL: foo:
+; BTI:       bl setjmp
+; BTI-NEXT:  bti
+; NOBTI-LABEL: foo:
+; NOBTI:       bl setjmp
+; NOBTI-NOT:   bti
+
+entry:
+  %call = call i32 @setjmp(i64* getelementptr inbounds ([20 x i64], [20 x i64]* @buf, i32 0, i32 0)) #0
+  %tobool.not = icmp eq i32 %call, 0
+  br i1 %tobool.not, label %if.else, label %if.end
+
+if.else:                                          ; preds = %entry
+  call void @bar(i32 %x)
+  br label %if.end
+
+if.end:                                           ; preds = %entry, %if.else
+  %x.addr.0 = phi i32 [ %x, %if.else ], [ 0, %entry ]
+  ret i32 %x.addr.0
+}
+
+declare void @bar(i32)
+declare i32 @setjmp(i64*) #0
+
+attributes #0 = { returns_twice }
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"branch-target-enforcement", i32 1}
Index: llvm/lib/Target/ARM/ARMSubtarget.h
===================================================================
--- llvm/lib/Target/ARM/ARMSubtarget.h
+++ llvm/lib/Target/ARM/ARMSubtarget.h
@@ -534,6 +534,10 @@
   /// Selected instruction itineraries (one entry per itinerary class.)
   InstrItineraryData InstrItins;
 
+  /// NoBTIAtReturnTwice - Don't place a BTI instruction after
+  /// return-twice constructs (setjmp)
+  bool NoBTIAtReturnTwice = false;
+
   /// Options passed via command line that could influence the target
   const TargetOptions &Options;
 
@@ -948,6 +952,8 @@
   bool hardenSlsRetBr() const { return HardenSlsRetBr; }
   bool hardenSlsBlr() const { return HardenSlsBlr; }
   bool hardenSlsNoComdat() const { return HardenSlsNoComdat; }
+
+  bool getNoBTIAtReturnTwice() const { return NoBTIAtReturnTwice; }
 };
 
 } // end namespace llvm
Index: llvm/lib/Target/ARM/ARMInstrThumb2.td
===================================================================
--- llvm/lib/Target/ARM/ARMInstrThumb2.td
+++ llvm/lib/Target/ARM/ARMInstrThumb2.td
@@ -5736,3 +5736,10 @@
 def t2AUT    : PACBTIHintSpaceUseInst<"aut", 0b00101101> {
   let hasSideEffects = 1;
 }
+
+def ARMt2CallBTI : SDNode<"ARMISD::t2CALL_BTI", SDT_ARMcall,
+                   [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>;
+
+def t2CALL_BTI : PseudoInst<(outs), (ins pred:$p, thumb_bl_target:$func),
+                 IIC_Br, [(ARMt2CallBTI tglobaladdr:$func)]>,
+                 Requires<[IsThumb2]>, Sched<[WriteBrL]>;
Index: llvm/lib/Target/ARM/ARMISelLowering.h
===================================================================
--- llvm/lib/Target/ARM/ARMISelLowering.h
+++ llvm/lib/Target/ARM/ARMISelLowering.h
@@ -69,6 +69,7 @@
     CALL_PRED,   // Function call that's predicable.
     CALL_NOLINK, // Function call with branch not branch-and-link.
     tSECALL,     // CMSE non-secure function call.
+    t2CALL_BTI,  // Thumb function call followed by BTI instruction.
     BRCOND,      // Conditional branch.
     BR_JT,       // Jumptable branch.
     BR2_JT,      // Jumptable branch (2 level - jumptable entry is a jump).
Index: llvm/lib/Target/ARM/ARMISelLowering.cpp
===================================================================
--- llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1658,6 +1658,7 @@
     MAKE_CASE(ARMISD::CALL_PRED)
     MAKE_CASE(ARMISD::CALL_NOLINK)
     MAKE_CASE(ARMISD::tSECALL)
+    MAKE_CASE(ARMISD::t2CALL_BTI)
     MAKE_CASE(ARMISD::BRCOND)
     MAKE_CASE(ARMISD::BR_JT)
     MAKE_CASE(ARMISD::BR2_JT)
@@ -2321,6 +2322,12 @@
   bool isCmseNSCall   = false;
   bool isSibCall = false;
   bool PreferIndirect = false;
+  bool GuardWithBTI = false;
+
+  // Lower 'returns_twice' calls to a pseudo-instruction.
+  if (CLI.CB && CLI.CB->getAttributes().hasFnAttr(Attribute::ReturnsTwice) &&
+      !Subtarget->getNoBTIAtReturnTwice())
+    GuardWithBTI = AFI->branchTargetEnforcement();
 
   // Determine whether this is a non-secure function call.
   if (CLI.CB && CLI.CB->getAttributes().hasFnAttr("cmse_nonsecure_call"))
@@ -2726,7 +2733,9 @@
   // FIXME: handle tail calls differently.
   unsigned CallOpc;
   if (Subtarget->isThumb()) {
-    if (isCmseNSCall)
+    if (GuardWithBTI)
+      CallOpc = ARMISD::t2CALL_BTI;
+    else if (isCmseNSCall)
       CallOpc = ARMISD::tSECALL;
     else if ((!isDirect || isARMFunc) && !Subtarget->hasV5TOps())
       CallOpc = ARMISD::CALL_NOLINK;
Index: llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
===================================================================
--- llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
+++ llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
@@ -3073,6 +3073,22 @@
       MI.eraseFromParent();
       return true;
     }
+    case ARM::t2CALL_BTI: {
+      MachineFunction &MF = *MI.getMF();
+      MachineInstrBuilder MIB =
+          BuildMI(MF, MI.getDebugLoc(), TII->get(ARM::tBL));
+      MIB.cloneMemRefs(MI);
+      for (unsigned i = 0; i < MI.getNumOperands(); ++i)
+        MIB.add(MI.getOperand(i));
+      if (MI.isCandidateForCallSiteEntry())
+        MF.moveCallSiteInfo(&MI, MIB.getInstr());
+      MIBundleBuilder Bundler(MBB, MI);
+      Bundler.append(MIB);
+      Bundler.append(BuildMI(MF, MI.getDebugLoc(), TII->get(ARM::t2BTI)));
+      finalizeBundle(MBB, Bundler.begin(), Bundler.end());
+      MI.eraseFromParent();
+      return true;
+    }
     case ARM::LOADDUAL:
     case ARM::STOREDUAL: {
       Register PairReg = MI.getOperand(0).getReg();
Index: llvm/lib/Target/ARM/ARM.td
===================================================================
--- llvm/lib/Target/ARM/ARM.td
+++ llvm/lib/Target/ARM/ARM.td
@@ -446,6 +446,11 @@
                                              "Enable Pointer Authentication and Branch "
                                              "Target Identification">;
 
+def FeatureNoBTIAtReturnTwice : SubtargetFeature<"no-bti-at-return-twice",
+                                                 "NoBTIAtReturnTwice", "true",
+                                                 "Don't place a BTI instruction "
+                                                 "after a return-twice">;
+
 //===----------------------------------------------------------------------===//
 // ARM architecture class
 //
Index: clang/test/Driver/arm-bti-return-twice.c
===================================================================
--- /dev/null
+++ clang/test/Driver/arm-bti-return-twice.c
@@ -0,0 +1,7 @@
+// RUN: %clang -target arm-arm-none-eabi -march=armv8-m.main -mbranch-protection=bti \
+// RUN: -mno-bti-at-return-twice -### %s 2>&1 | FileCheck %s --check-prefix=FEAT
+// RUN: %clang -target arm-arm-none-eabi -march=armv8-m.main -mbranch-protection=bti \
+// RUN: -### %s 2>&1 | FileCheck %s --check-prefix=NOFEAT
+
+// FEAT: "+no-bti-at-return-twice"
+// NOFEAT-NOT: "+no-bti-at-return-twice"
Index: clang/lib/Driver/ToolChains/Arch/ARM.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -875,6 +875,8 @@
     }
   }
 
+  if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
+    Features.push_back("+no-bti-at-return-twice");
 }
 
 std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) {
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -3338,6 +3338,11 @@
 def mmark_bti_property : Flag<["-"], "mmark-bti-property">,
   Group<m_aarch64_Features_Group>,
   HelpText<"Add .note.gnu.property with BTI to assembly files (AArch64 only)">;
+def mno_bti_at_return_twice : Flag<["-"], "mno-bti-at-return-twice">,
+  Group<m_arm_Features_Group>,
+  HelpText<"Do not add a BTI instruction after a setjmp or other"
+           " return-twice construct (Arm only)">;
+
 foreach i = {1-31} in
   def ffixed_x#i : Flag<["-"], "ffixed-x"#i>, Group<m_Group>,
     HelpText<"Reserve the x"#i#" register (AArch64/RISC-V only)">;
Index: clang/docs/ClangCommandLineReference.rst
===================================================================
--- clang/docs/ClangCommandLineReference.rst
+++ clang/docs/ClangCommandLineReference.rst
@@ -3260,6 +3260,11 @@
 
 Allow memory accesses to be unaligned (AArch32/AArch64 only)
 
+.. option:: -mno-bti-at-return-twice
+
+Do not add a BTI instruction after a setjmp or other return-twice construct (Arm
+only)
+
 Hexagon
 -------
 .. option:: -mieee-rnd-near
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to