blob: 5f2aef4f4435029bce9bb8d16d2baa6bf5870521 [file] [log] [blame]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=gvn -S < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4:5"
target triple = "x86_64-unknown-linux-gnu"
define void @f0(i1 %alwaysFalse, i64 %val, ptr %loc) {
; CHECK-LABEL: @f0(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i64 [[VAL:%.*]], ptr [[LOC:%.*]], align 8
; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]]
; CHECK: neverTaken:
; CHECK-NEXT: [[PTR:%.*]] = load ptr addrspace(4), ptr [[LOC]], align 8
; CHECK-NEXT: store i8 5, ptr addrspace(4) [[PTR]], align 1
; CHECK-NEXT: ret void
; CHECK: alwaysTaken:
; CHECK-NEXT: ret void
;
entry:
store i64 %val, ptr %loc
br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken
neverTaken:
%ptr = load ptr addrspace(4), ptr %loc
store i8 5, ptr addrspace(4) %ptr
ret void
alwaysTaken:
ret void
}
define i64 @f1(i1 %alwaysFalse, ptr addrspace(4) %val, ptr %loc) {
; CHECK-LABEL: @f1(
; CHECK-NEXT: entry:
; CHECK-NEXT: store ptr addrspace(4) [[VAL:%.*]], ptr [[LOC:%.*]], align 8
; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]]
; CHECK: neverTaken:
; CHECK-NEXT: [[INT:%.*]] = load i64, ptr [[LOC]], align 8
; CHECK-NEXT: ret i64 [[INT]]
; CHECK: alwaysTaken:
; CHECK-NEXT: ret i64 42
;
entry:
store ptr addrspace(4) %val, ptr %loc
br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken
neverTaken:
%int = load i64, ptr %loc
ret i64 %int
alwaysTaken:
ret i64 42
}
;; Note: For terseness, we stop using the %alwaysfalse trick for the
;; tests below and just exercise the bits of forwarding logic directly.
declare void @llvm.memset.p4.i64(ptr addrspace(4) nocapture, i8, i64, i1) nounwind
; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.)
define ptr addrspace(4) @neg_forward_memset(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_memset(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 7, i64 8, i1 false)
; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8
; CHECK-NEXT: ret ptr addrspace(4) [[REF]]
;
entry:
call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 7, i64 8, i1 false)
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
define <1 x ptr addrspace(4)> @neg_forward_memset_vload(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_memset_vload(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 7, i64 8, i1 false)
; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8
; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]]
;
entry:
call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 7, i64 8, i1 false)
%ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc
ret <1 x ptr addrspace(4)> %ref
}
; Can forward since we can do so w/o breaking types
define ptr addrspace(4) @forward_memset_zero(ptr addrspace(4) %loc) {
; CHECK-LABEL: @forward_memset_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 0, i64 8, i1 false)
; CHECK-NEXT: ret ptr addrspace(4) null
;
entry:
call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 0, i64 8, i1 false)
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.)
define ptr addrspace(4) @neg_forward_store(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_store(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i64 5, ptr addrspace(4) [[LOC:%.*]], align 8
; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8
; CHECK-NEXT: ret ptr addrspace(4) [[REF]]
;
entry:
store i64 5, ptr addrspace(4) %loc
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
define <1 x ptr addrspace(4)> @neg_forward_store_vload(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_store_vload(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i64 5, ptr addrspace(4) [[LOC:%.*]], align 8
; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8
; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]]
;
entry:
store i64 5, ptr addrspace(4) %loc
%ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc
ret <1 x ptr addrspace(4)> %ref
}
; Nulls have known bit patterns, so we can forward
define ptr addrspace(4) @forward_store_zero(ptr addrspace(4) %loc) {
; CHECK-LABEL: @forward_store_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i64 0, ptr addrspace(4) [[LOC:%.*]], align 8
; CHECK-NEXT: ret ptr addrspace(4) null
;
entry:
store i64 0, ptr addrspace(4) %loc
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
; Nulls have known bit patterns, so we can forward
define ptr addrspace(4) @forward_store_zero2(ptr addrspace(4) %loc) {
; CHECK-LABEL: @forward_store_zero2(
; CHECK-NEXT: entry:
; CHECK-NEXT: store <2 x i32> zeroinitializer, ptr addrspace(4) [[LOC:%.*]], align 8
; CHECK-NEXT: ret ptr addrspace(4) null
;
entry:
store <2 x i32> zeroinitializer, ptr addrspace(4) %loc
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
@NonZeroConstant = constant <4 x i64> <i64 3, i64 3, i64 3, i64 3>
@NonZeroConstant2 = constant <4 x ptr addrspace(4)> <
ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3),
ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3),
ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3),
ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3)>
@ZeroConstant = constant <4 x i64> zeroinitializer
; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.)
define ptr addrspace(4) @neg_forward_memcopy(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_memcopy(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false)
; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8
; CHECK-NEXT: ret ptr addrspace(4) [[REF]]
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false)
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
define ptr addrspace(4) @neg_forward_memcopy2(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_memcopy2(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false)
; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8
; CHECK-NEXT: ret ptr addrspace(4) [[REF]]
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false)
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
define ptr addrspace(4) @forward_memcopy(ptr addrspace(4) %loc) {
; CHECK-LABEL: @forward_memcopy(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 8, i1 false)
; CHECK-NEXT: ret ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3)
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 8, i1 false)
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
define ptr addrspace(4) @forward_memcopy2(ptr addrspace(4) %loc) {
; CHECK-LABEL: @forward_memcopy2(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 8, i1 false)
; CHECK-NEXT: ret ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3)
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 8, i1 false)
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
define <1 x ptr addrspace(4)> @neg_forward_memcpy_vload(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_memcpy_vload(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false)
; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8
; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]]
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false)
%ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc
ret <1 x ptr addrspace(4)> %ref
}
define <4 x ptr addrspace(4)> @neg_forward_memcpy_vload2(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_memcpy_vload2(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 32, i1 false)
; CHECK-NEXT: [[REF:%.*]] = load <4 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 32
; CHECK-NEXT: ret <4 x ptr addrspace(4)> [[REF]]
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 32, i1 false)
%ref = load <4 x ptr addrspace(4)>, ptr addrspace(4) %loc
ret <4 x ptr addrspace(4)> %ref
}
define <4 x i64> @neg_forward_memcpy_vload3(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_forward_memcpy_vload3(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 32, i1 false)
; CHECK-NEXT: [[REF:%.*]] = load <4 x i64>, ptr addrspace(4) [[LOC]], align 32
; CHECK-NEXT: ret <4 x i64> [[REF]]
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 32, i1 false)
%ref = load <4 x i64>, ptr addrspace(4) %loc
ret <4 x i64> %ref
}
define <1 x ptr addrspace(4)> @forward_memcpy_vload3(ptr addrspace(4) %loc) {
; CHECK-LABEL: @forward_memcpy_vload3(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 32, i1 false)
; CHECK-NEXT: ret <1 x ptr addrspace(4)> <ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3)>
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 32, i1 false)
%ref = load <4 x ptr addrspace(4)>, ptr addrspace(4) %loc
%val = extractelement <4 x ptr addrspace(4)> %ref, i32 0
%ret = insertelement <1 x ptr addrspace(4)> undef, ptr addrspace(4) %val, i32 0
ret <1 x ptr addrspace(4)> %ret
}
; Can forward since we can do so w/o breaking types
define ptr addrspace(4) @forward_memcpy_zero(ptr addrspace(4) %loc) {
; CHECK-LABEL: @forward_memcpy_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @ZeroConstant, i64 8, i1 false)
; CHECK-NEXT: ret ptr addrspace(4) null
;
entry:
call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @ZeroConstant, i64 8, i1 false)
%ref = load ptr addrspace(4), ptr addrspace(4) %loc
ret ptr addrspace(4) %ref
}
declare void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) nocapture, ptr nocapture, i64, i1) nounwind
; Same as the neg_forward_store cases, but for non defs.
; (Pretend we wrote out the alwaysfalse idiom above.)
define ptr addrspace(4) @neg_store_clobber(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_store_clobber(
; CHECK-NEXT: entry:
; CHECK-NEXT: store <2 x i64> <i64 4, i64 4>, ptr addrspace(4) [[LOC:%.*]], align 16
; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1
; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC_OFF]], align 8
; CHECK-NEXT: ret ptr addrspace(4) [[REF]]
;
entry:
store <2 x i64> <i64 4, i64 4>, ptr addrspace(4) %loc
%loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1
%ref = load ptr addrspace(4), ptr addrspace(4) %loc.off
ret ptr addrspace(4) %ref
}
declare void @use(<2 x i64>) inaccessiblememonly
; Same as the neg_forward_store cases, but for non defs.
; (Pretend we wrote out the alwaysfalse idiom above.)
define ptr addrspace(4) @neg_load_clobber(ptr addrspace(4) %loc) {
; CHECK-LABEL: @neg_load_clobber(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V:%.*]] = load <2 x i64>, ptr addrspace(4) [[LOC:%.*]], align 16
; CHECK-NEXT: call void @use(<2 x i64> [[V]])
; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1
; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC_OFF]], align 8
; CHECK-NEXT: ret ptr addrspace(4) [[REF]]
;
entry:
%v = load <2 x i64>, ptr addrspace(4) %loc
call void @use(<2 x i64> %v)
%loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1
%ref = load ptr addrspace(4), ptr addrspace(4) %loc.off
ret ptr addrspace(4) %ref
}
define ptr addrspace(4) @store_clobber_zero(ptr addrspace(4) %loc) {
; CHECK-LABEL: @store_clobber_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: store <2 x i64> zeroinitializer, ptr addrspace(4) [[LOC:%.*]], align 16
; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1
; CHECK-NEXT: ret ptr addrspace(4) null
;
entry:
store <2 x i64> zeroinitializer, ptr addrspace(4) %loc
%loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1
%ref = load ptr addrspace(4), ptr addrspace(4) %loc.off
ret ptr addrspace(4) %ref
}
define void @smaller_vector(ptr %p) {
; CHECK-LABEL: @smaller_vector(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V4:%.*]] = load <4 x ptr addrspace(4)>, ptr [[P:%.*]], align 32
; CHECK-NEXT: [[V2:%.*]] = load <2 x ptr addrspace(4)>, ptr [[P]], align 32
; CHECK-NEXT: call void @use.v2(<2 x ptr addrspace(4)> [[V2]])
; CHECK-NEXT: call void @use.v4(<4 x ptr addrspace(4)> [[V4]])
; CHECK-NEXT: ret void
;
entry:
%v4 = load <4 x ptr addrspace(4)>, ptr %p, align 32
%v2 = load <2 x ptr addrspace(4)>, ptr %p, align 32
call void @use.v2(<2 x ptr addrspace(4)> %v2)
call void @use.v4(<4 x ptr addrspace(4)> %v4)
ret void
}
define ptr addrspace(4) @vector_extract(ptr %p) {
; CHECK-LABEL: @vector_extract(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V4:%.*]] = load <4 x ptr addrspace(4)>, ptr [[P:%.*]], align 32
; CHECK-NEXT: [[RES:%.*]] = load ptr addrspace(4), ptr [[P]], align 32
; CHECK-NEXT: call void @use.v4(<4 x ptr addrspace(4)> [[V4]])
; CHECK-NEXT: ret ptr addrspace(4) [[RES]]
;
entry:
%v4 = load <4 x ptr addrspace(4)>, ptr %p, align 32
%res = load ptr addrspace(4), ptr %p, align 32
call void @use.v4(<4 x ptr addrspace(4)> %v4)
ret ptr addrspace(4) %res
}
declare void @use.v2(<2 x ptr addrspace(4)>)
declare void @use.v4(<4 x ptr addrspace(4)>)
define ptr addrspace(5) @multini(i1 %alwaysFalse, ptr addrspace(4) %val, ptr %loc) {
; CHECK-LABEL: @multini(
; CHECK-NEXT: entry:
; CHECK-NEXT: store ptr addrspace(4) [[VAL:%.*]], ptr [[LOC:%.*]], align 8
; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]]
; CHECK: neverTaken:
; CHECK-NEXT: [[DIFFERENTAS:%.*]] = load ptr addrspace(5), ptr [[LOC]], align 8
; CHECK-NEXT: ret ptr addrspace(5) [[DIFFERENTAS]]
; CHECK: alwaysTaken:
; CHECK-NEXT: ret ptr addrspace(5) null
;
entry:
store ptr addrspace(4) %val, ptr %loc
br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken
neverTaken:
%differentas = load ptr addrspace(5), ptr %loc
ret ptr addrspace(5) %differentas
alwaysTaken:
ret ptr addrspace(5) null
}