diff options
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 3 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp | 52 | ||||
| -rw-r--r-- | llvm/test/CodeGen/X86/statepoint-call-lowering.ll | 25 | 
3 files changed, 56 insertions, 24 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 8d04f47fa96..75b2960bb37 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -899,7 +899,8 @@ void SelectionDAGBuilder::visit(const Instruction &I) {    visit(I.getOpcode(), I); -  if (!isa<TerminatorInst>(&I) && !HasTailCall) +  if (!isa<TerminatorInst>(&I) && !HasTailCall && +      !isStatepoint(&I)) // statepoints handle their exports internally      CopyToExportRegsIfNeeded(&I);    CurInst = nullptr; diff --git a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp index 0bfa89d2ba1..05024063392 100644 --- a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp @@ -343,13 +343,17 @@ lowerCallFromStatepoint(ImmutableStatepoint ISP, const BasicBlock *EHPadBB,    assert(CallEnd->getOpcode() == ISD::CALLSEQ_END && "expected!"); -  if (HasDef) { -    if (CS.isInvoke()) { -      // Result value will be used in different basic block for invokes -      // so we need to export it now. But statepoint call has a different type -      // than the actual call. It means that standard exporting mechanism will -      // create register of the wrong type. So instead we need to create -      // register with correct type and save value into it manually. +  // Export the result value if needed +  const Instruction *GCResult = ISP.getGCResult(); +  if (HasDef && GCResult) { +    if (GCResult->getParent() != CS.getParent()) { +      // Result value will be used in a different basic block so we need to +      // export it now. +      // Default exporting mechanism will not work here because statepoint call +      // has a different type than the actual call. It means that by default +      // llvm will create export register of the wrong type (always i32 in our +      // case). So instead we need to create export register with correct type +      // manually.        // TODO: To eliminate this problem we can remove gc.result intrinsics        //       completely and make statepoint call to return a tuple.        unsigned Reg = Builder.FuncInfo.CreateRegs(ISP.getActualReturnType()); @@ -363,8 +367,9 @@ lowerCallFromStatepoint(ImmutableStatepoint ISP, const BasicBlock *EHPadBB,        PendingExports.push_back(Chain);        Builder.FuncInfo.ValueMap[CS.getInstruction()] = Reg;      } else { -      // The value of the statepoint itself will be the value of call itself. -      // We'll replace the actually call node shortly.  gc_result will grab +      // Result value will be used in a same basic block. Don't export it or +      // perform any explicit register copies. +      // We'll replace the actuall call node shortly. gc_result will grab        // this value.        Builder.setValue(CS.getInstruction(), ReturnValue);      } @@ -611,7 +616,8 @@ static void lowerStatepointMetaArgs(SmallVectorImpl<SDValue> &Ops,        // uses of the corresponding values so that it would automatically        // export them. Relocates of the spilled values does not use original        // value. -      if (StatepointSite.getCallSite().isInvoke()) +      if (RelocateOpers.getUnderlyingCallSite().getParent() != +          StatepointInstr->getParent())          Builder.ExportFromCurrentBlock(V);      }    } @@ -638,14 +644,12 @@ void SelectionDAGBuilder::LowerStatepoint(    ImmutableCallSite CS(ISP.getCallSite());  #ifndef NDEBUG -  // Consistency check. Don't do this for invokes. It would be too -  // expensive to preserve this information across different basic blocks -  if (!CS.isInvoke()) { -    for (const User *U : CS->users()) { -      const CallInst *Call = cast<CallInst>(U); -      if (isGCRelocate(Call)) -        StatepointLowering.scheduleRelocCall(*Call); -    } +  // Consistency check. Check only relocates in the same basic block as thier +  // statepoint. +  for (const User *U : CS->users()) { +    const CallInst *Call = cast<CallInst>(U); +    if (isGCRelocate(Call) && Call->getParent() == CS.getParent()) +      StatepointLowering.scheduleRelocCall(*Call);    }  #endif @@ -827,8 +831,9 @@ void SelectionDAGBuilder::visitGCResult(const CallInst &CI) {    Instruction *I = cast<Instruction>(CI.getArgOperand(0));    assert(isStatepoint(I) && "first argument must be a statepoint token"); -  if (isa<InvokeInst>(I)) { -    // For invokes we should have stored call result in a virtual register. +  if (I->getParent() != CI.getParent()) { +    // Statepoint is in different basic block so we should have stored call +    // result in a virtual register.      // We can not use default getValue() functionality to copy value from this      // register because statepoint and actuall call return types can be      // different, and getValue() will use CopyFromReg of the wrong type, @@ -851,9 +856,10 @@ void SelectionDAGBuilder::visitGCRelocate(const CallInst &CI) {  #ifndef NDEBUG    // Consistency check -  // We skip this check for invoke statepoints. It would be too expensive to -  // preserve validation info through different basic blocks. -  if (!RelocateOpers.isTiedToInvoke()) { +  // We skip this check for relocates not in the same basic block as thier +  // statepoint. It would be too expensive to preserve validation info through +  // different basic blocks. +  if (RelocateOpers.getStatepoint()->getParent() == CI.getParent()) {      StatepointLowering.relocCallVisited(CI);    }  #endif diff --git a/llvm/test/CodeGen/X86/statepoint-call-lowering.ll b/llvm/test/CodeGen/X86/statepoint-call-lowering.ll index 8f352b7728c..46d3cafa35b 100644 --- a/llvm/test/CodeGen/X86/statepoint-call-lowering.ll +++ b/llvm/test/CodeGen/X86/statepoint-call-lowering.ll @@ -100,6 +100,31 @@ entry:    ret i1 %call1  } +declare void @consume(i32 addrspace(1)* %obj) + +define i1 @test_cross_bb(i32 addrspace(1)* %a, i1 %external_cond) gc "statepoint-example" { +; CHECK-LABEL: test_cross_bb +; CHECK: movq +; CHECK: callq return_i1 +; CHECK: %left +; CHECK: movq +; CHECK-NEXT: callq consume +; CHECK: retq +entry: +  %safepoint_token = tail call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %a) +  br i1 %external_cond, label %left, label %right + +left: +  %call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token,  i32 7, i32 7) +  %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(i32 %safepoint_token) +  call void @consume(i32 addrspace(1)* %call1) +  ret i1 %call2 + +right: +  ret i1 true +} + +  declare i32 @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...)  declare i1 @llvm.experimental.gc.result.i1(i32)  | 

