Index: include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- include/llvm/CodeGen/ISDOpcodes.h +++ include/llvm/CodeGen/ISDOpcodes.h @@ -70,7 +70,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, + FRAMEADDR, RETURNADDR, ADDROFRETURNADDR, SPONENTRY, /// LOCAL_RECOVER - Represents the llvm.localrecover intrinsic. /// Materializes the offset from the local object pointer of another Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -320,6 +320,7 @@ def int_returnaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>; def int_addressofreturnaddress : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; def int_frameaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>; +def int_sponentry : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; def int_read_register : Intrinsic<[llvm_anyint_ty], [llvm_metadata_ty], [IntrReadMem], "llvm.read_register">; def int_write_register : Intrinsic<[], [llvm_metadata_ty, llvm_anyint_ty], Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1059,6 +1059,7 @@ case ISD::FRAMEADDR: case ISD::RETURNADDR: case ISD::ADDROFRETURNADDR: + case ISD::SPONENTRY: // These operations lie about being legal: when they claim to be legal, // they should actually be custom-lowered. Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5050,6 +5050,10 @@ setValue(&I, DAG.getNode(ISD::ADDROFRETURNADDR, sdl, TLI.getPointerTy(DAG.getDataLayout()))); return nullptr; + case Intrinsic::sponentry: + setValue(&I, DAG.getNode(ISD::SPONENTRY, sdl, + TLI.getPointerTy(DAG.getDataLayout()))); + return nullptr; case Intrinsic::frameaddress: setValue(&I, DAG.getNode(ISD::FRAMEADDR, sdl, TLI.getPointerTy(DAG.getDataLayout()), Index: lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -124,6 +124,7 @@ case ISD::RETURNADDR: return "RETURNADDR"; case ISD::ADDROFRETURNADDR: return "ADDROFRETURNADDR"; case ISD::FRAMEADDR: return "FRAMEADDR"; + case ISD::SPONENTRY: return "SPONENTRY"; case ISD::LOCAL_RECOVER: return "LOCAL_RECOVER"; case ISD::READ_REGISTER: return "READ_REGISTER"; case ISD::WRITE_REGISTER: return "WRITE_REGISTER"; Index: lib/Target/AArch64/AArch64FastISel.cpp =================================================================== --- lib/Target/AArch64/AArch64FastISel.cpp +++ lib/Target/AArch64/AArch64FastISel.cpp @@ -3450,6 +3450,42 @@ updateValueMap(II, SrcReg); return true; } + case Intrinsic::sponentry: { + MachineFrameInfo &MFI = FuncInfo.MF->getFrameInfo(); + MFI.setFrameAddressIsTaken(true); + + // Make sure the computation is correct. + if (!Subtarget->getFrameLowering()->noFramePointerElim(*FuncInfo.MF)) + report_fatal_error("Intrinsic::sponentry requires frame pointer."); + + // FP + 16 without Fixed Object. + // Fixed Object + 16 + unsigned numFixed = MFI.getNumFixedObjects(); + MVT VT = TLI.getPointerTy(DL); + if (numFixed) { + // First fixed objected + unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT)); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(AArch64::ADDXri), ResultReg) + .addFrameIndex(-numFixed) + .addImm(0) + .addImm(0); + updateValueMap(II, ResultReg); + } else { + // FP + 16 + const AArch64RegisterInfo *RegInfo = Subtarget->getRegisterInfo(); + unsigned FramePtr = RegInfo->getFrameRegister(*(FuncInfo.MF)); + unsigned SrcReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), SrcReg).addReg(FramePtr); + + unsigned AddReg = emitAdd_ri_(VT, SrcReg, /*IsKill=*/false, 16); + SrcReg = AddReg; + + updateValueMap(II, SrcReg); + } + return true; + } case Intrinsic::memcpy: case Intrinsic::memmove: { const auto *MTI = cast(II); Index: lib/Target/AArch64/AArch64ISelLowering.h =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.h +++ lib/Target/AArch64/AArch64ISelLowering.h @@ -617,6 +617,7 @@ SDValue LowerVACOPY(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSPONENTRY(SDValue Op, SelectionDAG &DAG) const; SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const; Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -2863,6 +2863,8 @@ return LowerFP_EXTEND(Op, DAG); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); + case ISD::SPONENTRY: + return LowerSPONENTRY(Op, DAG); case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); case ISD::INSERT_VECTOR_ELT: @@ -5152,6 +5154,29 @@ return FrameAddr; } +SDValue AArch64TargetLowering::LowerSPONENTRY(SDValue Op, + SelectionDAG &DAG) const { + MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); + MFI.setFrameAddressIsTaken(true); + + // Make sure the computation is correct. + if (!Subtarget->getFrameLowering()->noFramePointerElim( + DAG.getMachineFunction())) + report_fatal_error("Intrinsic::sponentry requires frame pointer."); + + unsigned numFixed = MFI.getNumFixedObjects(); + EVT VT = getPointerTy(DAG.getDataLayout()); + SDLoc DL(Op); + if (numFixed) { + return DAG.getFrameIndex(-numFixed, VT); + } else { + SDValue Offset = DAG.getConstant(16, DL, MVT::i64); + SDValue FrameAddr = + DAG.getCopyFromReg(DAG.getEntryNode(), DL, AArch64::FP, VT); + return DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset); + } +} + // FIXME? Maybe this could be a TableGen attribute on some registers and // this table could be generated automatically from RegInfo. unsigned AArch64TargetLowering::getRegisterByName(const char* RegName, EVT VT, Index: test/CodeGen/AArch64/sponentry.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/sponentry.ll @@ -0,0 +1,27 @@ +; RUN: llc -mtriple=aarch64-windows-msvc -disable-fp-elim %s -o - | FileCheck %s +; RUN: not llc -mtriple=aarch64-windows-msvc %s -o - 2>&1 | FileCheck %s --check-prefix=NOTWORK + +define dso_local void @bar([24 x i64]*) { + %2 = alloca [24 x i64]*, align 8 + %3 = alloca i32, align 4 + store [24 x i64]* %0, [24 x i64]** %2, align 8 + %4 = call i8* @llvm.sponentry() + %5 = load [24 x i64]*, [24 x i64]** %2, align 8 + %6 = getelementptr inbounds [24 x i64], [24 x i64]* %5, i32 0, i32 0 + %7 = bitcast i64* %6 to i8* + %8 = call i32 @_setjmpex(i8* %7, i8* %4) #2 + store i32 %8, i32* %3, align 4 + ret void +} + +; Function Attrs: nounwind readnone +declare i8* @llvm.sponentry() + +; Function Attrs: returns_twice +declare dso_local i32 @_setjmpex(i8*, i8*) + +; CHECK: add x29, sp, #16 +; CHECK: add x1, x29, #16 +; CEHCK: bl _setjmpex + +; NOTWORK: Intrinsic::sponentry requires frame pointer