Skip to content

Commit 3263d0c

Browse files
authored
Merge pull request #8705 from eeckstein/fix-merge-funcs
MergeFunctions: now really handle self recursions correctly.
2 parents 7e04474 + f3a7824 commit 3263d0c

File tree

2 files changed

+41
-29
lines changed

2 files changed

+41
-29
lines changed

lib/LLVMPasses/LLVMMergeFunctions.cpp

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -782,31 +782,20 @@ bool SwiftMergeFunctions::deriveParams(ParamInfos &Params,
782782

783783
/// Returns true if the \p OpIdx's constant operand in the current instruction
784784
/// does differ in any of the functions in \p FInfos.
785-
///
786-
/// But it accepts the case where all operands refer to their containing
787-
/// functions (in case of self recursive functions).
788785
bool SwiftMergeFunctions::constsDiffer(const FunctionInfos &FInfos,
789786
unsigned OpIdx) {
790787
Constant *CommonConst = nullptr;
791-
bool matching = true;
792-
bool selfReferencing = true;
793788

794789
for (const FunctionInfo &FI : FInfos) {
795790
Value *Op = FI.CurrentInst->getOperand(OpIdx);
796791
if (Constant *C = dyn_cast<Constant>(Op)) {
797-
if (C != FI.F)
798-
selfReferencing = false;
799-
800792
if (!CommonConst) {
801793
CommonConst = C;
802794
} else if (C != CommonConst) {
803-
matching = false;
804-
}
805-
if (!selfReferencing && !matching)
806795
return true;
796+
}
807797
}
808798
}
809-
assert(selfReferencing || matching);
810799
return false;
811800
}
812801

@@ -895,18 +884,29 @@ void SwiftMergeFunctions::mergeWithParams(const FunctionInfos &FInfos,
895884
OrigArg.replaceAllUsesWith(&NewArg);
896885
}
897886

887+
SmallPtrSet<Function *, 8> SelfReferencingFunctions;
888+
898889
// Replace all differing operands with a parameter.
899890
for (const ParamInfo &PI : Params) {
900891
Argument *NewArg = &*NewArgIter++;
901892
for (const OpLocation &OL : PI.Uses) {
902893
OL.I->setOperand(OL.OpIndex, NewArg);
903894
}
904895
ParamTypes.push_back(PI.Values[0]->getType());
896+
897+
// Collect all functions which are referenced by any parameter.
898+
for (Value *V : PI.Values) {
899+
if (Function *F = dyn_cast<Function>(V))
900+
SelfReferencingFunctions.insert(F);
901+
}
905902
}
906903

907904
for (unsigned FIdx = 0, NumFuncs = FInfos.size(); FIdx < NumFuncs; ++FIdx) {
908905
Function *OrigFunc = FInfos[FIdx].F;
909-
if (replaceDirectCallers(OrigFunc, NewFunction, Params, FIdx)) {
906+
// Don't try to replace all callers of functions which are used as
907+
// parameters because we must not delete such functions.
908+
if (SelfReferencingFunctions.count(OrigFunc) == 0 &&
909+
replaceDirectCallers(OrigFunc, NewFunction, Params, FIdx)) {
910910
// We could replace all uses (and the function is not externally visible),
911911
// so we can delete the original function.
912912
auto Iter = FuncEntries.find(OrigFunc);
@@ -1075,12 +1075,8 @@ bool SwiftMergeFunctions::replaceDirectCallers(Function *Old, Function *New,
10751075
for (const ParamInfo &PI : Params) {
10761076
assert(ParamIdx < NewFuncTy->getNumParams());
10771077
Constant *ArgValue = PI.Values[FuncIdx];
1078-
1079-
// Check if it's a self referencing function. We must not use the old
1080-
// function pointer as argument.
1081-
if (ArgValue == Old)
1082-
ArgValue = New;
1083-
1078+
assert(ArgValue != Old &&
1079+
"should not try to replace all callers of self referencing functions");
10841080
NewArgs.push_back(ArgValue);
10851081
OldParamTypes.push_back(ArgValue->getType());
10861082
++ParamIdx;

test/LLVMPasses/merge_func.ll

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -326,63 +326,79 @@ done:
326326

327327
; Check self recursive functions
328328

329-
; CHECK-NOT: @recursive1(
329+
; CHECK-LABEL: define internal void @recursive1(i32 %x, i32 %y)
330+
; CHECK: tail call void @recursive1_merged(i32 %x, i32 %y, i32* @g1, void (i32, i32)* @recursive1)
331+
; CHECK: ret void
330332
define internal void @recursive1(i32 %x, i32 %y) {
331333
br i1 undef, label %bb1, label %bb2
332334

333335
bb1:
336+
%l = load i32, i32* @g1, align 4
334337
call void @recursive1(i32 %x, i32 %y)
335338
br label %bb2
336339

337340
bb2:
338341
ret void
339342
}
340343

341-
; CHECK-LABEL: define internal void @recursive1_merged(i32, i32)
342-
; CHECK: call void @recursive1_merged(i32 %0, i32 %1)
344+
; CHECK-LABEL: define internal void @recursive2(i32 %x, i32 %y)
345+
; CHECK: tail call void @recursive1_merged(i32 %x, i32 %y, i32* @g2, void (i32, i32)* @recursive2)
343346
; CHECK: ret void
344347
define internal void @recursive2(i32 %x, i32 %y) {
345348
br i1 undef, label %bb1, label %bb2
346349

347350
bb1:
351+
%l = load i32, i32* @g2, align 4
348352
call void @recursive2(i32 %x, i32 %y)
349353
br label %bb2
350354

351355
bb2:
352356
ret void
353357
}
358+
; CHECK-LABEL: define internal void @recursive1_merged(i32, i32, i32*, void (i32, i32)*)
359+
; CHECK: load i32, i32* %2
360+
; CHECK: call void %3(i32 %0, i32 %1)
361+
; CHECK: ret void
362+
354363

355-
; CHECK-LABEL: define internal void @another_recursive_func_merged(i32, void (i32)*)
356-
; CHECK: call void %1(i32 %0)
364+
; CHECK-LABEL: define internal void @another_recursive_func(i32 %x)
365+
; CHECK: tail call void @another_recursive_func_merged(i32 %x, i32* @g1, void (i32)* @another_recursive_func)
357366
; CHECK: ret void
358367
define internal void @another_recursive_func(i32 %x) {
359368
br i1 undef, label %bb1, label %bb2
360369

361370
bb1:
371+
store i32 %x, i32 *@g1, align 4
362372
call void @another_recursive_func(i32 %x)
363373
br label %bb2
364374

365375
bb2:
366376
ret void
367377
}
368-
369378
; CHECK-NOT: @not_really_recursive(
379+
380+
; CHECK-LABEL: define internal void @another_recursive_func_merged(i32, i32*, void (i32)*)
381+
; CHECK: store i32 %0, i32* %1
382+
; CHECK: call void %2(i32 %0)
383+
; CHECK: ret void
370384
define internal void @not_really_recursive(i32 %x) {
371385
br i1 undef, label %bb1, label %bb2
372386

373387
bb1:
388+
store i32 %x, i32 *@g2, align 4
374389
call void @callee1(i32 %x)
375390
br label %bb2
376391

377392
bb2:
378393
ret void
379394
}
395+
; CHECK-NOT: @not_really_recursive(
380396

381397
; CHECK-LABEL: define void @call_recursive_funcs(i32 %x)
382-
; CHECK: call void @recursive1_merged(i32 %x, i32 %x)
383-
; CHECK: call void @recursive1_merged(i32 %x, i32 %x)
384-
; CHECK: call void bitcast (void (i32, void (i32)*)* @another_recursive_func_merged to void (i32, void (i32, void (i32)*)*)*)(i32 %x, void (i32, void (i32)*)* @another_recursive_func_merged)
385-
; CHECK: call void @another_recursive_func_merged(i32 %x, void (i32)* @callee1)
398+
; CHECK: call void @recursive1(i32 %x, i32 %x)
399+
; CHECK: call void @recursive2(i32 %x, i32 %x)
400+
; CHECK: call void @another_recursive_func(i32 %x)
401+
; CHECK: call void @another_recursive_func_merged(i32 %x, i32* @g2, void (i32)* @callee1)
386402
; CHECK: ret void
387403
define void @call_recursive_funcs(i32 %x) {
388404
call void @recursive1(i32 %x, i32 %x)

0 commit comments

Comments
 (0)