danielkiss created this revision.
danielkiss added reviewers: ostannard, asl.
Herald added subscribers: llvm-commits, cfe-commits, jdoerfert, hiraditya, 
kristof.beyls.
Herald added projects: clang, LLVM.

This change adds the support for __builtin_extract_return_addr
for ARMv8.3A Pointer Authentications.
Location of the authentication code in the pointer depends on
the system configuration, therefor a dedicated instruction is used for
effectively removing the authentication code without
authenticating the pointer.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75044

Files:
  clang/lib/CodeGen/TargetInfo.cpp
  clang/test/CodeGen/arm64-extractreturnaddress.c
  llvm/docs/LangRef.rst
  llvm/include/llvm/CodeGen/ISDOpcodes.h
  llvm/include/llvm/IR/Intrinsics.td
  llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
  llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
  llvm/lib/Target/AArch64/AArch64ISelLowering.h
  llvm/test/CodeGen/AArch64/aarch64-extractreturnaddress.ll

Index: llvm/test/CodeGen/AArch64/aarch64-extractreturnaddress.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/AArch64/aarch64-extractreturnaddress.ll
@@ -0,0 +1,29 @@
+; RUN: llc < %s -mtriple=arm64-eabi -asm-verbose=false -mattr=v8.2a | FileCheck %s
+; RUN: llc < %s -mtriple=arm64-eabi -asm-verbose=false -mattr=v8.3a | FileCheck %s --check-prefix=CHECKV83
+
+; Armv8.3-A Pointer Authetication requires a special intsruction to strip the
+; pointer authentication code from the pointer.
+; The XPACLRI instruction assembles to a hint-space instruction before Armv8.3-A
+; therefore this instruction can be safely used for any pre Armv8.3-A architectures.
+; On Armv8.3-A and onwards XPACI is available so use that instead.
+
+define i8* @era0(i8* %x) nounwind readnone #0 {
+entry:
+; CHECK-LABEL: era0:
+; CHECK:          hint #25
+; CHECK-NEXT:     str     x30, [sp, #-16]!
+; CHECK-NEXT:     mov     x30, x0
+; CHECK-NEXT:     hint #7
+; CHECK-NEXT:     mov     x0, x30
+; CHECK-NEXT:     ldr     x30, [sp], #16
+; CHECK-NEXT:     hint #29
+; CHECK-NEXT:     ret
+; CHECKV83:       paciasp
+; CHECKV83-NEXT:  xpaci   x0
+; CHECKV83-NEXT:  retaa
+  %0 = tail call i8* @llvm.extractreturnaddress(i8* %x)
+  ret i8* %0
+}
+attributes #0 = { "sign-return-address"="all" }
+
+declare i8* @llvm.extractreturnaddress(i8*) nounwind readnone
Index: llvm/lib/Target/AArch64/AArch64ISelLowering.h
===================================================================
--- llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -738,6 +738,7 @@
   SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerSPONENTRY(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerEXTRACTRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
===================================================================
--- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3249,6 +3249,8 @@
     return LowerSPONENTRY(Op, DAG);
   case ISD::RETURNADDR:
     return LowerRETURNADDR(Op, DAG);
+  case ISD::EXTRACTRETURNADDR:
+    return LowerEXTRACTRETURNADDR(Op, DAG);
   case ISD::ADDROFRETURNADDR:
     return LowerADDROFRETURNADDR(Op, DAG);
   case ISD::INSERT_VECTOR_ELT:
@@ -5953,6 +5955,27 @@
   return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, VT);
 }
 
+SDValue AArch64TargetLowering::LowerEXTRACTRETURNADDR(SDValue Op,
+                                                      SelectionDAG &DAG) const {
+  SDLoc DL(Op);
+  EVT VT = Op.getValueType();
+
+  // The XPACLRI instruction assembles to a hint-space instruction before
+  // Armv8.3-A therefore this instruction can be safely used for any pre
+  // Armv8.3-A architectures. On Armv8.3-A and onwards XPACI is available so use
+  // that instead.
+  if (Subtarget->hasV8_3aOps()) {
+    SDNode *St = DAG.getMachineNode(AArch64::XPACI, DL, VT, Op.getOperand(0));
+    return SDValue(St, 0);
+  } else {
+    // XPACLRI operates on LR therefore we must move the operand accordingly.
+    SDValue Reg =
+        DAG.getCopyToReg(DAG.getEntryNode(), DL, AArch64::LR, Op.getOperand(0));
+    SDNode *St = DAG.getMachineNode(AArch64::XPACLRI, DL, VT, Reg);
+    return SDValue(St, 0);
+  }
+}
+
 /// LowerShiftRightParts - Lower SRA_PARTS, which returns two
 /// i64 values and take a 2 x i64 value to shift plus a shift amount.
 SDValue AArch64TargetLowering::LowerShiftRightParts(SDValue Op,
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5770,6 +5770,11 @@
                              TLI.getPointerTy(DAG.getDataLayout()),
                              getValue(I.getArgOperand(0))));
     return;
+  case Intrinsic::extractreturnaddress:
+    setValue(&I, DAG.getNode(ISD::EXTRACTRETURNADDR, sdl,
+                             TLI.getPointerTy(DAG.getDataLayout()),
+                             getValue(I.getArgOperand(0))));
+    return;
   case Intrinsic::addressofreturnaddress:
     setValue(&I, DAG.getNode(ISD::ADDROFRETURNADDR, sdl,
                              TLI.getPointerTy(DAG.getDataLayout())));
Index: llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -1088,6 +1088,7 @@
   case ISD::ADJUST_TRAMPOLINE:
   case ISD::FRAMEADDR:
   case ISD::RETURNADDR:
+  case ISD::EXTRACTRETURNADDR:
   case ISD::ADDROFRETURNADDR:
   case ISD::SPONENTRY:
     // These operations lie about being legal: when they claim to be legal,
Index: llvm/include/llvm/IR/Intrinsics.td
===================================================================
--- llvm/include/llvm/IR/Intrinsics.td
+++ llvm/include/llvm/IR/Intrinsics.td
@@ -425,6 +425,7 @@
 def int_returnaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem, ImmArg<0>]>;
 def int_addressofreturnaddress : Intrinsic<[llvm_anyptr_ty], [], [IntrNoMem]>;
 def int_frameaddress : Intrinsic<[llvm_anyptr_ty], [llvm_i32_ty], [IntrNoMem, ImmArg<0>]>;
+def int_extractreturnaddress : Intrinsic<[llvm_anyptr_ty], [llvm_anyptr_ty], [IntrNoMem]>;
 def int_sponentry  : Intrinsic<[llvm_anyptr_ty], [], [IntrNoMem]>;
 def int_read_register  : Intrinsic<[llvm_anyint_ty], [llvm_metadata_ty],
                                    [IntrReadMem], "llvm.read_register">;
Index: llvm/include/llvm/CodeGen/ISDOpcodes.h
===================================================================
--- llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -71,7 +71,7 @@
     /// of the frame or return address to return.  An index of zero corresponds
     /// to the current function's frame or return address, an index of one to
     /// the parent's frame or return address, and so on.
-    FRAMEADDR, RETURNADDR, ADDROFRETURNADDR, SPONENTRY,
+    FRAMEADDR, RETURNADDR, ADDROFRETURNADDR, EXTRACTRETURNADDR, SPONENTRY,
 
     /// LOCAL_RECOVER - Represents the llvm.localrecover intrinsic.
     /// Materializes the offset from the local object pointer of another
Index: llvm/docs/LangRef.rst
===================================================================
--- llvm/docs/LangRef.rst
+++ llvm/docs/LangRef.rst
@@ -11179,6 +11179,36 @@
 other aggressive transformations, so the value returned may not be that
 of the obvious source-language caller.
 
+'``llvm.extractreturnaddress``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+      declare i8* @llvm.extractreturnaddress(i8* <addr>)
+
+Overview:
+"""""""""
+
+The '``llvm.extractreturnaddress``' intrinsic post processes the return
+address. On most architechutre it could return with the address as it is.
+
+Arguments:
+""""""""""
+
+The argument to this intrinsic is an address from '``llvm.returnaddress``'.
+
+Semantics:
+""""""""""
+
+The '``llvm.extractreturnaddress``' intrinsic returns a pointer that is
+post processed. There is no validation on the address therefore the required
+transformation will be performed on any argument.
+
+This intrinsic is only implemented for aarch64.
+
 '``llvm.addressofreturnaddress``' Intrinsic
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
Index: clang/test/CodeGen/arm64-extractreturnaddress.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/arm64-extractreturnaddress.c
@@ -0,0 +1,22 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang -target arm64-none-linux-gnu -march=armv8-a \
+// RUN:  -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang -target arm64-none-linux-gnu -march=armv8-a -mbranch-protection=pac-ret \
+// RUN:  -S -emit-llvm -o - %s | FileCheck %s  --check-prefix=CHECK-PAC
+// RUN: %clang -target arm64-none-linux-gnu -march=armv8.3-a -mbranch-protection=pac-ret \
+// RUN:  -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-PAC83
+// RUN: %clang -target arm64-none-linux-gnu -march=armv8-a -mbranch-protection=standard \
+// RUN:  -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BPROT8
+// RUN: %clang -target arm64-none-linux-gnu -march=armv8.5-a -mbranch-protection=standard \
+// RUN:  -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BPROT83
+
+// CHECK:; Function Attrs: noinline nounwind optnone
+// CHECK:      define dso_local i8* @bar() #0 {
+// CHECK-NEXT:    ret i8* inttoptr (i64 42 to i8*)
+// CHECK-PAC:     %1 = call i8* @llvm.extractreturnaddress.p0i8.p0i8(i8* inttoptr (i64 42 to i8*))
+// CHECK-PAC83:   %1 = call i8* @llvm.extractreturnaddress.p0i8.p0i8(i8* inttoptr (i64 42 to i8*))
+// CHECK-BPROT8:  %1 = call i8* @llvm.extractreturnaddress.p0i8.p0i8(i8* inttoptr (i64 42 to i8*))
+// CHECK-BPROT83: %1 = call i8* @llvm.extractreturnaddress.p0i8.p0i8(i8* inttoptr (i64 42 to i8*))
+void *bar() {
+  return __builtin_extract_return_addr((void *)42);
+}
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -5139,6 +5139,20 @@
     if (BranchTargetEnforcement)
       Fn->addFnAttr("branch-target-enforcement");
   }
+  llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF,
+                                   llvm::Value *Address) const override {
+    CodeGenOptions::SignReturnAddressScope Scope =
+        CGF.CGM.getCodeGenOpts().getSignReturnAddress();
+    if (Scope == CodeGenOptions::SignReturnAddressScope::None) {
+      return Address;
+    }
+    llvm::Function *F =
+        CGF.CGM.getIntrinsic(llvm::Intrinsic::extractreturnaddress,
+                             {Address->getType(), Address->getType()});
+    llvm::CallInst *Call = CGF.Builder.CreateCall(F, Address);
+    Call->setDoesNotAccessMemory();
+    return Call;
+  }
 };
 
 class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to