aboutsummaryrefslogtreecommitdiff
path: root/llvm/test/Transforms/InstCombine
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test/Transforms/InstCombine')
-rw-r--r--llvm/test/Transforms/InstCombine/assume.ll28
-rw-r--r--llvm/test/Transforms/InstCombine/fold-selective-shift.ll22
-rw-r--r--llvm/test/Transforms/InstCombine/ptrtoaddr.ll138
-rw-r--r--llvm/test/Transforms/InstCombine/select_with_identical_phi.ll417
-rw-r--r--llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll11
-rw-r--r--llvm/test/Transforms/InstCombine/trunc-sext.ll16
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
+}