forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ArgPromotion] Handle pointer arguments of recursive calls (llvm#78735)
Argument promotion doesn't handle recursive function calls to promote arguments. This patch adds functionality to handle self recursive function calls, i.e. whose SCC size is 1. Due to complexity of ValueTracking in recursive calls with SCC size greater than 1, we bail out in such cases.
- Loading branch information
1 parent
a7fae89
commit 428bed3
Showing
7 changed files
with
525 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
llvm/test/Transforms/ArgumentPromotion/recursion/aggregate-promote-recursive.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes | ||
; RUN: opt < %s -passes=argpromotion -S | FileCheck %s | ||
|
||
%T = type { i32, i32, i32, i32 } | ||
@G = constant %T { i32 0, i32 0, i32 17, i32 25 } | ||
|
||
define internal i32 @test(ptr %p) { | ||
; CHECK-LABEL: define {{[^@]+}}@test | ||
; CHECK-SAME: (i32 [[P_8_VAL:%.*]], i32 [[P_12_VAL:%.*]]) { | ||
; CHECK-NEXT: entry: | ||
; CHECK-NEXT: [[V:%.*]] = add i32 [[P_12_VAL]], [[P_8_VAL]] | ||
; CHECK-NEXT: [[RET:%.*]] = call i32 @test(i32 [[P_8_VAL]], i32 [[P_12_VAL]]) | ||
; CHECK-NEXT: [[ARET:%.*]] = add i32 [[V]], [[RET]] | ||
; CHECK-NEXT: ret i32 [[ARET]] | ||
; | ||
entry: | ||
%a.gep = getelementptr %T, ptr %p, i64 0, i32 3 | ||
%b.gep = getelementptr %T, ptr %p, i64 0, i32 2 | ||
%a = load i32, ptr %a.gep | ||
%b = load i32, ptr %b.gep | ||
%v = add i32 %a, %b | ||
%ret = call i32 @test(ptr %p) | ||
%aret = add i32 %v, %ret | ||
ret i32 %aret | ||
} | ||
|
||
define i32 @caller() { | ||
; CHECK-LABEL: define {{[^@]+}}@caller() { | ||
; CHECK-NEXT: entry: | ||
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr @G, i64 8 | ||
; CHECK-NEXT: [[G_VAL:%.*]] = load i32, ptr [[TMP0]], align 4 | ||
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr @G, i64 12 | ||
; CHECK-NEXT: [[G_VAL1:%.*]] = load i32, ptr [[TMP1]], align 4 | ||
; CHECK-NEXT: [[V:%.*]] = call i32 @test(i32 [[G_VAL]], i32 [[G_VAL1]]) | ||
; CHECK-NEXT: ret i32 [[V]] | ||
; | ||
entry: | ||
%v = call i32 @test(ptr @G) | ||
ret i32 %v | ||
} |
65 changes: 65 additions & 0 deletions
65
llvm/test/Transforms/ArgumentPromotion/recursion/argpromotion-recursion-pr1259.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 | ||
; RUN: opt -S -passes=argpromotion < %s | FileCheck %s | ||
define internal i32 @foo(ptr %x, i32 %n, i32 %m) { | ||
; CHECK-LABEL: define internal i32 @foo( | ||
; CHECK-SAME: i32 [[X_0_VAL:%.*]], i32 [[N:%.*]], i32 [[M:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[N]], 0 | ||
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] | ||
; CHECK: [[COND_TRUE]]: | ||
; CHECK-NEXT: br label %[[RETURN:.*]] | ||
; CHECK: [[COND_FALSE]]: | ||
; CHECK-NEXT: [[SUBVAL:%.*]] = sub i32 [[N]], 1 | ||
; CHECK-NEXT: [[CALLRET:%.*]] = call i32 @foo(i32 [[X_0_VAL]], i32 [[SUBVAL]], i32 [[X_0_VAL]]) | ||
; CHECK-NEXT: [[SUBVAL2:%.*]] = sub i32 [[N]], 2 | ||
; CHECK-NEXT: [[CALLRET2:%.*]] = call i32 @foo(i32 [[X_0_VAL]], i32 [[SUBVAL2]], i32 [[M]]) | ||
; CHECK-NEXT: [[CMP2:%.*]] = add i32 [[CALLRET]], [[CALLRET2]] | ||
; CHECK-NEXT: br label %[[RETURN]] | ||
; CHECK: [[COND_NEXT:.*]]: | ||
; CHECK-NEXT: br label %[[RETURN]] | ||
; CHECK: [[RETURN]]: | ||
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[X_0_VAL]], %[[COND_TRUE]] ], [ [[CMP2]], %[[COND_FALSE]] ], [ poison, %[[COND_NEXT]] ] | ||
; CHECK-NEXT: ret i32 [[RETVAL_0]] | ||
; | ||
entry: | ||
%cmp = icmp ne i32 %n, 0 | ||
br i1 %cmp, label %cond_true, label %cond_false | ||
|
||
cond_true: ; preds = %entry | ||
%val = load i32, ptr %x, align 4 | ||
br label %return | ||
|
||
cond_false: ; preds = %entry | ||
%val2 = load i32, ptr %x, align 4 | ||
%subval = sub i32 %n, 1 | ||
%callret = call i32 @foo(ptr %x, i32 %subval, i32 %val2) | ||
%subval2 = sub i32 %n, 2 | ||
%callret2 = call i32 @foo(ptr %x, i32 %subval2, i32 %m) | ||
%cmp2 = add i32 %callret, %callret2 | ||
br label %return | ||
|
||
cond_next: ; No predecessors! | ||
br label %return | ||
|
||
return: ; preds = %cond_next, %cond_false, %cond_true | ||
%retval.0 = phi i32 [ %val, %cond_true ], [ %cmp2, %cond_false ], [ poison, %cond_next ] | ||
ret i32 %retval.0 | ||
} | ||
|
||
define i32 @bar(ptr align(4) dereferenceable(4) %x, i32 %n, i32 %m) { | ||
; CHECK-LABEL: define i32 @bar( | ||
; CHECK-SAME: ptr align 4 dereferenceable(4) [[X:%.*]], i32 [[N:%.*]], i32 [[M:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: [[X_VAL:%.*]] = load i32, ptr [[X]], align 4 | ||
; CHECK-NEXT: [[CALLRET3:%.*]] = call i32 @foo(i32 [[X_VAL]], i32 [[N]], i32 [[M]]) | ||
; CHECK-NEXT: br label %[[RETURN:.*]] | ||
; CHECK: [[RETURN]]: | ||
; CHECK-NEXT: ret i32 [[CALLRET3]] | ||
; | ||
entry: | ||
%callret3 = call i32 @foo(ptr %x, i32 %n, i32 %m) | ||
br label %return | ||
|
||
return: ; preds = %entry | ||
ret i32 %callret3 | ||
} |
68 changes: 68 additions & 0 deletions
68
llvm/test/Transforms/ArgumentPromotion/recursion/recursion-arg-position-pr1259.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 | ||
; RUN: opt -S -passes=argpromotion < %s | FileCheck %s | ||
define internal i32 @foo(ptr %x, ptr %y, i32 %n, i32 %m) { | ||
; CHECK-LABEL: define internal i32 @foo( | ||
; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]], i32 [[N:%.*]], i32 [[M:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[N]], 0 | ||
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] | ||
; CHECK: [[COND_TRUE]]: | ||
; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4 | ||
; CHECK-NEXT: br label %[[RETURN:.*]] | ||
; CHECK: [[COND_FALSE]]: | ||
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[X]], align 4 | ||
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[Y]], align 4 | ||
; CHECK-NEXT: [[SUBVAL:%.*]] = sub i32 [[N]], [[VAL3]] | ||
; CHECK-NEXT: [[CALLRET:%.*]] = call i32 @foo(ptr [[X]], ptr [[Y]], i32 [[SUBVAL]], i32 [[VAL2]]) | ||
; CHECK-NEXT: [[SUBVAL2:%.*]] = sub i32 [[N]], 2 | ||
; CHECK-NEXT: [[CALLRET2:%.*]] = call i32 @foo(ptr [[Y]], ptr [[X]], i32 [[SUBVAL2]], i32 [[M]]) | ||
; CHECK-NEXT: [[CMP2:%.*]] = add i32 [[CALLRET]], [[CALLRET2]] | ||
; CHECK-NEXT: br label %[[RETURN]] | ||
; CHECK: [[COND_NEXT:.*]]: | ||
; CHECK-NEXT: br label %[[RETURN]] | ||
; CHECK: [[RETURN]]: | ||
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[VAL]], %[[COND_TRUE]] ], [ [[CMP2]], %[[COND_FALSE]] ], [ poison, %[[COND_NEXT]] ] | ||
; CHECK-NEXT: ret i32 [[RETVAL_0]] | ||
; | ||
entry: | ||
%cmp = icmp ne i32 %n, 0 | ||
br i1 %cmp, label %cond_true, label %cond_false | ||
|
||
cond_true: ; preds = %entry | ||
%val = load i32, ptr %x, align 4 | ||
br label %return | ||
|
||
cond_false: ; preds = %entry | ||
%val2 = load i32, ptr %x, align 4 | ||
%val3 = load i32, ptr %y, align 4 | ||
%subval = sub i32 %n, %val3 | ||
%callret = call i32 @foo(ptr %x, ptr %y, i32 %subval, i32 %val2) | ||
%subval2 = sub i32 %n, 2 | ||
%callret2 = call i32 @foo(ptr %y, ptr %x, i32 %subval2, i32 %m) | ||
%cmp2 = add i32 %callret, %callret2 | ||
br label %return | ||
|
||
cond_next: ; No predecessors! | ||
br label %return | ||
|
||
return: ; preds = %cond_next, %cond_false, %cond_true | ||
%retval.0 = phi i32 [ %val, %cond_true ], [ %cmp2, %cond_false ], [ poison, %cond_next ] | ||
ret i32 %retval.0 | ||
} | ||
|
||
define i32 @bar(ptr align(4) dereferenceable(4) %x, ptr align(4) dereferenceable(4) %y, i32 %n, i32 %m) { | ||
; CHECK-LABEL: define i32 @bar( | ||
; CHECK-SAME: ptr align 4 dereferenceable(4) [[X:%.*]], ptr align 4 dereferenceable(4) [[Y:%.*]], i32 [[N:%.*]], i32 [[M:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: [[CALLRET3:%.*]] = call i32 @foo(ptr [[X]], ptr [[Y]], i32 [[N]], i32 [[M]]) | ||
; CHECK-NEXT: br label %[[RETURN:.*]] | ||
; CHECK: [[RETURN]]: | ||
; CHECK-NEXT: ret i32 [[CALLRET3]] | ||
; | ||
entry: | ||
%callret3 = call i32 @foo(ptr %x, ptr %y, i32 %n, i32 %m) | ||
br label %return | ||
|
||
return: ; preds = %entry | ||
ret i32 %callret3 | ||
} |
84 changes: 84 additions & 0 deletions
84
llvm/test/Transforms/ArgumentPromotion/recursion/recursion-mixed-calls.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 | ||
; RUN: opt -S -passes=argpromotion < %s | FileCheck %s | ||
define internal i32 @zoo(ptr %x, i32 %m) { | ||
; CHECK-LABEL: define internal i32 @zoo( | ||
; CHECK-SAME: i32 [[X_0_VAL:%.*]], i32 [[M:%.*]]) { | ||
; CHECK-NEXT: [[RESZOO:%.*]] = add i32 [[X_0_VAL]], [[M]] | ||
; CHECK-NEXT: ret i32 [[X_0_VAL]] | ||
; | ||
%valzoo = load i32, ptr %x, align 4 | ||
%reszoo = add i32 %valzoo, %m | ||
ret i32 %valzoo | ||
} | ||
|
||
define internal i32 @foo(ptr %x, ptr %y, i32 %n, i32 %m) { | ||
; CHECK-LABEL: define internal i32 @foo( | ||
; CHECK-SAME: ptr [[X:%.*]], i32 [[Y_0_VAL:%.*]], i32 [[N:%.*]], i32 [[M:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[N]], 0 | ||
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] | ||
; CHECK: [[COND_TRUE]]: | ||
; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4 | ||
; CHECK-NEXT: br label %[[RETURN:.*]] | ||
; CHECK: [[COND_FALSE]]: | ||
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[X]], align 4 | ||
; CHECK-NEXT: [[SUBVAL:%.*]] = sub i32 [[N]], [[Y_0_VAL]] | ||
; CHECK-NEXT: [[CALLRET:%.*]] = call i32 @foo(ptr [[X]], i32 [[Y_0_VAL]], i32 [[SUBVAL]], i32 [[VAL2]]) | ||
; CHECK-NEXT: [[SUBVAL2:%.*]] = sub i32 [[N]], 2 | ||
; CHECK-NEXT: [[CALLRET2:%.*]] = call i32 @foo(ptr [[X]], i32 [[Y_0_VAL]], i32 [[SUBVAL2]], i32 [[M]]) | ||
; CHECK-NEXT: [[CMP1:%.*]] = add i32 [[CALLRET]], [[CALLRET2]] | ||
; CHECK-NEXT: [[X_VAL:%.*]] = load i32, ptr [[X]], align 4 | ||
; CHECK-NEXT: [[CALLRETFINAL:%.*]] = call i32 @zoo(i32 [[X_VAL]], i32 [[M]]) | ||
; CHECK-NEXT: [[CMP2:%.*]] = add i32 [[CMP1]], [[CALLRETFINAL]] | ||
; CHECK-NEXT: br label %[[RETURN]] | ||
; CHECK: [[COND_NEXT:.*]]: | ||
; CHECK-NEXT: br label %[[RETURN]] | ||
; CHECK: [[RETURN]]: | ||
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[VAL]], %[[COND_TRUE]] ], [ [[CMP2]], %[[COND_FALSE]] ], [ poison, %[[COND_NEXT]] ] | ||
; CHECK-NEXT: ret i32 [[RETVAL_0]] | ||
; | ||
entry: | ||
%cmp = icmp ne i32 %n, 0 | ||
br i1 %cmp, label %cond_true, label %cond_false | ||
|
||
cond_true: ; preds = %entry | ||
%val = load i32, ptr %x, align 4 | ||
br label %return | ||
|
||
cond_false: ; preds = %entry | ||
%val2 = load i32, ptr %x, align 4 | ||
%val3 = load i32, ptr %y, align 4 | ||
%subval = sub i32 %n, %val3 | ||
%callret = call i32 @foo(ptr %x, ptr %y, i32 %subval, i32 %val2) | ||
%subval2 = sub i32 %n, 2 | ||
%callret2 = call i32 @foo(ptr %x, ptr %y, i32 %subval2, i32 %m) | ||
%cmp1 = add i32 %callret, %callret2 | ||
%callretfinal = call i32 @zoo(ptr %x, i32 %m) | ||
%cmp2 = add i32 %cmp1, %callretfinal | ||
br label %return | ||
|
||
cond_next: ; No predecessors! | ||
br label %return | ||
|
||
return: ; preds = %cond_next, %cond_false, %cond_true | ||
%retval.0 = phi i32 [ %val, %cond_true ], [ %cmp2, %cond_false ], [ poison, %cond_next ] | ||
ret i32 %retval.0 | ||
} | ||
|
||
define i32 @bar(ptr align(4) dereferenceable(4) %x, ptr align(4) dereferenceable(4) %y, i32 %n, i32 %m) { | ||
; CHECK-LABEL: define i32 @bar( | ||
; CHECK-SAME: ptr align 4 dereferenceable(4) [[X:%.*]], ptr align 4 dereferenceable(4) [[Y:%.*]], i32 [[N:%.*]], i32 [[M:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: [[Y_VAL:%.*]] = load i32, ptr [[Y]], align 4 | ||
; CHECK-NEXT: [[CALLRET3:%.*]] = call i32 @foo(ptr [[X]], i32 [[Y_VAL]], i32 [[N]], i32 [[M]]) | ||
; CHECK-NEXT: br label %[[RETURN:.*]] | ||
; CHECK: [[RETURN]]: | ||
; CHECK-NEXT: ret i32 [[CALLRET3]] | ||
; | ||
entry: | ||
%callret3 = call i32 @foo(ptr %x, ptr %y, i32 %n, i32 %m) | ||
br label %return | ||
|
||
return: ; preds = %entry | ||
ret i32 %callret3 | ||
} |
Oops, something went wrong.