diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1027,6 +1027,16 @@ LowerHWASAN_CHECK_MEMACCESS(*MI); return; + case AArch64::ADR_PC: { + auto Sym = OutContext.createTempSymbol(); + OutStreamer->EmitLabel(Sym); + EmitToStreamer(*OutStreamer, + MCInstBuilder(AArch64::ADR) + .addReg(MI->getOperand(0).getReg()) + .addExpr(MCSymbolRefExpr::create(Sym, OutContext))); + return; + } + case AArch64::SEH_StackAlloc: TS->EmitARM64WinCFIAllocStack(MI->getOperand(0).getImm()); return; diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -2678,6 +2678,13 @@ return true; } + if (RegString->getString() == "pc") { + ReplaceNode(N, CurDAG->getMachineNode(AArch64::ADR_PC, DL, + N->getSimpleValueType(0), MVT::Other, + N->getOperand(0))); + return true; + } + return false; } diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -1619,6 +1619,10 @@ def : Pat<(AArch64adrp tblockaddress:$cp), (ADRP tblockaddress:$cp)>; def : Pat<(AArch64adrp texternalsym:$sym), (ADRP texternalsym:$sym)>; +// An ADR pseudo-instruction that returns the address of itself. +// Used to implement read_register("pc"). +def ADR_PC : Pseudo<(outs GPR64:$addr), (ins), []>, Sched<[WriteI]>; + //===----------------------------------------------------------------------===// // Unconditional branch (register) instructions. //===----------------------------------------------------------------------===// diff --git a/llvm/test/CodeGen/AArch64/read-pc.ll b/llvm/test/CodeGen/AArch64/read-pc.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/read-pc.ll @@ -0,0 +1,12 @@ +; RUN: llc < %s -mtriple=arm64-linux-gnu | FileCheck %s + +define i64 @read_pc() { + ; CHECK: .Ltmp0: + ; CHECK-NEXT: adr x0, .Ltmp0 + %pc = call i64 @llvm.read_register.i64(metadata !0) + ret i64 %pc +} + +declare i64 @llvm.read_register.i64(metadata) nounwind + +!0 = !{!"pc"}