| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -ipsccp -S | FileCheck %s |
| |
| declare void @use(i1) |
| |
| ; We can simplify the conditions in the true block, because the condition |
| ; allows us to replace all uses of %a in the block with a constant. |
| define void @val_undef_eq() { |
| ; CHECK-LABEL: @val_undef_eq( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[A:%.*]] = add i32 undef, 0 |
| ; CHECK-NEXT: [[BC_1:%.*]] = icmp eq i32 [[A]], 10 |
| ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @use(i1 false) |
| ; CHECK-NEXT: call void @use(i1 true) |
| ; CHECK-NEXT: ret void |
| ; CHECK: false: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %a = add i32 undef, 0 |
| %bc.1 = icmp eq i32 %a, 10 |
| br i1 %bc.1, label %true, label %false |
| |
| true: |
| %f.1 = icmp ne i32 %a, 10 |
| call void @use(i1 %f.1) |
| %f.2 = icmp eq i32 %a, 10 |
| call void @use(i1 %f.2) |
| ret void |
| |
| false: |
| ret void |
| } |
| |
| declare void @use.i32(i32) |
| |
| ; It is not allowed to use the range information from the condition to remove |
| ; %a.127 = and ... in the true block, as %a could be undef. |
| define void @val_undef_range() { |
| ; CHECK-LABEL: @val_undef_range( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[A:%.*]] = add i32 undef, 0 |
| ; CHECK-NEXT: [[BC_1:%.*]] = icmp ult i32 [[A]], 127 |
| ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @use(i1 false) |
| ; CHECK-NEXT: [[A_127:%.*]] = and i32 [[A]], 127 |
| ; CHECK-NEXT: call void @use.i32(i32 [[A_127]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: false: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %a = add i32 undef, 0 |
| %bc.1 = icmp ult i32 %a, 127 |
| br i1 %bc.1, label %true, label %false |
| |
| true: |
| %f.1 = icmp eq i32 %a, 128 |
| call void @use(i1 %f.1) |
| |
| %a.127 = and i32 %a, 127 |
| call void @use.i32(i32 %a.127) |
| ret void |
| |
| false: |
| ret void |
| } |
| |
| ; All uses of %p can be replaced by a constant (10). |
| define void @val_singlecrfromundef_range(i1 %cond) { |
| ; CHECK-LABEL: @val_singlecrfromundef_range( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[INC1:%.*]], label [[INC2:%.*]] |
| ; CHECK: inc1: |
| ; CHECK-NEXT: br label [[IF:%.*]] |
| ; CHECK: inc2: |
| ; CHECK-NEXT: br label [[IF]] |
| ; CHECK: if: |
| ; CHECK-NEXT: br label [[TRUE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @use(i1 false) |
| ; CHECK-NEXT: [[P_127:%.*]] = and i32 10, 127 |
| ; CHECK-NEXT: call void @use.i32(i32 [[P_127]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| |
| br i1 %cond, label %inc1, label %inc2 |
| |
| inc1: |
| br label %if |
| |
| inc2: |
| br label %if |
| |
| if: |
| %p = phi i32 [ 10, %inc1 ], [ undef, %inc2 ] |
| %bc.1 = icmp ult i32 %p, 127 |
| br i1 %bc.1, label %true, label %false |
| |
| true: |
| %f.1 = icmp eq i32 %p, 128 |
| call void @use(i1 %f.1) |
| |
| %p.127 = and i32 %p, 127 |
| call void @use.i32(i32 %p.127) |
| ret void |
| |
| false: |
| ret void |
| } |
| |
| |
| ; It is not allowed to use the information from the condition ([0, 128)) |
| ; to remove a.127.2 = and i32 %p, 127, as %p might be undef. |
| define void @val_undef_to_cr_to_overdef_range(i32 %a, i1 %cond) { |
| ; CHECK-LABEL: @val_undef_to_cr_to_overdef_range( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[A_127:%.*]] = and i32 [[A:%.*]], 127 |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[INC1:%.*]], label [[INC2:%.*]] |
| ; CHECK: inc1: |
| ; CHECK-NEXT: br label [[IF:%.*]] |
| ; CHECK: inc2: |
| ; CHECK-NEXT: br label [[IF]] |
| ; CHECK: if: |
| ; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[A_127]], [[INC1]] ], [ undef, [[INC2]] ] |
| ; CHECK-NEXT: [[BC_1:%.*]] = icmp ult i32 [[P]], 100 |
| ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @use(i1 false) |
| ; CHECK-NEXT: [[P_127:%.*]] = and i32 [[P]], 127 |
| ; CHECK-NEXT: call void @use.i32(i32 [[P_127]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: false: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %a.127 = and i32 %a, 127 |
| br i1 %cond, label %inc1, label %inc2 |
| |
| inc1: |
| br label %if |
| |
| inc2: |
| br label %if |
| |
| if: |
| %p = phi i32 [ %a.127, %inc1 ], [ undef, %inc2 ] |
| %bc.1 = icmp ult i32 %p, 100 |
| br i1 %bc.1, label %true, label %false |
| |
| true: |
| %f.1 = icmp eq i32 %p, 128 |
| call void @use(i1 %f.1) |
| |
| %p.127 = and i32 %p, 127 |
| call void @use.i32(i32 %p.127) |
| ret void |
| |
| false: |
| ret void |
| } |
| |
| ; All uses of %p can be replaced by a constant (10), we are allowed to use it |
| ; as a bound too. |
| define void @bound_singlecrfromundef(i32 %a, i1 %cond) { |
| ; CHECK-LABEL: @bound_singlecrfromundef( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: br label [[PRED:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: br label [[PRED]] |
| ; CHECK: pred: |
| ; CHECK-NEXT: [[BC_1:%.*]] = icmp ugt i32 [[A:%.*]], 10 |
| ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: call void @use(i1 false) |
| ; CHECK-NEXT: call void @use(i1 true) |
| ; CHECK-NEXT: [[A_127:%.*]] = and i32 [[A]], 127 |
| ; CHECK-NEXT: call void @use.i32(i32 [[A_127]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: false: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %cond, label %bb1, label %bb2 |
| |
| bb1: |
| br label %pred |
| |
| bb2: |
| br label %pred |
| |
| pred: |
| %p = phi i32 [ undef, %bb1 ], [ 10, %bb2 ] |
| %bc.1 = icmp ugt i32 %a, %p |
| br i1 %bc.1, label %true, label %false |
| |
| true: |
| %f.1 = icmp eq i32 %a, 5 |
| call void @use(i1 %f.1) |
| |
| %t.1 = icmp ne i32 %a, 5 |
| call void @use(i1 %t.1) |
| |
| %a.127 = and i32 %a, 127 |
| call void @use.i32(i32 %a.127) |
| |
| ret void |
| |
| false: |
| ret void |
| } |
| |
| ; It is not allowed to use the information from %p as a bound, because an |
| ; incoming value is undef. |
| define void @bound_range_and_undef(i32 %a, i1 %cond) { |
| ; CHECK-LABEL: @bound_range_and_undef( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[A_10:%.*]] = and i32 [[A:%.*]], 127 |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: br label [[PRED:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: br label [[PRED]] |
| ; CHECK: pred: |
| ; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[A_10]], [[BB1]] ], [ undef, [[BB2]] ] |
| ; CHECK-NEXT: [[BC_1:%.*]] = icmp ugt i32 [[A]], [[P]] |
| ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] |
| ; CHECK: true: |
| ; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[A]], 300 |
| ; CHECK-NEXT: call void @use(i1 [[F_1]]) |
| ; CHECK-NEXT: [[A_127_2:%.*]] = and i32 [[P]], 127 |
| ; CHECK-NEXT: call void @use.i32(i32 [[A_127_2]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: false: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %a.10 = and i32 %a, 127 |
| br i1 %cond, label %bb1, label %bb2 |
| |
| bb1: |
| br label %pred |
| |
| bb2: |
| br label %pred |
| |
| pred: |
| %p = phi i32 [ %a.10, %bb1 ], [ undef, %bb2 ] |
| %bc.1 = icmp ugt i32 %a, %p |
| br i1 %bc.1, label %true, label %false |
| |
| true: |
| %f.1 = icmp eq i32 %a, 300 |
| call void @use(i1 %f.1) |
| |
| %a.127.2 = and i32 %p, 127 |
| call void @use.i32(i32 %a.127.2) |
| |
| ret void |
| |
| false: |
| ret void |
| } |