visitExtractValueInst uses mergeInValue, so it already can handle constant ranges. Initially the early exit was using isOverdefined to keep things as NFC during the initial move to ValueLatticeElement. As the function already supports constant ranges, it can just use ValueState[&I].isOverdefined. Reviewers: efriedma, mssimpso, davide Reviewed By: efriedma Differential Revision: https://reviews.llvm.org/D78393
164 lines
5.2 KiB
LLVM
164 lines
5.2 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt %s -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} undef, 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: [[T_1:%.*]] = icmp ne i64 [[V1]], 10
|
|
; CHECK-NEXT: call void @use(i1 [[T_1]])
|
|
; CHECK-NEXT: [[T_2:%.*]] = icmp ult i64 [[V1]], 100
|
|
; CHECK-NEXT: call void @use(i1 [[T_2]])
|
|
; CHECK-NEXT: [[T_3:%.*]] = icmp ne i64 [[V2]], 0
|
|
; CHECK-NEXT: call void @use(i1 [[T_3]])
|
|
; CHECK-NEXT: [[T_4:%.*]] = icmp ult i64 [[V2]], 301
|
|
; CHECK-NEXT: call void @use(i1 [[T_4]])
|
|
; 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 ne i64 %v2, 0
|
|
call void @use(i1 %t.3)
|
|
%t.4 = icmp ult i64 %v2, 301
|
|
call void @use(i1 %t.4)
|
|
|
|
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 } undef, 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} undef, 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: [[T_1:%.*]] = icmp ne i64 [[V1]], 10
|
|
; CHECK-NEXT: call void @use(i1 [[T_1]])
|
|
; CHECK-NEXT: [[T_2:%.*]] = icmp ult i64 [[V1]], 100
|
|
; CHECK-NEXT: call void @use(i1 [[T_2]])
|
|
; CHECK-NEXT: [[T_3:%.*]] = icmp ne i64 [[V2]], 0
|
|
; CHECK-NEXT: call void @use(i1 [[T_3]])
|
|
; CHECK-NEXT: [[T_4:%.*]] = icmp ult i64 [[V2]], 301
|
|
; CHECK-NEXT: call void @use(i1 [[T_4]])
|
|
; CHECK-NEXT: [[F_1:%.*]] = icmp eq i64 [[V1]], 10
|
|
; CHECK-NEXT: call void @use(i1 [[F_1]])
|
|
; CHECK-NEXT: [[F_2:%.*]] = icmp ult i64 [[V1]], 19
|
|
; CHECK-NEXT: call void @use(i1 [[F_2]])
|
|
; CHECK-NEXT: [[F_3:%.*]] = icmp eq i64 [[V2]], 50
|
|
; CHECK-NEXT: call void @use(i1 [[F_3]])
|
|
; CHECK-NEXT: [[F_4:%.*]] = icmp ugt i64 [[V2]], 301
|
|
; CHECK-NEXT: call void @use(i1 [[F_4]])
|
|
; 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
|
|
}
|