[PATCH] D106426: [FuncSpec] Support specialising recursive functions
Chuanqi Xu via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 27 01:40:24 PDT 2021
ChuanqiXu added a comment.
In D106426#2906622 <https://reviews.llvm.org/D106426#2906622>, @SjoerdMeijer wrote:
> In D106426#2906213 <https://reviews.llvm.org/D106426#2906213>, @ChuanqiXu wrote:
>
>> 4 times is an arbitrary number. I thought the best would be 1 time only. But I worried if it is too strict. So I said 4 times. Now I think we should be more strict. So I think it would better to specialize it only 1 time.
>
> I can't follow any this. There are only arbitrary numbers here. I can't follow the decision making behind this, because no rationale is given.
> Taking your example, specialising 4 times, and after cleanup passes like inline, instcombine, and simplify cfg, this would exactly give the code I would expect.
> And that's the problem of this discussion, it is based on a idea, and not based on an any data that we can verify. For *this* example, I don't see which high level criteria is the problem:
>
> - compile-times,
> - code-size,
> - performance.
>
>>> how things work for recursive function, I think we need to discuss how the cost-model changes would look like
>>
>> I think we need to handle recursive function specially. Since it is common that recursive function f and its specialized one f' have the same cost and bonus. We need to record the function specialized (and specialized argument). Then we need to specialize a function (for specific argument) we had specialized, we could forbid it or give it a much higher penalty. The detail is missing. But the key point is that we need to handle recursive function specially instead of tuning or refactoring the cost model.
>
> To help this discussion and make this concrete, can you take your own example, and point exactly on what code-generation criteria I mentioned before you would like to specialise this only once?
>
> The problem I have with this discussion is that it is based on an idea that I cannot verify with data. While I understand the general idea, perhaps, and implementing a penalty is easy but I simply don't know what that should be. I can put a random/arbitrary number in, but why would we do that? That's why I still prefer the approach of getting this foundation in place, because it is opt-in, then we can tune this further.
Hi, for this example:
; opt -function-specialization -func-specialization-max-iters=100 -S %s
@Global = internal constant i32 1, align 4
define internal void @recursiveFunc(i32* nocapture readonly %arg) {
%temp = alloca i32, align 4
%arg.load = load i32, i32* %arg, align 4
%arg.cmp = icmp slt i32 %arg.load, 10000
br i1 %arg.cmp, label %loop1, label %ret.block
loop1:
br label %loop2
loop2:
br label %loop3
loop3:
br label %loop4
loop4:
br label %block6
block6:
call void @print_val(i32 %arg.load)
%arg.add = add nsw i32 %arg.load, 1
store i32 %arg.add, i32* %temp, align 4
call void @recursiveFunc(i32* nonnull %temp)
br label %loop4.end
loop4.end:
%exit_cond1 = call i1 @exit_cond()
br i1 %exit_cond1, label %loop4, label %loop3.end
loop3.end:
%exit_cond2 = call i1 @exit_cond()
br i1 %exit_cond2, label %loop3, label %loop2.end
loop2.end:
%exit_cond3 = call i1 @exit_cond()
br i1 %exit_cond3, label %loop2, label %loop1.end
loop1.end:
%exit_cond4 = call i1 @exit_cond()
br i1 %exit_cond4, label %loop1, label %ret.block
ret.block:
ret void
}
define i32 @main() {
call void @recursiveFunc(i32* nonnull @Global)
ret i32 0
}
declare dso_local void @print_val(i32)
declare dso_local i1 @exit_cond()
If we run `bin/opt -function-specialization -func-specialization-max-iters=10 -S %s`, we could find that `recursiveFunc` would get specialized 18 times. But I believe it would be a consensus for us that `recursiveFunc ` shouldn't get specialized so many times.
Then I run `bin/opt -function-specialization -func-specialization-max-iters=10 -inline -instcombine -simplifycfg -S %s`, I got:
; ModuleID = 'RecursiveFunc.ll'
source_filename = "RecursiveFunc.ll"
@Global = internal constant i32 1, align 4
@funcspec.arg = internal constant i32 2
@funcspec.arg.3 = internal constant i32 3
@funcspec.arg.5 = internal constant i32 4
@funcspec.arg.7 = internal constant i32 5
@funcspec.arg.9 = internal constant i32 6
@funcspec.arg.11 = internal constant i32 7
@funcspec.arg.13 = internal constant i32 8
@funcspec.arg.15 = internal constant i32 9
@funcspec.arg.17 = internal constant i32 10
@funcspec.arg.19 = internal constant i32 11
define internal void @recursiveFunc(i32* nocapture readonly %arg) {
%temp = alloca i32, align 4
%arg.load = load i32, i32* %arg, align 4
%arg.cmp = icmp slt i32 %arg.load, 10000
br i1 %arg.cmp, label %loop1, label %ret.block
loop1: ; preds = %loop1.end, %0
br label %loop2
loop2: ; preds = %loop2.end, %loop1
br label %loop3
loop3: ; preds = %loop3.end, %loop2
br label %loop4
loop4: ; preds = %loop4, %loop3
call void @print_val(i32 %arg.load)
%arg.add = add nsw i32 %arg.load, 1
store i32 %arg.add, i32* %temp, align 4
call void @recursiveFunc(i32* nonnull %temp)
%exit_cond1 = call i1 @exit_cond()
br i1 %exit_cond1, label %loop4, label %loop3.end
loop3.end: ; preds = %loop4
%exit_cond2 = call i1 @exit_cond()
br i1 %exit_cond2, label %loop3, label %loop2.end
loop2.end: ; preds = %loop3.end
%exit_cond3 = call i1 @exit_cond()
br i1 %exit_cond3, label %loop2, label %loop1.end
loop1.end: ; preds = %loop2.end
%exit_cond4 = call i1 @exit_cond()
br i1 %exit_cond4, label %loop1, label %ret.block
ret.block: ; preds = %loop1.end, %0
ret void
}
define i32 @main() {
br label %loop1.i
loop1.i: ; preds = %loop1.end.i, %0
br label %loop2.i
loop2.i: ; preds = %loop2.end.i, %loop1.i
br label %loop3.i
loop3.i: ; preds = %loop3.end.i, %loop2.i
br label %loop4.i
loop4.i: ; preds = %recursiveFunc.2.exit.i, %loop3.i
call void @print_val(i32 1)
br label %loop1.i.i
loop1.i.i: ; preds = %loop1.end.i.i, %loop4.i
br label %loop2.i.i
loop2.i.i: ; preds = %loop2.end.i.i, %loop1.i.i
br label %loop3.i.i
loop3.i.i: ; preds = %loop3.end.i.i, %loop2.i.i
br label %loop4.i.i
loop4.i.i: ; preds = %recursiveFunc.4.exit.i.i, %loop3.i.i
call void @print_val(i32 2)
br label %loop1.i.i.i
loop1.i.i.i: ; preds = %loop1.end.i.i.i, %loop4.i.i
br label %loop2.i.i.i
loop2.i.i.i: ; preds = %loop2.end.i.i.i, %loop1.i.i.i
br label %loop3.i.i.i
loop3.i.i.i: ; preds = %loop3.end.i.i.i, %loop2.i.i.i
br label %loop4.i.i.i
loop4.i.i.i: ; preds = %recursiveFunc.6.exit.i.i.i, %loop3.i.i.i
call void @print_val(i32 3)
br label %loop1.i.i.i.i
loop1.i.i.i.i: ; preds = %loop1.end.i.i.i.i, %loop4.i.i.i
br label %loop2.i.i.i.i
loop2.i.i.i.i: ; preds = %loop2.end.i.i.i.i, %loop1.i.i.i.i
br label %loop3.i.i.i.i
loop3.i.i.i.i: ; preds = %loop3.end.i.i.i.i, %loop2.i.i.i.i
br label %loop4.i.i.i.i
loop4.i.i.i.i: ; preds = %recursiveFunc.8.exit.i.i.i.i, %loop3.i.i.i.i
call void @print_val(i32 4)
br label %loop1.i.i.i.i.i
loop1.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i, %loop4.i.i.i.i
br label %loop2.i.i.i.i.i
loop2.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i, %loop1.i.i.i.i.i
br label %loop3.i.i.i.i.i
loop3.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i, %loop2.i.i.i.i.i
br label %loop4.i.i.i.i.i
loop4.i.i.i.i.i: ; preds = %recursiveFunc.10.exit.i.i.i.i.i, %loop3.i.i.i.i.i
call void @print_val(i32 5)
br label %loop1.i.i.i.i.i.i
loop1.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i, %loop4.i.i.i.i.i
br label %loop2.i.i.i.i.i.i
loop2.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i, %loop1.i.i.i.i.i.i
br label %loop3.i.i.i.i.i.i
loop3.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i, %loop2.i.i.i.i.i.i
br label %loop4.i.i.i.i.i.i
loop4.i.i.i.i.i.i: ; preds = %recursiveFunc.12.exit.i.i.i.i.i.i, %loop3.i.i.i.i.i.i
call void @print_val(i32 6)
br label %loop1.i.i.i.i.i.i.i
loop1.i.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i.i, %loop4.i.i.i.i.i.i
br label %loop2.i.i.i.i.i.i.i
loop2.i.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i.i, %loop1.i.i.i.i.i.i.i
br label %loop3.i.i.i.i.i.i.i
loop3.i.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i.i, %loop2.i.i.i.i.i.i.i
br label %loop4.i.i.i.i.i.i.i
loop4.i.i.i.i.i.i.i: ; preds = %recursiveFunc.14.exit.i.i.i.i.i.i.i, %loop3.i.i.i.i.i.i.i
call void @print_val(i32 7)
br label %loop1.i.i.i.i.i.i.i.i
loop1.i.i.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i.i.i, %loop4.i.i.i.i.i.i.i
br label %loop2.i.i.i.i.i.i.i.i
loop2.i.i.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i.i.i, %loop1.i.i.i.i.i.i.i.i
br label %loop3.i.i.i.i.i.i.i.i
loop3.i.i.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i.i.i, %loop2.i.i.i.i.i.i.i.i
br label %loop4.i.i.i.i.i.i.i.i
loop4.i.i.i.i.i.i.i.i: ; preds = %recursiveFunc.16.exit.i.i.i.i.i.i.i.i, %loop3.i.i.i.i.i.i.i.i
call void @print_val(i32 8)
br label %loop1.i.i.i.i.i.i.i.i.i
loop1.i.i.i.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i.i.i.i, %loop4.i.i.i.i.i.i.i.i
br label %loop2.i.i.i.i.i.i.i.i.i
loop2.i.i.i.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i.i.i.i, %loop1.i.i.i.i.i.i.i.i.i
br label %loop3.i.i.i.i.i.i.i.i.i
loop3.i.i.i.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i.i.i.i, %loop2.i.i.i.i.i.i.i.i.i
br label %loop4.i.i.i.i.i.i.i.i.i
loop4.i.i.i.i.i.i.i.i.i: ; preds = %recursiveFunc.18.exit.i.i.i.i.i.i.i.i.i, %loop3.i.i.i.i.i.i.i.i.i
call void @print_val(i32 9)
br label %loop1.i.i.i.i.i.i.i.i.i.i
loop1.i.i.i.i.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i.i.i.i.i, %loop4.i.i.i.i.i.i.i.i.i
br label %loop2.i.i.i.i.i.i.i.i.i.i
loop2.i.i.i.i.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i.i.i.i.i, %loop1.i.i.i.i.i.i.i.i.i.i
br label %loop3.i.i.i.i.i.i.i.i.i.i
loop3.i.i.i.i.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i.i.i.i.i, %loop2.i.i.i.i.i.i.i.i.i.i
br label %loop4.i.i.i.i.i.i.i.i.i.i
loop4.i.i.i.i.i.i.i.i.i.i: ; preds = %loop4.i.i.i.i.i.i.i.i.i.i, %loop3.i.i.i.i.i.i.i.i.i.i
call void @print_val(i32 10)
call void @recursiveFunc(i32* nonnull @funcspec.arg.19)
%exit_cond1.i.i.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i.i.i.i.i.i.i.i.i, label %loop4.i.i.i.i.i.i.i.i.i.i, label %loop3.end.i.i.i.i.i.i.i.i.i.i
loop3.end.i.i.i.i.i.i.i.i.i.i: ; preds = %loop4.i.i.i.i.i.i.i.i.i.i
%exit_cond2.i.i.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i.i.i.i.i.i.i.i.i, label %loop3.i.i.i.i.i.i.i.i.i.i, label %loop2.end.i.i.i.i.i.i.i.i.i.i
loop2.end.i.i.i.i.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i.i.i.i.i
%exit_cond3.i.i.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i.i.i.i.i.i.i.i.i, label %loop2.i.i.i.i.i.i.i.i.i.i, label %loop1.end.i.i.i.i.i.i.i.i.i.i
loop1.end.i.i.i.i.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i.i.i.i.i
%exit_cond4.i.i.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i.i.i.i.i.i.i.i.i, label %loop1.i.i.i.i.i.i.i.i.i.i, label %recursiveFunc.18.exit.i.i.i.i.i.i.i.i.i
recursiveFunc.18.exit.i.i.i.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i.i.i.i.i
%exit_cond1.i.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i.i.i.i.i.i.i.i, label %loop4.i.i.i.i.i.i.i.i.i, label %loop3.end.i.i.i.i.i.i.i.i.i
loop3.end.i.i.i.i.i.i.i.i.i: ; preds = %recursiveFunc.18.exit.i.i.i.i.i.i.i.i.i
%exit_cond2.i.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i.i.i.i.i.i.i.i, label %loop3.i.i.i.i.i.i.i.i.i, label %loop2.end.i.i.i.i.i.i.i.i.i
loop2.end.i.i.i.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i.i.i.i
%exit_cond3.i.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i.i.i.i.i.i.i.i, label %loop2.i.i.i.i.i.i.i.i.i, label %loop1.end.i.i.i.i.i.i.i.i.i
loop1.end.i.i.i.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i.i.i.i
%exit_cond4.i.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i.i.i.i.i.i.i.i, label %loop1.i.i.i.i.i.i.i.i.i, label %recursiveFunc.16.exit.i.i.i.i.i.i.i.i
recursiveFunc.16.exit.i.i.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i.i.i.i
%exit_cond1.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i.i.i.i.i.i.i, label %loop4.i.i.i.i.i.i.i.i, label %loop3.end.i.i.i.i.i.i.i.i
loop3.end.i.i.i.i.i.i.i.i: ; preds = %recursiveFunc.16.exit.i.i.i.i.i.i.i.i
%exit_cond2.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i.i.i.i.i.i.i, label %loop3.i.i.i.i.i.i.i.i, label %loop2.end.i.i.i.i.i.i.i.i
loop2.end.i.i.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i.i.i
%exit_cond3.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i.i.i.i.i.i.i, label %loop2.i.i.i.i.i.i.i.i, label %loop1.end.i.i.i.i.i.i.i.i
loop1.end.i.i.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i.i.i
%exit_cond4.i.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i.i.i.i.i.i.i, label %loop1.i.i.i.i.i.i.i.i, label %recursiveFunc.14.exit.i.i.i.i.i.i.i
recursiveFunc.14.exit.i.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i.i.i
%exit_cond1.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i.i.i.i.i.i, label %loop4.i.i.i.i.i.i.i, label %loop3.end.i.i.i.i.i.i.i
loop3.end.i.i.i.i.i.i.i: ; preds = %recursiveFunc.14.exit.i.i.i.i.i.i.i
%exit_cond2.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i.i.i.i.i.i, label %loop3.i.i.i.i.i.i.i, label %loop2.end.i.i.i.i.i.i.i
loop2.end.i.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i.i
%exit_cond3.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i.i.i.i.i.i, label %loop2.i.i.i.i.i.i.i, label %loop1.end.i.i.i.i.i.i.i
loop1.end.i.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i.i
%exit_cond4.i.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i.i.i.i.i.i, label %loop1.i.i.i.i.i.i.i, label %recursiveFunc.12.exit.i.i.i.i.i.i
recursiveFunc.12.exit.i.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i.i
%exit_cond1.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i.i.i.i.i, label %loop4.i.i.i.i.i.i, label %loop3.end.i.i.i.i.i.i
loop3.end.i.i.i.i.i.i: ; preds = %recursiveFunc.12.exit.i.i.i.i.i.i
%exit_cond2.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i.i.i.i.i, label %loop3.i.i.i.i.i.i, label %loop2.end.i.i.i.i.i.i
loop2.end.i.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i.i
%exit_cond3.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i.i.i.i.i, label %loop2.i.i.i.i.i.i, label %loop1.end.i.i.i.i.i.i
loop1.end.i.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i.i
%exit_cond4.i.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i.i.i.i.i, label %loop1.i.i.i.i.i.i, label %recursiveFunc.10.exit.i.i.i.i.i
recursiveFunc.10.exit.i.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i.i
%exit_cond1.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i.i.i.i, label %loop4.i.i.i.i.i, label %loop3.end.i.i.i.i.i
loop3.end.i.i.i.i.i: ; preds = %recursiveFunc.10.exit.i.i.i.i.i
%exit_cond2.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i.i.i.i, label %loop3.i.i.i.i.i, label %loop2.end.i.i.i.i.i
loop2.end.i.i.i.i.i: ; preds = %loop3.end.i.i.i.i.i
%exit_cond3.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i.i.i.i, label %loop2.i.i.i.i.i, label %loop1.end.i.i.i.i.i
loop1.end.i.i.i.i.i: ; preds = %loop2.end.i.i.i.i.i
%exit_cond4.i.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i.i.i.i, label %loop1.i.i.i.i.i, label %recursiveFunc.8.exit.i.i.i.i
recursiveFunc.8.exit.i.i.i.i: ; preds = %loop1.end.i.i.i.i.i
%exit_cond1.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i.i.i, label %loop4.i.i.i.i, label %loop3.end.i.i.i.i
loop3.end.i.i.i.i: ; preds = %recursiveFunc.8.exit.i.i.i.i
%exit_cond2.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i.i.i, label %loop3.i.i.i.i, label %loop2.end.i.i.i.i
loop2.end.i.i.i.i: ; preds = %loop3.end.i.i.i.i
%exit_cond3.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i.i.i, label %loop2.i.i.i.i, label %loop1.end.i.i.i.i
loop1.end.i.i.i.i: ; preds = %loop2.end.i.i.i.i
%exit_cond4.i.i.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i.i.i, label %loop1.i.i.i.i, label %recursiveFunc.6.exit.i.i.i
recursiveFunc.6.exit.i.i.i: ; preds = %loop1.end.i.i.i.i
%exit_cond1.i.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i.i, label %loop4.i.i.i, label %loop3.end.i.i.i
loop3.end.i.i.i: ; preds = %recursiveFunc.6.exit.i.i.i
%exit_cond2.i.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i.i, label %loop3.i.i.i, label %loop2.end.i.i.i
loop2.end.i.i.i: ; preds = %loop3.end.i.i.i
%exit_cond3.i.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i.i, label %loop2.i.i.i, label %loop1.end.i.i.i
loop1.end.i.i.i: ; preds = %loop2.end.i.i.i
%exit_cond4.i.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i.i, label %loop1.i.i.i, label %recursiveFunc.4.exit.i.i
recursiveFunc.4.exit.i.i: ; preds = %loop1.end.i.i.i
%exit_cond1.i.i = call i1 @exit_cond()
br i1 %exit_cond1.i.i, label %loop4.i.i, label %loop3.end.i.i
loop3.end.i.i: ; preds = %recursiveFunc.4.exit.i.i
%exit_cond2.i.i = call i1 @exit_cond()
br i1 %exit_cond2.i.i, label %loop3.i.i, label %loop2.end.i.i
loop2.end.i.i: ; preds = %loop3.end.i.i
%exit_cond3.i.i = call i1 @exit_cond()
br i1 %exit_cond3.i.i, label %loop2.i.i, label %loop1.end.i.i
loop1.end.i.i: ; preds = %loop2.end.i.i
%exit_cond4.i.i = call i1 @exit_cond()
br i1 %exit_cond4.i.i, label %loop1.i.i, label %recursiveFunc.2.exit.i
recursiveFunc.2.exit.i: ; preds = %loop1.end.i.i
%exit_cond1.i = call i1 @exit_cond()
br i1 %exit_cond1.i, label %loop4.i, label %loop3.end.i
loop3.end.i: ; preds = %recursiveFunc.2.exit.i
%exit_cond2.i = call i1 @exit_cond()
br i1 %exit_cond2.i, label %loop3.i, label %loop2.end.i
loop2.end.i: ; preds = %loop3.end.i
%exit_cond3.i = call i1 @exit_cond()
br i1 %exit_cond3.i, label %loop2.i, label %loop1.end.i
loop1.end.i: ; preds = %loop2.end.i
%exit_cond4.i = call i1 @exit_cond()
br i1 %exit_cond4.i, label %loop1.i, label %recursiveFunc.1.exit
recursiveFunc.1.exit: ; preds = %loop1.end.i
ret i32 0
}
declare dso_local void @print_val(i32)
declare dso_local i1 @exit_cond()
; Function Attrs: argmemonly nofree nosync nounwind willreturn
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #0
; Function Attrs: argmemonly nofree nosync nounwind willreturn
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #0
attributes #0 = { argmemonly nofree nosync nounwind willreturn }
hmmmm, I guess it must not be your expected code, right?
> For *this* example, I don't see which high level criteria is the problem:
> compile-times,
> code-size,
> performance.
I think all of them would be affected. The impact on code-size is obvious. For the compile-time, it would take a long time to compile if we set the argument `func-specialization-max-iters` to 2000.
> That's why I still prefer the approach of getting this foundation in place, because it is opt-in, then we can tune this further.
I prefer to use small program to analysis. My work flow to optimize would be :
Run big workloads -> analysis the hot part -> extract small example from the hot part -> optimize for the hot part -> prove the effects with the big workloads.
It is hard to optimize big workloads directly since many details are missing. So I think it may be better to talk about the small example if we can. I mean, we need to take many time to find a small program from workloads to find the insight generally. But if we could talk about the small example directly, it would be much better.
> I can't follow any this. There are only arbitrary numbers here. I can't follow the decision making behind this, because no rationale is given.
My bad. I mean we shouldn't make `recursiveFunc` arbitrarily. The limit number may get discussed more.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D106426/new/
https://reviews.llvm.org/D106426
More information about the llvm-commits
mailing list