diff options
Diffstat (limited to 'llvm/test/Transforms/InstCombine')
| -rw-r--r-- | llvm/test/Transforms/InstCombine/assume.ll | 28 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/fold-selective-shift.ll | 22 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/ptrtoaddr.ll | 138 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/select_with_identical_phi.ll | 417 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll | 11 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/trunc-sext.ll | 16 |
6 files changed, 629 insertions, 3 deletions
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll index 7b0b871..cc87d65 100644 --- a/llvm/test/Transforms/InstCombine/assume.ll +++ b/llvm/test/Transforms/InstCombine/assume.ll @@ -10,8 +10,8 @@ declare void @llvm.assume(i1) #1 ; Check that the assume has not been removed: -define i32 @foo1(ptr %a) #0 { -; DEFAULT-LABEL: @foo1( +define i32 @align_to_bundle(ptr %a) #0 { +; DEFAULT-LABEL: @align_to_bundle( ; DEFAULT-NEXT: [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4 ; DEFAULT-NEXT: [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64 ; DEFAULT-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31 @@ -19,7 +19,7 @@ define i32 @foo1(ptr %a) #0 { ; DEFAULT-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) ; DEFAULT-NEXT: ret i32 [[T0]] ; -; BUNDLES-LABEL: @foo1( +; BUNDLES-LABEL: @align_to_bundle( ; BUNDLES-NEXT: [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4 ; BUNDLES-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 32) ] ; BUNDLES-NEXT: ret i32 [[T0]] @@ -32,6 +32,28 @@ define i32 @foo1(ptr %a) #0 { ret i32 %t0 } +define i32 @align_to_bundle_ptrtoaddr(ptr %a) #0 { +; DEFAULT-LABEL: @align_to_bundle_ptrtoaddr( +; DEFAULT-NEXT: [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4 +; DEFAULT-NEXT: [[PTRINT:%.*]] = ptrtoaddr ptr [[A]] to i64 +; DEFAULT-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31 +; DEFAULT-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0 +; DEFAULT-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) +; DEFAULT-NEXT: ret i32 [[T0]] +; +; BUNDLES-LABEL: @align_to_bundle_ptrtoaddr( +; BUNDLES-NEXT: [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4 +; BUNDLES-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 32) ] +; BUNDLES-NEXT: ret i32 [[T0]] +; + %t0 = load i32, ptr %a, align 4 + %ptrint = ptrtoaddr ptr %a to i64 + %maskedptr = and i64 %ptrint, 31 + %maskcond = icmp eq i64 %maskedptr, 0 + tail call void @llvm.assume(i1 %maskcond) + ret i32 %t0 +} + define i32 @align_assume_trunc_cond(ptr %a) #0 { ; DEFAULT-LABEL: @align_assume_trunc_cond( ; DEFAULT-NEXT: [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4 diff --git a/llvm/test/Transforms/InstCombine/fold-selective-shift.ll b/llvm/test/Transforms/InstCombine/fold-selective-shift.ll index 2b22965..dcfd933 100644 --- a/llvm/test/Transforms/InstCombine/fold-selective-shift.ll +++ b/llvm/test/Transforms/InstCombine/fold-selective-shift.ll @@ -21,6 +21,28 @@ define i16 @selective_shift_16(i32 %mask, i16 %upper, i16 %lower) { ret i16 %trunc } +; Will assert if InsertPoint is not set before creating an instruction +; with IRBuilder +define i16 @selective_shift_16_insertpt(i32 %mask, i16 %upper, i16 %lower) { +; CHECK-LABEL: define i16 @selective_shift_16_insertpt( +; CHECK-SAME: i32 [[MASK:%.*]], i16 [[UPPER:%.*]], i16 [[LOWER:%.*]]) { +; CHECK-NEXT: [[MASK_BIT:%.*]] = and i32 [[MASK]], 16 +; CHECK-NEXT: [[MASK_BIT_Z:%.*]] = icmp eq i32 [[MASK_BIT]], 0 +; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[MASK_BIT_Z]], i16 [[LOWER]], i16 [[UPPER]] +; CHECK-NEXT: [[ADD_ONE:%.*]] = add i16 [[SEL_V]], 1 +; CHECK-NEXT: ret i16 [[ADD_ONE]] +; + %mask.bit = and i32 %mask, 16 + %upper.zext = zext i16 %upper to i32 + %upper.shl = shl nuw i32 %upper.zext, 16 + %lower.zext = zext i16 %lower to i32 + %pack = or disjoint i32 %upper.shl, %lower.zext + %sel = lshr i32 %pack, %mask.bit + %add.one = add i32 %sel, 1 + %trunc = trunc i32 %add.one to i16 + ret i16 %trunc +} + define i16 @selective_shift_16.commute(i32 %mask, i16 %upper, i16 %lower) { ; CHECK-LABEL: define i16 @selective_shift_16.commute( ; CHECK-SAME: i32 [[MASK:%.*]], i16 [[UPPER:%.*]], i16 [[LOWER:%.*]]) { diff --git a/llvm/test/Transforms/InstCombine/ptrtoaddr.ll b/llvm/test/Transforms/InstCombine/ptrtoaddr.ll index f19cca8..adf3aa1 100644 --- a/llvm/test/Transforms/InstCombine/ptrtoaddr.ll +++ b/llvm/test/Transforms/InstCombine/ptrtoaddr.ll @@ -4,6 +4,10 @@ ; The ptrtoaddr folds are also valid for pointers that have external state. target datalayout = "pe1:64:64:64:32" +declare void @use.i1(i1) +declare void @use.i32(i32) +declare void @use.i64(i64) + ; ptrtoaddr result type is fixed, and can't be combined with integer cast. define i32 @ptrtoaddr_trunc(ptr %p) { ; CHECK-LABEL: define i32 @ptrtoaddr_trunc( @@ -171,3 +175,137 @@ define i128 @sub_zext_ptrtoint_ptrtoaddr_addrsize(ptr addrspace(1) %p, i32 %offs %sub = sub i128 %p2.addr.ext, %p.int.ext ret i128 %sub } + +; The uses in icmp, ptrtoint, ptrtoaddr should be replaced. The one in the +; return value should not, as the provenance differs. +define ptr @gep_sub_ptrtoaddr_different_obj(ptr %p, ptr %p2, ptr %p3) { +; CHECK-LABEL: define ptr @gep_sub_ptrtoaddr_different_obj( +; CHECK-SAME: ptr [[P:%.*]], ptr [[P2:%.*]], ptr [[P3:%.*]]) { +; CHECK-NEXT: [[P_ADDR:%.*]] = ptrtoaddr ptr [[P]] to i64 +; CHECK-NEXT: [[P2_ADDR:%.*]] = ptrtoaddr ptr [[P2]] to i64 +; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[P2_ADDR]], [[P_ADDR]] +; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[SUB]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P2]], [[P3]] +; CHECK-NEXT: call void @use.i1(i1 [[CMP]]) +; CHECK-NEXT: [[INT:%.*]] = ptrtoint ptr [[P2]] to i64 +; CHECK-NEXT: call void @use.i64(i64 [[INT]]) +; CHECK-NEXT: [[ADDR:%.*]] = ptrtoaddr ptr [[P2]] to i64 +; CHECK-NEXT: call void @use.i64(i64 [[ADDR]]) +; CHECK-NEXT: ret ptr [[GEP]] +; + %p.addr = ptrtoaddr ptr %p to i64 + %p2.addr = ptrtoaddr ptr %p2 to i64 + %sub = sub i64 %p2.addr, %p.addr + %gep = getelementptr i8, ptr %p, i64 %sub + %cmp = icmp eq ptr %gep, %p3 + call void @use.i1(i1 %cmp) + %int = ptrtoint ptr %gep to i64 + call void @use.i64(i64 %int) + %addr = ptrtoaddr ptr %gep to i64 + call void @use.i64(i64 %addr) + ret ptr %gep +} + +; The use in ptrtoaddr should be replaced. The uses in ptrtoint and icmp should +; not be replaced, as the non-address bits differ. The use in the return value +; should not be replaced as the provenace differs. +define ptr addrspace(1) @gep_sub_ptrtoaddr_different_obj_addrsize(ptr addrspace(1) %p, ptr addrspace(1) %p2, ptr addrspace(1) %p3) { +; CHECK-LABEL: define ptr addrspace(1) @gep_sub_ptrtoaddr_different_obj_addrsize( +; CHECK-SAME: ptr addrspace(1) [[P:%.*]], ptr addrspace(1) [[P2:%.*]], ptr addrspace(1) [[P3:%.*]]) { +; CHECK-NEXT: [[P_ADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[P]] to i32 +; CHECK-NEXT: [[P2_ADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[P2]] to i32 +; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[P2_ADDR]], [[P_ADDR]] +; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr addrspace(1) [[P]], i32 [[SUB]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr addrspace(1) [[GEP]], [[P3]] +; CHECK-NEXT: call void @use.i1(i1 [[CMP]]) +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(1) [[GEP]] to i64 +; CHECK-NEXT: [[INT:%.*]] = trunc i64 [[TMP1]] to i32 +; CHECK-NEXT: call void @use.i32(i32 [[INT]]) +; CHECK-NEXT: [[ADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[P2]] to i32 +; CHECK-NEXT: call void @use.i32(i32 [[ADDR]]) +; CHECK-NEXT: ret ptr addrspace(1) [[GEP]] +; + %p.addr = ptrtoaddr ptr addrspace(1) %p to i32 + %p2.addr = ptrtoaddr ptr addrspace(1) %p2 to i32 + %sub = sub i32 %p2.addr, %p.addr + %gep = getelementptr i8, ptr addrspace(1) %p, i32 %sub + %cmp = icmp eq ptr addrspace(1) %gep, %p3 + call void @use.i1(i1 %cmp) + %int = ptrtoint ptr addrspace(1) %gep to i32 + call void @use.i32(i32 %int) + %addr = ptrtoaddr ptr addrspace(1) %gep to i32 + call void @use.i32(i32 %addr) + ret ptr addrspace(1) %gep +} + +define i64 @ptrtoaddr_of_ptrmask(ptr %p, i64 %mask) { +; CHECK-LABEL: define i64 @ptrtoaddr_of_ptrmask( +; CHECK-SAME: ptr [[P:%.*]], i64 [[MASK:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[P]] to i64 +; CHECK-NEXT: [[ADDR:%.*]] = and i64 [[MASK]], [[TMP1]] +; CHECK-NEXT: ret i64 [[ADDR]] +; + %masked = call ptr @llvm.ptrmask(ptr %p, i64 %mask) + %addr = ptrtoaddr ptr %masked to i64 + ret i64 %addr +} + +define i32 @ptrtoaddr_of_ptrmask_addrsize(ptr addrspace(1) %p, i32 %mask) { +; CHECK-LABEL: define i32 @ptrtoaddr_of_ptrmask_addrsize( +; CHECK-SAME: ptr addrspace(1) [[P:%.*]], i32 [[MASK:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr addrspace(1) [[P]] to i32 +; CHECK-NEXT: [[ADDR:%.*]] = and i32 [[MASK]], [[TMP1]] +; CHECK-NEXT: ret i32 [[ADDR]] +; + %masked = call ptr addrspace(1) @llvm.ptrmask(ptr addrspace(1) %p, i32 %mask) + %addr = ptrtoaddr ptr addrspace(1) %masked to i32 + ret i32 %addr +} + +define i64 @ptrtoaddr_of_gep_of_inttoptr(i64 %int, i64 %offset) { +; CHECK-LABEL: define i64 @ptrtoaddr_of_gep_of_inttoptr( +; CHECK-SAME: i64 [[INT:%.*]], i64 [[OFFSET:%.*]]) { +; CHECK-NEXT: [[ADDR:%.*]] = add i64 [[INT]], [[OFFSET]] +; CHECK-NEXT: ret i64 [[ADDR]] +; + %ptr = inttoptr i64 %int to ptr + %gep = getelementptr i8, ptr %ptr, i64 %offset + %addr = ptrtoaddr ptr %gep to i64 + ret i64 %addr +} + +; FIXME: This could be supported by truncating %int before performing the +; arithmetic. +define i32 @ptrtoaddr_of_gep_of_inttoptr_addrsize(i64 %int, i32 %offset) { +; CHECK-LABEL: define i32 @ptrtoaddr_of_gep_of_inttoptr_addrsize( +; CHECK-SAME: i64 [[INT:%.*]], i32 [[OFFSET:%.*]]) { +; CHECK-NEXT: [[PTR:%.*]] = inttoptr i64 [[INT]] to ptr addrspace(1) +; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr addrspace(1) [[PTR]], i32 [[OFFSET]] +; CHECK-NEXT: [[ADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[GEP]] to i32 +; CHECK-NEXT: ret i32 [[ADDR]] +; + %ptr = inttoptr i64 %int to ptr addrspace(1) + %gep = getelementptr i8, ptr addrspace(1) %ptr, i32 %offset + %addr = ptrtoaddr ptr addrspace(1) %gep to i32 + ret i32 %addr +} + +define i64 @ptrtoaddr_of_gep_of_null(i64 %offset) { +; CHECK-LABEL: define i64 @ptrtoaddr_of_gep_of_null( +; CHECK-SAME: i64 [[OFFSET:%.*]]) { +; CHECK-NEXT: ret i64 [[OFFSET]] +; + %gep = getelementptr i8, ptr null, i64 %offset + %addr = ptrtoaddr ptr %gep to i64 + ret i64 %addr +} + +define i32 @ptrtoaddr_of_gep_of_null_addrsize(i32 %offset) { +; CHECK-LABEL: define i32 @ptrtoaddr_of_gep_of_null_addrsize( +; CHECK-SAME: i32 [[OFFSET:%.*]]) { +; CHECK-NEXT: ret i32 [[OFFSET]] +; + %gep = getelementptr i8, ptr addrspace(1) null, i32 %offset + %addr = ptrtoaddr ptr addrspace(1) %gep to i32 + ret i32 %addr +} diff --git a/llvm/test/Transforms/InstCombine/select_with_identical_phi.ll b/llvm/test/Transforms/InstCombine/select_with_identical_phi.ll new file mode 100644 index 0000000..db4965b --- /dev/null +++ b/llvm/test/Transforms/InstCombine/select_with_identical_phi.ll @@ -0,0 +1,417 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -S -passes=instcombine | FileCheck %s +@A = extern_weak global float, align 4 + +; %same.as.v1 is a select with two phis %v1 and %phi.to.remove as the true +; and false values, while %v1 and %phi.to.remove are actually the same. +; Fold the selection instruction %same.as.v1 to %v1. +define void @select_with_identical_phi(ptr %m, ptr %n, i32 %count) { +; CHECK-LABEL: @select_with_identical_phi( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V0:%.*]] = phi float [ 0x4415AF1D80000000, [[ENTRY:%.*]] ], [ [[V0_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[Q:%.*]] = phi ptr [ [[M:%.*]], [[ENTRY]] ], [ [[Q_NEXT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[C:%.*]] = phi ptr [ [[N:%.*]], [[ENTRY]] ], [ [[C_NEXT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[Q_LOAD:%.*]] = load float, ptr [[Q]], align 4 +; CHECK-NEXT: [[C_LOAD:%.*]] = load float, ptr [[C]], align 4 +; CHECK-NEXT: [[SUB:%.*]] = fsub float [[Q_LOAD]], [[C_LOAD]] +; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[SUB]], [[V0]] +; CHECK-NEXT: [[V0_1]] = select i1 [[CMP1]], float [[SUB]], float [[V0]] +; CHECK-NEXT: [[CMP2:%.*]] = fcmp ogt float [[SUB]], [[V1]] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2]], float [[SUB]], float [[V1]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[Q_NEXT]] = getelementptr inbounds nuw i8, ptr [[Q]], i64 4 +; CHECK-NEXT: [[C_NEXT]] = getelementptr inbounds nuw i8, ptr [[C]], i64 4 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], [[COUNT:%.*]] +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v0 = phi float [ 0x4415AF1D80000000, %entry ], [ %v0.1, %for.body ] + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %q = phi ptr [ %m, %entry ], [ %q.next, %for.body ] + %c = phi ptr [ %n, %entry ], [ %c.next, %for.body ] + %q.load = load float, ptr %q + %c.load = load float, ptr %c + %sub = fsub float %q.load, %c.load + %cmp1 = fcmp olt float %sub, %v0 + %v0.1 = select i1 %cmp1, float %sub, float %v0 + %same.as.v1 = select i1 %cmp1, float %v1, float %phi.to.remove + %cmp2 = fcmp ogt float %sub, %same.as.v1 + %v1.1 = select i1 %cmp2, float %sub, float %v1 + %phi.to.remove.next = select i1 %cmp2, float %sub, float %same.as.v1 + %inc.i = add nuw nsw i32 %i, 1 + %q.next = getelementptr inbounds i8, ptr %q, i64 4 + %c.next = getelementptr inbounds i8, ptr %c, i64 4 + %exitcond = icmp eq i32 %inc.i, %count + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; Reduced from select_with_identical_phi(). +; Check that %same.as.v1 can be folded. +define void @select_with_identical_phi_2(i1 %cmp1, i1 %cmp2, float %x) { +; CHECK-LABEL: @select_with_identical_phi_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY:%.*]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2:%.*]], float [[X:%.*]], float [[V1]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %v1, float %phi.to.remove + %v1.1 = select i1 %cmp2, float %x, float %v1 + %phi.to.remove.next = select i1 %cmp2, float %x, float %same.as.v1 + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; The difference from select_with_identical_phi_2() is that the true and false values in +; %phi.to.remove.next and %v1.1 are swapped. +; Check that %same.as.v1 can be folded. +define void @select_with_identical_phi_3(i1 %cmp1, i1 %cmp2, float %x) { +; CHECK-LABEL: @select_with_identical_phi_3( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY:%.*]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2:%.*]], float [[V1]], float [[X:%.*]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %v1, float %phi.to.remove + %v1.1 = select i1 %cmp2, float %v1, float %x + %phi.to.remove.next = select i1 %cmp2, float %same.as.v1, float %x + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; The difference from select_with_identical_phi_2() is that the true and false values in +; same.as.v1 are swapped. +; Check that %same.as.v1 can be folded. +define void @select_with_identical_phi_4(i1 %cmp1, i1 %cmp2, float %x) { +; CHECK-LABEL: @select_with_identical_phi_4( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY:%.*]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2:%.*]], float [[X:%.*]], float [[V1]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %phi.to.remove, float %v1 + %v1.1 = select i1 %cmp2, float %x, float %v1 + %phi.to.remove.next = select i1 %cmp2, float %x, float %same.as.v1 + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; The difference from select_with_identical_phi() is that the true and false values in +; %same.as.v1, %phi.to.remove.next and %v1.1 are swapped. +; Check that %same.as.v1 can be folded. +define void @select_with_identical_phi_5(i1 %cmp1, i1 %cmp2, float %x) { +; CHECK-LABEL: @select_with_identical_phi_5( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY:%.*]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2:%.*]], float [[V1]], float [[X:%.*]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %phi.to.remove, float %v1 + %v1.1 = select i1 %cmp2, float %v1, float %x + %phi.to.remove.next = select i1 %cmp2, float %same.as.v1, float %x + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; The difference from select_with_identical_phi_2() is that not all phis are sorted with +; the same order of incoming BBs. +; Check that %same.as.v1 can be folded. +define void @select_with_identical_phi_6(i1 %cmp1, i1 %cmp2, float %x) { +; CHECK-LABEL: @select_with_identical_phi_6( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY:%.*]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2:%.*]], float [[X:%.*]], float [[V1]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ %phi.to.remove.next, %for.body ], [ 0xC415AF1D80000000, %entry ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %v1, float %phi.to.remove + %v1.1 = select i1 %cmp2, float %x, float %v1 + %phi.to.remove.next = select i1 %cmp2, float %x, float %same.as.v1 + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; %v1 and %phi.to.remove do not have the same start value. +; Cannot fold %same.as.v1. +define void @select_with_identical_phi_negative_1(i1 %cmp1, i1 %cmp2, float %x) { +; CHECK-LABEL: @select_with_identical_phi_negative_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0x4415AF1D80000000, [[ENTRY:%.*]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[PHI_TO_REMOVE:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY]] ], [ [[PHI_TO_REMOVE_NEXT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[SAME_AS_V1:%.*]] = select i1 [[CMP1:%.*]], float [[V1]], float [[PHI_TO_REMOVE]] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2:%.*]], float [[X:%.*]], float [[V1]] +; CHECK-NEXT: [[PHI_TO_REMOVE_NEXT]] = select i1 [[CMP2]], float [[X]], float [[SAME_AS_V1]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v1 = phi float [ 0x4415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %v1, float %phi.to.remove + %v1.1 = select i1 %cmp2, float %x, float %v1 + %phi.to.remove.next = select i1 %cmp2, float %x, float %same.as.v1 + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; %v1 and %phi.to.remove do not act as the same phi since %v1.1 and %phi.to.remove.next do not evolve the same. +; Cannot fold %same.as.v1. +define void @select_with_identical_phi_negative_2(i1 %cmp1, i1 %cmp2, float %x) { +; CHECK-LABEL: @select_with_identical_phi_negative_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY:%.*]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[PHI_TO_REMOVE:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY]] ], [ [[PHI_TO_REMOVE_NEXT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[SAME_AS_V1:%.*]] = select i1 [[CMP1:%.*]], float [[V1]], float [[PHI_TO_REMOVE]] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2:%.*]], float [[V1]], float [[X:%.*]] +; CHECK-NEXT: [[PHI_TO_REMOVE_NEXT]] = select i1 [[CMP2]], float [[X]], float [[SAME_AS_V1]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %v1, float %phi.to.remove + %v1.1 = select i1 %cmp2, float %v1, float %x + %phi.to.remove.next = select i1 %cmp2, float %x, float %same.as.v1 + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; %v1 and %phi.to.remove do not act as the same phi since %v1.1 and %phi.to.remove.next do not +; have the same condition. +; Cannot fold %same.as.v1. +define void @select_with_identical_phi_negative_3(i1 %cmp1, i1 %cmp2, i1 %cmp3, float %x) { +; CHECK-LABEL: @select_with_identical_phi_negative_3( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY:%.*]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[PHI_TO_REMOVE:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY]] ], [ [[PHI_TO_REMOVE_NEXT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[SAME_AS_V1:%.*]] = select i1 [[CMP1:%.*]], float [[V1]], float [[PHI_TO_REMOVE]] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP3:%.*]], float [[V1]], float [[X:%.*]] +; CHECK-NEXT: [[PHI_TO_REMOVE_NEXT]] = select i1 [[CMP2:%.*]], float [[X]], float [[SAME_AS_V1]] +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %v1, float %phi.to.remove + %v1.1 = select i1 %cmp3, float %v1, float %x + %phi.to.remove.next = select i1 %cmp2, float %x, float %same.as.v1 + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} + +; The true and false values of %same.as.v1 are not really the same phi. +; Cannot fold %same.as.v1. +define void @select_with_identical_phi_negative_4(i1 %cmp1, i1 %cmp2, float %x) { +; CHECK-LABEL: @select_with_identical_phi_negative_4( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[V0:%.*]] = phi float [ 0x4415AF1D80000000, [[ENTRY:%.*]] ], [ [[V0_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[V1:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY]] ], [ [[V1_1:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[PHI_TO_REMOVE:%.*]] = phi float [ 0xC415AF1D80000000, [[ENTRY]] ], [ [[PHI_TO_REMOVE_NEXT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[SAME_AS_V1:%.*]] = select i1 [[CMP1:%.*]], float [[V0]], float [[PHI_TO_REMOVE]] +; CHECK-NEXT: [[V1_1]] = select i1 [[CMP2:%.*]], float [[X:%.*]], float [[V1]] +; CHECK-NEXT: [[PHI_TO_REMOVE_NEXT]] = select i1 [[CMP2]], float [[X]], float [[SAME_AS_V1]] +; CHECK-NEXT: [[V0_1]] = fadd float [[V0]], 1.000000e+00 +; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC_I]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[FOR_BODY]] +; CHECK: exit: +; CHECK-NEXT: store float [[V1_1]], ptr @A, align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %v0 = phi float [ 0x4415AF1D80000000, %entry ], [ %v0.1, %for.body ] + %v1 = phi float [ 0xC415AF1D80000000, %entry ], [ %v1.1, %for.body ] + %phi.to.remove = phi float [ 0xC415AF1D80000000, %entry ], [ %phi.to.remove.next, %for.body ] + %i = phi i32 [ 0, %entry ], [ %inc.i, %for.body ] + %same.as.v1 = select i1 %cmp1, float %v0, float %phi.to.remove + %v1.1 = select i1 %cmp2, float %x, float %v1 + %phi.to.remove.next = select i1 %cmp2, float %x, float %same.as.v1 + %v0.1 = fadd float %v0, 1.0 + %inc.i = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc.i, 100 + br i1 %exitcond, label %exit, label %for.body + +exit: + %vl.1.lcssa = phi float [ %v1.1, %for.body ] + store float %vl.1.lcssa, ptr @A + ret void +} diff --git a/llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll b/llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll index 516f1a2..4128a15 100644 --- a/llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll +++ b/llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll @@ -144,6 +144,17 @@ define i24 @wide_source_matching_signbits(i32 %x) { ret i24 %c } +define i32 @wide_source_matching_signbits_has_nsw_flag(i64 %i) { +; CHECK-LABEL: define i32 @wide_source_matching_signbits_has_nsw_flag( +; CHECK-SAME: i64 [[I:%.*]]) { +; CHECK-NEXT: [[A:%.*]] = trunc nsw i64 [[I]] to i32 +; CHECK-NEXT: ret i32 [[A]] +; + %a = trunc nsw i64 %i to i16 + %b = sext i16 %a to i32 + ret i32 %b +} + ; negative test - not enough sign-bits define i24 @wide_source_not_matching_signbits(i32 %x) { diff --git a/llvm/test/Transforms/InstCombine/trunc-sext.ll b/llvm/test/Transforms/InstCombine/trunc-sext.ll new file mode 100644 index 0000000..ac143840 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/trunc-sext.ll @@ -0,0 +1,16 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +target datalayout = "i16:16:16-i32:32:32-i64:64:64-n16:32:64" + +define i32 @test(i64 %i) { +; CHECK-LABEL: define i32 @test( +; CHECK-SAME: i64 [[I:%.*]]) { +; CHECK-NEXT: [[A:%.*]] = trunc i64 [[I]] to i16 +; CHECK-NEXT: [[B:%.*]] = sext i16 [[A]] to i32 +; CHECK-NEXT: ret i32 [[B]] +; + %a = trunc i64 %i to i16 + %b = sext i16 %a to i32 + ret i32 %b +} |
