Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -12169,8 +12169,12 @@ Lowering: """"""""" -Lowering for ``@llvm.experimental.deoptimize`` is not yet implemented, -and is a work in progress. +Calls to ``@llvm.experimental.deoptimize`` are lowered to calls to the +symbol ``__llvm_deoptimize`` (it is the frontend's responsibility to +ensure that this symbol is defined). The call arguments to +``@llvm.experimental.deoptimize`` are lowered as if they were formal +arguments of the specified types, and not as varargs. + Stack Map Intrinsics -------------------- Index: llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h +++ llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h @@ -401,6 +401,9 @@ // Stack Protector Fail. STACKPROTECTOR_CHECK_FAIL, + // Deoptimization. + DEOPTIMIZE, + UNKNOWN_LIBCALL }; Index: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -781,6 +781,8 @@ void LowerCallSiteWithDeoptBundle(ImmutableCallSite CS, SDValue Callee, const BasicBlock *EHPadBB); + void LowerDeoptimizeCall(const CallInst *CI); + private: // Terminator instructions. void visitRet(const ReturnInst &I); Index: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5460,6 +5460,10 @@ setValue(&I, N); return nullptr; } + + case Intrinsic::experimental_deoptimize: + LowerDeoptimizeCall(&I); + return nullptr; } } Index: llvm/trunk/lib/CodeGen/SelectionDAG/StatepointLowering.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/StatepointLowering.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/StatepointLowering.cpp @@ -923,3 +923,37 @@ assert(SpillLoad.getNode()); setValue(&Relocate, SpillLoad); } + +void SelectionDAGBuilder::LowerDeoptimizeCall(const CallInst *CI) { + const auto &TLI = DAG.getTargetLoweringInfo(); + + SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(RTLIB::DEOPTIMIZE), + TLI.getPointerTy(DAG.getDataLayout())); + StatepointLoweringInfo SI(DAG); + unsigned ArgBeginIndex = CI->arg_begin() - CI->op_begin(); + populateCallLoweringInfo(SI.CLI, CI, ArgBeginIndex, CI->getNumArgOperands(), + Callee, CI->getType(), false); + + // We don't lower calls to __llvm_deoptimize as varargs, but as a + // regular call. + assert(!SI.CLI.IsVarArg && "Expected from populateCallLoweringInfo!"); + + auto DeoptBundle = *CI->getOperandBundle(LLVMContext::OB_deopt); + + unsigned DefaultID = StatepointDirectives::DeoptBundleStatepointID; + + auto SD = parseStatepointDirectivesFromAttrs(CI->getAttributes()); + SI.ID = SD.StatepointID.getValueOr(DefaultID); + SI.NumPatchBytes = SD.NumPatchBytes.getValueOr(0); + + SI.DeoptState = + ArrayRef(DeoptBundle.Inputs.begin(), DeoptBundle.Inputs.end()); + SI.StatepointFlags = static_cast(StatepointFlags::None); + + // NB! The GC arguments are specifically left empty. + + if (SDValue ReturnVal = LowerAsSTATEPOINT(SI)) { + ReturnVal = lowerRangeToAssertZExt(DAG, *CI, ReturnVal); + setValue(CI, ReturnVal); + } +} Index: llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp +++ llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp @@ -435,6 +435,8 @@ Names[RTLIB::FPEXT_F16_F32] = "__extendhfsf2"; Names[RTLIB::FPROUND_F32_F16] = "__truncsfhf2"; } + + Names[RTLIB::DEOPTIMIZE] = "__llvm_deoptimize"; } /// InitLibcallCallingConvs - Set default libcall CallingConvs. Index: llvm/trunk/test/CodeGen/X86/deopt-intrinsic.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/deopt-intrinsic.ll +++ llvm/trunk/test/CodeGen/X86/deopt-intrinsic.ll @@ -0,0 +1,86 @@ +; RUN: llc < %s | FileCheck %s +; RUN: llc -debug-only=stackmaps < %s 2>&1 | FileCheck --check-prefix=STACKMAPS %s +; REQUIRES: asserts + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +declare i32 @llvm.experimental.deoptimize.i32(...) +declare i8 @llvm.experimental.deoptimize.i8(...) + +define i32 @caller_0() { +; CHECK-LABEL: _caller_0: +; CHECK-NEXT: {{.+cfi.+}} +; CHECK-NEXT: ##{{.+}} +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: {{Ltmp[0-9]+}}: +; CHECK-NEXT: {{.+cfi.+}} +; CHECK-NEXT: callq ___llvm_deoptimize +; CHECK-NEXT: {{Ltmp[0-9]+}}: +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: retq +entry: + %v = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 0) ] + ret i32 %v +} + +define i8 @caller_1() { +; CHECK-LABEL: _caller_1: +; CHECK-NEXT: {{.+cfi.+}} +; CHECK-NEXT: ##{{.+}} +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: {{Ltmp[0-9]+}}: +; CHECK-NEXT: {{.+cfi.+}} +; CHECK-NEXT: movss {{[a-zA-Z0-9_]+}}(%rip), %xmm0 ## xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: movl $42, %edi +; CHECK-NEXT: callq ___llvm_deoptimize +; CHECK-NEXT: {{Ltmp[0-9]+}}: +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: retq + +entry: + %v = call i8(...) @llvm.experimental.deoptimize.i8(i32 42, float 500.0) [ "deopt"(i32 1) ] + ret i8 %v +} + +define i8 @caller_2() { +; CHECK-LABEL: _caller_2: +; CHECK-NEXT: {{.+cfi.+}} +; CHECK-NEXT: ##{{.+}} +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: {{Ltmp[0-9]+}}: +; CHECK-NEXT: {{.+cfi.+}} +; CHECK-NEXT: movl $1140457472, (%rsp) ## imm = 0x43FA0000 +; CHECK-NEXT: movl $42, %eax +; CHECK-NEXT: callq ___llvm_deoptimize +; CHECK-NEXT: {{Ltmp[0-9]+}}: +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: retq + +entry: + %v = call webkit_jscc i8(...) @llvm.experimental.deoptimize.i8(i32 42, float 500.0) [ "deopt"(i32 3) ] + ret i8 %v +} + +; STACKMAPS: Stack Maps: callsites: +; STACKMAPS-NEXT: Stack Maps: callsite 2882400015 +; STACKMAPS-NEXT: Stack Maps: has 4 locations +; STACKMAPS-NEXT: Stack Maps: Loc 0: Constant 0 [encoding: .byte 4, .byte 8, .short 0, .int 0] +; STACKMAPS-NEXT: Stack Maps: Loc 1: Constant 0 [encoding: .byte 4, .byte 8, .short 0, .int 0] +; STACKMAPS-NEXT: Stack Maps: Loc 2: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1] +; STACKMAPS-NEXT: Stack Maps: Loc 3: Constant 0 [encoding: .byte 4, .byte 8, .short 0, .int 0] +; STACKMAPS-NEXT: Stack Maps: has 0 live-out registers +; STACKMAPS-NEXT: Stack Maps: callsite 2882400015 +; STACKMAPS-NEXT: Stack Maps: has 4 locations +; STACKMAPS-NEXT: Stack Maps: Loc 0: Constant 0 [encoding: .byte 4, .byte 8, .short 0, .int 0] +; STACKMAPS-NEXT: Stack Maps: Loc 1: Constant 0 [encoding: .byte 4, .byte 8, .short 0, .int 0] +; STACKMAPS-NEXT: Stack Maps: Loc 2: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1] +; STACKMAPS-NEXT: Stack Maps: Loc 3: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1] +; STACKMAPS-NEXT: Stack Maps: has 0 live-out registers +; STACKMAPS-NEXT: Stack Maps: callsite 2882400015 +; STACKMAPS-NEXT: Stack Maps: has 4 locations +; STACKMAPS-NEXT: Stack Maps: Loc 0: Constant 12 [encoding: .byte 4, .byte 8, .short 0, .int 12] +; STACKMAPS-NEXT: Stack Maps: Loc 1: Constant 0 [encoding: .byte 4, .byte 8, .short 0, .int 0] +; STACKMAPS-NEXT: Stack Maps: Loc 2: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1] +; STACKMAPS-NEXT: Stack Maps: Loc 3: Constant 3 [encoding: .byte 4, .byte 8, .short 0, .int 3] +; STACKMAPS-NEXT: Stack Maps: has 0 live-out registers