Index: lib/Transforms/Scalar/CallSiteSplitting.cpp =================================================================== --- lib/Transforms/Scalar/CallSiteSplitting.cpp +++ lib/Transforms/Scalar/CallSiteSplitting.cpp @@ -183,6 +183,9 @@ } static bool canSplitCallSite(CallSite CS, TargetTransformInfo &TTI) { + if (CS.isConvergent() || CS.cannotDuplicate()) + return false; + // FIXME: As of now we handle only CallInst. InvokeInst could be handled // without too much effort. Instruction *Instr = CS.getInstruction(); Index: test/Transforms/CallSiteSplitting/convergent.ll =================================================================== --- /dev/null +++ test/Transforms/CallSiteSplitting/convergent.ll @@ -0,0 +1,197 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -callsite-splitting -callsite-splitting-duplication-threshold=100000000 < %s | FileCheck --check-prefix=CHECK %s + +; Convergent calls should not be duplicated in this case +define void @convergent_caller(i1 %c, i8* %a_elt, i8* %b_elt) #0 { +; CHECK-LABEL: @convergent_caller( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[TOP:%.*]] +; CHECK: Top: +; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i8* [[A_ELT:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[CALLSITEBB:%.*]], label [[NEXTCOND:%.*]] +; CHECK: NextCond: +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8* [[B_ELT:%.*]], null +; CHECK-NEXT: br i1 [[CMP]], label [[CALLSITEBB]], label [[END:%.*]] +; CHECK: CallSiteBB: +; CHECK-NEXT: [[P:%.*]] = phi i1 [ false, [[TOP]] ], [ [[C:%.*]], [[NEXTCOND]] ] +; CHECK-NEXT: call void @convergent_callee(i8* [[A_ELT]], i1 [[P]]) +; CHECK-NEXT: br label [[END]] +; CHECK: End: +; CHECK-NEXT: ret void +; +entry: + br label %Top + +Top: + %tobool1 = icmp eq i8* %a_elt, null + br i1 %tobool1, label %CallSiteBB, label %NextCond + +NextCond: + %cmp = icmp ne i8* %b_elt, null + br i1 %cmp, label %CallSiteBB, label %End + +CallSiteBB: + %p = phi i1 [ false, %Top ], [ %c, %NextCond ] + call void @convergent_callee(i8* %a_elt, i1 %p) + br label %End + +End: + ret void +} + +define void @convergent_callee(i8* %a_elt, i1 %c) #0 { +; CHECK-LABEL: @convergent_callee( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[A_ELT:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[ENDIF:%.*]] +; CHECK: then: +; CHECK-NEXT: br label [[ENDIF]] +; CHECK: endif: +; CHECK-NEXT: call void @convergent_external(i8* [[A_ELT]]) #0 +; CHECK-NEXT: ret void +; +entry: + %tobool = icmp ne i8* %a_elt, null + br i1 %tobool, label %then, label %endif + +then: + br label %endif + +endif: + call void @convergent_external(i8* %a_elt) #0 + ret void +} + +; Noduplicate calls should not be duplicated +define void @noduplicate_caller(i1 %c, i8* %a_elt, i8* %b_elt) #2 { +; CHECK-LABEL: @noduplicate_caller( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[TOP:%.*]] +; CHECK: Top: +; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i8* [[A_ELT:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[CALLSITEBB:%.*]], label [[NEXTCOND:%.*]] +; CHECK: NextCond: +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8* [[B_ELT:%.*]], null +; CHECK-NEXT: br i1 [[CMP]], label [[CALLSITEBB]], label [[END:%.*]] +; CHECK: CallSiteBB: +; CHECK-NEXT: [[P:%.*]] = phi i1 [ false, [[TOP]] ], [ [[C:%.*]], [[NEXTCOND]] ] +; CHECK-NEXT: call void @noduplicate_callee(i8* [[A_ELT]], i1 [[P]]) +; CHECK-NEXT: br label [[END]] +; CHECK: End: +; CHECK-NEXT: ret void +; +entry: + br label %Top + +Top: + %tobool1 = icmp eq i8* %a_elt, null + br i1 %tobool1, label %CallSiteBB, label %NextCond + +NextCond: + %cmp = icmp ne i8* %b_elt, null + br i1 %cmp, label %CallSiteBB, label %End + +CallSiteBB: + %p = phi i1 [ false, %Top ], [ %c, %NextCond ] + call void @noduplicate_callee(i8* %a_elt, i1 %p) + br label %End + +End: + ret void +} + +define void @noduplicate_callee(i8* %a_elt, i1 %c) #2 { +; CHECK-LABEL: @noduplicate_callee( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[A_ELT:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[ENDIF:%.*]] +; CHECK: then: +; CHECK-NEXT: br label [[ENDIF]] +; CHECK: endif: +; CHECK-NEXT: call void @noduplicate_external(i8* [[A_ELT]]) +; CHECK-NEXT: ret void +; +entry: + %tobool = icmp ne i8* %a_elt, null + br i1 %tobool, label %then, label %endif + +then: + br label %endif + +endif: + call void @noduplicate_external(i8* %a_elt) + ret void +} + +; Make sure an otherwise identical function is transformed +define void @reference_caller(i1 %c, i8* %a_elt, i8* %b_elt) #1 { +; CHECK-LABEL: @reference_caller( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[TOP:%.*]] +; CHECK: Top: +; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i8* [[A_ELT:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[TOP_SPLIT:%.*]], label [[NEXTCOND:%.*]] +; CHECK: Top.split: +; CHECK-NEXT: call void @nonconvergent_callee(i8* null, i1 false) +; CHECK-NEXT: br label [[CALLSITEBB:%.*]] +; CHECK: NextCond: +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8* [[B_ELT:%.*]], null +; CHECK-NEXT: br i1 [[CMP]], label [[NEXTCOND_SPLIT:%.*]], label [[END:%.*]] +; CHECK: NextCond.split: +; CHECK-NEXT: call void @nonconvergent_callee(i8* nonnull [[A_ELT]], i1 [[C:%.*]]) +; CHECK-NEXT: br label [[CALLSITEBB]] +; CHECK: CallSiteBB: +; CHECK-NEXT: br label [[END]] +; CHECK: End: +; CHECK-NEXT: ret void +; +entry: + br label %Top + +Top: + %tobool1 = icmp eq i8* %a_elt, null + br i1 %tobool1, label %CallSiteBB, label %NextCond + +NextCond: + %cmp = icmp ne i8* %b_elt, null + br i1 %cmp, label %CallSiteBB, label %End + +CallSiteBB: + %p = phi i1 [ false, %Top ], [ %c, %NextCond ] + call void @nonconvergent_callee(i8* %a_elt, i1 %p) + br label %End + +End: + ret void +} + +define void @nonconvergent_callee(i8* %a_elt, i1 %c) #1 { +; CHECK-LABEL: @nonconvergent_callee( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[A_ELT:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[ENDIF:%.*]] +; CHECK: then: +; CHECK-NEXT: br label [[ENDIF]] +; CHECK: endif: +; CHECK-NEXT: call void @nonconvergent_external(i8* [[A_ELT]]) +; CHECK-NEXT: ret void +; +entry: + %tobool = icmp ne i8* %a_elt, null + br i1 %tobool, label %then, label %endif + +then: + br label %endif + +endif: + call void @nonconvergent_external(i8* %a_elt) + ret void +} + +declare void @convergent_external(i8*) #0 +declare void @nonconvergent_external(i8*) #1 +declare void @noduplicate_external(i8*) #2 + +attributes #0 = { convergent nounwind } +attributes #1 = { nounwind } +attributes #2 = { noduplicate nounwind }