Add lowering support for llvm.experimental.deoptimize
authorSanjoy Das <sanjoy@playingwithpointers.com>
Thu, 24 Mar 2016 20:23:29 +0000 (20:23 +0000)
committerSanjoy Das <sanjoy@playingwithpointers.com>
Thu, 24 Mar 2016 20:23:29 +0000 (20:23 +0000)
Summary:
Only adds support for "naked" calls to llvm.experimental.deoptimize.
Support for round-tripping through RewriteStatepointsForGC will come
as a separate patch (should be simpler than this one).

Reviewers: reames

Subscribers: sanjoy, mcrosier, llvm-commits

Differential Revision: http://reviews.llvm.org/D18429

llvm-svn: 264329

llvm/docs/LangRef.rst
llvm/include/llvm/CodeGen/RuntimeLibcalls.h
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
llvm/lib/CodeGen/TargetLoweringBase.cpp
llvm/test/CodeGen/X86/deopt-intrinsic.ll [new file with mode: 0644]

index 4316848..01c255d 100644 (file)
@@ -12169,8 +12169,12 @@ intrinsic to return directly from the frame of the function it inlined into.
 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 8beb55d..bdf8d9c 100644 (file)
@@ -401,6 +401,9 @@ namespace RTLIB {
     // Stack Protector Fail.
     STACKPROTECTOR_CHECK_FAIL,
 
+    // Deoptimization.
+    DEOPTIMIZE,
+
     UNKNOWN_LIBCALL
   };
 
index 6f65361..5126bde 100644 (file)
@@ -5460,6 +5460,10 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
     setValue(&I, N);
     return nullptr;
   }
+
+  case Intrinsic::experimental_deoptimize:
+    LowerDeoptimizeCall(&I);
+    return nullptr;
   }
 }
 
index eebae0d..4b222a9 100644 (file)
@@ -781,6 +781,8 @@ public:
   void LowerCallSiteWithDeoptBundle(ImmutableCallSite CS, SDValue Callee,
                                     const BasicBlock *EHPadBB);
 
+  void LowerDeoptimizeCall(const CallInst *CI);
+
 private:
   // Terminator instructions.
   void visitRet(const ReturnInst &I);
index f50d7d0..bf9f1fa 100644 (file)
@@ -923,3 +923,37 @@ void SelectionDAGBuilder::visitGCRelocate(const GCRelocateInst &Relocate) {
   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<const Use>(DeoptBundle.Inputs.begin(), DeoptBundle.Inputs.end());
+  SI.StatepointFlags = static_cast<uint64_t>(StatepointFlags::None);
+
+  // NB! The GC arguments are specifically left empty.
+
+  if (SDValue ReturnVal = LowerAsSTATEPOINT(SI)) {
+    ReturnVal = lowerRangeToAssertZExt(DAG, *CI, ReturnVal);
+    setValue(CI, ReturnVal);
+  }
+}
index d714ad1..747950f 100644 (file)
@@ -435,6 +435,8 @@ static void InitLibcallNames(const char **Names, const Triple &TT) {
     Names[RTLIB::FPEXT_F16_F32] = "__extendhfsf2";
     Names[RTLIB::FPROUND_F32_F16] = "__truncsfhf2";
   }
+
+  Names[RTLIB::DEOPTIMIZE] = "__llvm_deoptimize";
 }
 
 /// InitLibcallCallingConvs - Set default libcall CallingConvs.
diff --git a/llvm/test/CodeGen/X86/deopt-intrinsic.ll b/llvm/test/CodeGen/X86/deopt-intrinsic.ll
new file mode 100644 (file)
index 0000000..044e1c0
--- /dev/null
@@ -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