This patch adds support for constant propagation of individual structure members through Phi nodes. Each member is handled independently, allowing optimization opportunities when specific members become constant. Also, update the testcase since we are able to optimize the call parameter now.
197 lines
6.0 KiB
LLVM
197 lines
6.0 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt %s -passes=ipsccp -S | FileCheck %s
|
|
|
|
declare i1 @cond()
|
|
declare void @use(i1)
|
|
|
|
define internal {i64, i64} @struct1() {
|
|
; CHECK-LABEL: @struct1(
|
|
; CHECK-NEXT: [[C:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[C]], label [[TRUE:%.*]], label [[FALSE:%.*]]
|
|
; CHECK: true:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: false:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[R:%.*]] = phi { i64, i64 } [ { i64 20, i64 200 }, [[TRUE]] ], [ { i64 30, i64 300 }, [[FALSE]] ]
|
|
; CHECK-NEXT: ret { i64, i64 } [[R]]
|
|
;
|
|
%c = call i1 @cond()
|
|
br i1 %c, label %true, label %false
|
|
|
|
true:
|
|
%s.1 = insertvalue {i64, i64} undef, i64 20, 0
|
|
%s.2 = insertvalue {i64, i64} %s.1, i64 200, 1
|
|
br label %exit
|
|
|
|
false:
|
|
%s.3 = insertvalue {i64, i64} poison, i64 30, 0
|
|
%s.4 = insertvalue {i64, i64} %s.3, i64 300, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
%r = phi {i64, i64} [ %s.2, %true], [ %s.4, %false ]
|
|
ret {i64, i64} %r
|
|
}
|
|
|
|
define void @struct1_caller() {
|
|
; CHECK-LABEL: @struct1_caller(
|
|
; CHECK-NEXT: [[S:%.*]] = call { i64, i64 } @struct1()
|
|
; CHECK-NEXT: [[V1:%.*]] = extractvalue { i64, i64 } [[S]], 0
|
|
; CHECK-NEXT: [[V2:%.*]] = extractvalue { i64, i64 } [[S]], 1
|
|
; CHECK-NEXT: call void @use(i1 true)
|
|
; CHECK-NEXT: call void @use(i1 true)
|
|
; CHECK-NEXT: [[T_3:%.*]] = icmp eq i64 [[V1]], 20
|
|
; CHECK-NEXT: call void @use(i1 [[T_3]])
|
|
; CHECK-NEXT: call void @use(i1 true)
|
|
; CHECK-NEXT: call void @use(i1 true)
|
|
; CHECK-NEXT: [[T_6:%.*]] = icmp eq i64 [[V2]], 300
|
|
; CHECK-NEXT: call void @use(i1 [[T_6]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%s = call {i64, i64} @struct1()
|
|
%v1 = extractvalue {i64, i64} %s, 0
|
|
%v2 = extractvalue {i64, i64} %s, 1
|
|
|
|
%t.1 = icmp ne i64 %v1, 10
|
|
call void @use(i1 %t.1)
|
|
%t.2 = icmp ult i64 %v1, 100
|
|
call void @use(i1 %t.2)
|
|
%t.3 = icmp eq i64 %v1, 20
|
|
call void @use(i1 %t.3)
|
|
%t.4 = icmp ne i64 %v2, 0
|
|
call void @use(i1 %t.4)
|
|
%t.5 = icmp ult i64 %v2, 301
|
|
call void @use(i1 %t.5)
|
|
%t.6 = icmp eq i64 %v2, 300
|
|
call void @use(i1 %t.6)
|
|
|
|
ret void
|
|
}
|
|
|
|
define internal {i64, i64} @struct2() {
|
|
; CHECK-LABEL: @struct2(
|
|
; CHECK-NEXT: [[C:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[C]], label [[TRUE:%.*]], label [[FALSE:%.*]]
|
|
; CHECK: true:
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
; CHECK: false:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[V1:%.*]] = phi i64 [ 20, [[TRUE]] ], [ 30, [[FALSE]] ]
|
|
; CHECK-NEXT: [[V2:%.*]] = phi i64 [ 200, [[TRUE]] ], [ 300, [[FALSE]] ]
|
|
; CHECK-NEXT: [[S_1:%.*]] = insertvalue { i64, i64 } poison, i64 [[V1]], 0
|
|
; CHECK-NEXT: [[S_2:%.*]] = insertvalue { i64, i64 } [[S_1]], i64 [[V2]], 1
|
|
; CHECK-NEXT: ret { i64, i64 } [[S_2]]
|
|
;
|
|
%c = call i1 @cond()
|
|
br i1 %c, label %true, label %false
|
|
|
|
true:
|
|
br label %exit
|
|
|
|
false:
|
|
br label %exit
|
|
|
|
exit:
|
|
%v1 = phi i64 [ 20, %true ], [ 30, %false ]
|
|
%v2 = phi i64 [ 200, %true ], [ 300, %false ]
|
|
%s.1 = insertvalue {i64, i64} poison, i64 %v1, 0
|
|
%s.2 = insertvalue {i64, i64} %s.1, i64 %v2, 1
|
|
ret {i64, i64} %s.2
|
|
}
|
|
|
|
define void @struct2_caller() {
|
|
; CHECK-LABEL: @struct2_caller(
|
|
; CHECK-NEXT: [[S:%.*]] = call { i64, i64 } @struct2()
|
|
; CHECK-NEXT: [[V1:%.*]] = extractvalue { i64, i64 } [[S]], 0
|
|
; CHECK-NEXT: [[V2:%.*]] = extractvalue { i64, i64 } [[S]], 1
|
|
; CHECK-NEXT: call void @use(i1 true)
|
|
; CHECK-NEXT: call void @use(i1 true)
|
|
; CHECK-NEXT: call void @use(i1 true)
|
|
; CHECK-NEXT: call void @use(i1 true)
|
|
; CHECK-NEXT: call void @use(i1 false)
|
|
; CHECK-NEXT: call void @use(i1 false)
|
|
; CHECK-NEXT: call void @use(i1 false)
|
|
; CHECK-NEXT: call void @use(i1 false)
|
|
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i64 [[V1]], 25
|
|
; CHECK-NEXT: call void @use(i1 [[C_1]])
|
|
; CHECK-NEXT: [[C_2:%.*]] = icmp ult i64 [[V1]], 25
|
|
; CHECK-NEXT: call void @use(i1 [[C_2]])
|
|
; CHECK-NEXT: [[C_3:%.*]] = icmp eq i64 [[V2]], 250
|
|
; CHECK-NEXT: call void @use(i1 [[C_3]])
|
|
; CHECK-NEXT: [[C_4:%.*]] = icmp ugt i64 [[V2]], 250
|
|
; CHECK-NEXT: call void @use(i1 [[C_4]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%s = call {i64, i64} @struct2()
|
|
%v1 = extractvalue {i64, i64} %s, 0
|
|
%v2 = extractvalue {i64, i64} %s, 1
|
|
|
|
%t.1 = icmp ne i64 %v1, 10
|
|
call void @use(i1 %t.1)
|
|
%t.2 = icmp ult i64 %v1, 100
|
|
call void @use(i1 %t.2)
|
|
%t.3 = icmp ne i64 %v2, 0
|
|
call void @use(i1 %t.3)
|
|
%t.4 = icmp ult i64 %v2, 301
|
|
call void @use(i1 %t.4)
|
|
|
|
%f.1 = icmp eq i64 %v1, 10
|
|
call void @use(i1 %f.1)
|
|
%f.2 = icmp ult i64 %v1, 19
|
|
call void @use(i1 %f.2)
|
|
%f.3 = icmp eq i64 %v2, 50
|
|
call void @use(i1 %f.3)
|
|
%f.4 = icmp ugt i64 %v2, 301
|
|
call void @use(i1 %f.4)
|
|
|
|
%c.1 = icmp eq i64 %v1, 25
|
|
call void @use(i1 %c.1)
|
|
%c.2 = icmp ult i64 %v1, 25
|
|
call void @use(i1 %c.2)
|
|
%c.3 = icmp eq i64 %v2, 250
|
|
call void @use(i1 %c.3)
|
|
%c.4 = icmp ugt i64 %v2, 250
|
|
call void @use(i1 %c.4)
|
|
|
|
ret void
|
|
}
|
|
|
|
%"phi_type" = type {i64, i64}
|
|
|
|
define internal %"phi_type" @test(i32 %input) {
|
|
; CHECK-LABEL: @test(
|
|
; CHECK-NEXT: br label [[COND_TRUE_I:%.*]]
|
|
; CHECK: cond.true.i:
|
|
; CHECK-NEXT: br label [[COND_END_I:%.*]]
|
|
; CHECK: cond.end.i:
|
|
; CHECK-NEXT: ret [[PHI_TYPE:%.*]] poison
|
|
;
|
|
%cmp.cond = icmp eq i32 %input, 1
|
|
br i1 %cmp.cond, label %cond.true.i, label %cond.false.i
|
|
|
|
cond.true.i:
|
|
%r1.tmp = insertvalue %"phi_type" poison, i64 1, 0
|
|
%r1.tmp.2 = insertvalue %"phi_type" %r1.tmp, i64 2, 1
|
|
br label %cond.end.i
|
|
|
|
cond.false.i:
|
|
%r2.tmp = insertvalue %"phi_type" poison, i64 3, 0
|
|
%r2.tmp.2 = insertvalue %"phi_type" %r2.tmp, i64 4, 1
|
|
br label %cond.end.i
|
|
|
|
cond.end.i:
|
|
%retval = phi %"phi_type" [ %r1.tmp.2, %cond.true.i ], [ %r2.tmp.2, %cond.false.i ]
|
|
ret %"phi_type" %retval
|
|
}
|
|
|
|
define %"phi_type" @test2() {
|
|
; CHECK-LABEL: @test2(
|
|
; CHECK-NEXT: [[CALL_1:%.*]] = tail call fastcc [[PHI_TYPE:%.*]] @[[TEST:[a-zA-Z0-9_$\"\\.-]*[a-zA-Z_$\"\\.-][a-zA-Z0-9_$\"\\.-]*]](i32 noundef 1)
|
|
; CHECK-NEXT: ret [[PHI_TYPE]] { i64 1, i64 2 }
|
|
;
|
|
%call.1 = tail call fastcc noundef %"phi_type" @test(i32 noundef 1)
|
|
ret %"phi_type" %call.1
|
|
}
|