diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index e0c3cc5eddb82..115a26a76bf34 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -9233,10 +9233,24 @@ AArch64TargetLowering::LowerDarwinGlobalTLSAddress(SDValue Op, // normal AArch64 call node: x0 takes the address of the descriptor, and // returns the address of the variable in this thread. Chain = DAG.getCopyToReg(Chain, DL, AArch64::X0, DescAddr, SDValue()); - Chain = - DAG.getNode(AArch64ISD::CALL, DL, DAG.getVTList(MVT::Other, MVT::Glue), - Chain, FuncTLVGet, DAG.getRegister(AArch64::X0, MVT::i64), - DAG.getRegisterMask(Mask), Chain.getValue(1)); + + unsigned Opcode = AArch64ISD::CALL; + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(FuncTLVGet); + + // With ptrauth-calls, the tlv access thunk pointer is authenticated (IA, 0). + if (DAG.getMachineFunction().getFunction().hasFnAttribute("ptrauth-calls")) { + Opcode = AArch64ISD::AUTH_CALL; + Ops.push_back(DAG.getTargetConstant(AArch64PACKey::IA, DL, MVT::i32)); + Ops.push_back(DAG.getTargetConstant(0, DL, MVT::i64)); // Integer Disc. + Ops.push_back(DAG.getRegister(AArch64::NoRegister, MVT::i64)); // Addr Disc. + } + + Ops.push_back(DAG.getRegister(AArch64::X0, MVT::i64)); + Ops.push_back(DAG.getRegisterMask(Mask)); + Ops.push_back(Chain.getValue(1)); + Chain = DAG.getNode(Opcode, DL, DAG.getVTList(MVT::Other, MVT::Glue), Ops); return DAG.getCopyFromReg(Chain, DL, AArch64::X0, PtrVT, Chain.getValue(1)); } diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index 9e0860934f777..be02f92ec71f9 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -3653,7 +3653,15 @@ bool AArch64InstructionSelector::selectTLSGlobalValue( // TLS calls preserve all registers except those that absolutely must be // trashed: X0 (it takes an argument), LR (it's a call) and NZCV (let's not be // silly). - MIB.buildInstr(getBLRCallOpcode(MF), {}, {Load}) + unsigned Opcode = getBLRCallOpcode(MF); + + // With ptrauth-calls, the tlv access thunk pointer is authenticated (IA, 0). + if (MF.getFunction().hasFnAttribute("ptrauth-calls")) { + assert(Opcode == AArch64::BLR); + Opcode = AArch64::BLRAAZ; + } + + MIB.buildInstr(Opcode, {}, {Load}) .addUse(AArch64::X0, RegState::Implicit) .addDef(AArch64::X0, RegState::Implicit) .addRegMask(TRI.getTLSCallPreservedMask()); diff --git a/llvm/test/CodeGen/AArch64/ptrauth-tls-darwin.ll b/llvm/test/CodeGen/AArch64/ptrauth-tls-darwin.ll new file mode 100644 index 0000000000000..e3cb0e818d16d --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-tls-darwin.ll @@ -0,0 +1,27 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=arm64e-apple-darwin %s -o - \ +; RUN: -aarch64-enable-collect-loh=0 | FileCheck %s + +; RUN: llc -mtriple=arm64e-apple-darwin %s -o - \ +; RUN: -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-enable-collect-loh=0 | FileCheck %s + +@var = thread_local global i8 0 + +define i8 @get_var() #0 { +; CHECK-LABEL: get_var: +; CHECK: ; %bb.0: +; CHECK-NEXT: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill +; CHECK-NEXT: adrp x0, _var@TLVPPAGE +; CHECK-NEXT: ldr x0, [x0, _var@TLVPPAGEOFF] +; CHECK-NEXT: ldr x8, [x0] +; CHECK-NEXT: blraaz x8 +; CHECK-NEXT: ldrb w0, [x0] +; CHECK-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload +; CHECK-NEXT: ret + + %val = load i8, ptr @var, align 1 + ret i8 %val +} + +attributes #0 = { nounwind "ptrauth-calls" }