; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
define i32 @fold(i32 %x) {
; CHECK-LABEL: @fold(
; CHECK-NEXT: [[Y:%.*]] = freeze i32 [[X:%.*]]
; CHECK-NEXT: ret i32 [[Y]]
;
%y = freeze i32 %x
%z = freeze i32 %y
ret i32 %z
}
define i32 @make_const() {
; CHECK-LABEL: @make_const(
; CHECK-NEXT: ret i32 10
;
%x = freeze i32 10
ret i32 %x
}
define float @make_const2() {
; CHECK-LABEL: @make_const2(
; CHECK-NEXT: ret float 1.000000e+01
;
%x = freeze float 10.0
ret float %x
}
@glb = constant i32 0
define ptr @make_const_glb() {
; CHECK-LABEL: @make_const_glb(
; CHECK-NEXT: ret ptr @glb
;
%k = freeze ptr @glb
ret ptr %k
}
define ptr @make_const_fn() {
; CHECK-LABEL: @make_const_fn(
; CHECK-NEXT: ret ptr @make_const
;
%k = freeze ptr @make_const
ret ptr %k
}
define ptr @make_const_null() {
; CHECK-LABEL: @make_const_null(
; CHECK-NEXT: ret ptr null
;
%k = freeze ptr null
ret ptr %k
}
define <2 x i32> @constvector() {
; CHECK-LABEL: @constvector(
; CHECK-NEXT: ret <2 x i32> <i32 0, i32 1>
;
%x = freeze <2 x i32> <i32 0, i32 1>
ret <2 x i32> %x
}
define <3 x i5> @constvector_weird() {
; CHECK-LABEL: @constvector_weird(
; CHECK-NEXT: ret <3 x i5> <i5 0, i5 1, i5 10>
;
%x = freeze <3 x i5> <i5 0, i5 1, i5 42>
ret <3 x i5> %x
}
define <2 x float> @constvector_FP() {
; CHECK-LABEL: @constvector_FP(
; CHECK-NEXT: ret <2 x float> <float 0.000000e+00, float 1.000000e+00>
;
%x = freeze <2 x float> <float 0.0, float 1.0>
ret <2 x float> %x
}
; Negative test
define <2 x i32> @constvector_noopt() {
; CHECK-LABEL: @constvector_noopt(
; CHECK-NEXT: [[X:%.*]] = freeze <2 x i32> <i32 0, i32 undef>
; CHECK-NEXT: ret <2 x i32> [[X]]
;
%x = freeze <2 x i32> <i32 0, i32 undef>
ret <2 x i32> %x
}
; Negative test
define <3 x i5> @constvector_weird_noopt() {
; CHECK-LABEL: @constvector_weird_noopt(
; CHECK-NEXT: [[X:%.*]] = freeze <3 x i5> <i5 0, i5 undef, i5 10>
; CHECK-NEXT: ret <3 x i5> [[X]]
;
%x = freeze <3 x i5> <i5 0, i5 undef, i5 42>
ret <3 x i5> %x
}
; Negative test
define <2 x float> @constvector_FP_noopt() {
; CHECK-LABEL: @constvector_FP_noopt(
; CHECK-NEXT: [[X:%.*]] = freeze <2 x float> <float 0.000000e+00, float undef>
; CHECK-NEXT: ret <2 x float> [[X]]
;
%x = freeze <2 x float> <float 0.0, float undef>
ret <2 x float> %x
}
@g = external global i16, align 1
@g2 = external global i16, align 1
define float @constant_expr() {
; CHECK-LABEL: @constant_expr(
; CHECK-NEXT: ret float bitcast (i32 ptrtoint (ptr @g to i32) to float)
;
%r = freeze float bitcast (i32 ptrtoint (ptr @g to i32) to float)
ret float %r
}
define ptr @constant_expr2() {
; CHECK-LABEL: @constant_expr2(
; CHECK-NEXT: ret ptr @g
;
%r = freeze ptr @g
ret ptr %r
}
define ptr @constant_expr3() {
; CHECK-LABEL: @constant_expr3(
; CHECK-NEXT: ret ptr getelementptr (i32, ptr @glb, i64 3)
;
%r = freeze ptr getelementptr (i32, ptr @glb, i64 3)
ret ptr %r
}
define i64 @ptrdiff() {
; CHECK-LABEL: @ptrdiff(
; CHECK-NEXT: ret i64 sub (i64 ptrtoint (ptr @g to i64), i64 ptrtoint (ptr @g2 to i64))
;
%i = ptrtoint ptr @g to i64
%i2 = ptrtoint ptr @g2 to i64
%diff = sub i64 %i, %i2
%r = freeze i64 %diff
ret i64 %r
}
; Negative test
define <2 x i31> @vector_element_constant_expr() {
; CHECK-LABEL: @vector_element_constant_expr(
; CHECK-NEXT: [[R:%.*]] = freeze <2 x i31> <i31 34, i31 ptrtoint (ptr @g to i31)>
; CHECK-NEXT: ret <2 x i31> [[R]]
;
%r = freeze <2 x i31> <i31 34, i31 ptrtoint (ptr @g to i31)>
ret <2 x i31> %r
}
define void @alloca() {
; CHECK-LABEL: @alloca(
; CHECK-NEXT: [[P:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @f3(ptr [[P]])
; CHECK-NEXT: ret void
;
%p = alloca i8
%y = freeze ptr %p
call void @f3(ptr %y)
ret void
}
define ptr @gep() {
; CHECK-LABEL: @gep(
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8], align 1
; CHECK-NEXT: [[Q:%.*]] = getelementptr [4 x i8], ptr [[P]], i32 0, i32 6
; CHECK-NEXT: ret ptr [[Q]]
;
%p = alloca [4 x i8]
%q = getelementptr [4 x i8], ptr %p, i32 0, i32 6
%q2 = freeze ptr %q
ret ptr %q2
}
define ptr @gep_noopt(i32 %arg) {
; CHECK-LABEL: @gep_noopt(
; CHECK-NEXT: [[Q:%.*]] = getelementptr [4 x i8], ptr null, i32 0, i32 [[ARG:%.*]]
; CHECK-NEXT: [[Q2:%.*]] = freeze ptr [[Q]]
; CHECK-NEXT: ret ptr [[Q2]]
;
%q = getelementptr [4 x i8], ptr null, i32 0, i32 %arg
%q2 = freeze ptr %q
ret ptr %q2
}
define ptr @gep_inbounds() {
; CHECK-LABEL: @gep_inbounds(
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8], align 1
; CHECK-NEXT: ret ptr [[P]]
;
%p = alloca [4 x i8]
%q2 = freeze ptr %p
ret ptr %q2
}
define ptr @gep_inbounds_noopt(i32 %arg) {
; CHECK-LABEL: @gep_inbounds_noopt(
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8], align 1
; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds [4 x i8], ptr [[P]], i32 0, i32 [[ARG:%.*]]
; CHECK-NEXT: [[Q2:%.*]] = freeze ptr [[Q]]
; CHECK-NEXT: ret ptr [[Q2]]
;
%p = alloca [4 x i8]
%q = getelementptr inbounds [4 x i8], ptr %p, i32 0, i32 %arg
%q2 = freeze ptr %q
ret ptr %q2
}
define ptr @gep_inbounds_null() {
; CHECK-LABEL: @gep_inbounds_null(
; CHECK-NEXT: ret ptr null
;
%k = freeze ptr null
ret ptr %k
}
define ptr @gep_inbounds_null_noopt(ptr %p) {
; CHECK-LABEL: @gep_inbounds_null_noopt(
; CHECK-NEXT: [[K:%.*]] = freeze ptr [[P:%.*]]
; CHECK-NEXT: ret ptr [[K]]
;
%k = freeze ptr %p
ret ptr %k
}
define ptr @load_ptr(ptr %ptr) {
; CHECK-LABEL: @load_ptr(
; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[PTR:%.*]], align 1
; CHECK-NEXT: call void @f4(i8 [[V]])
; CHECK-NEXT: ret ptr [[PTR]]
;
%v = load i8, ptr %ptr
%q = freeze ptr %ptr
call void @f4(i8 %v) ; prevents %v from being DCEd
ret ptr %q
}
define ptr @store_ptr(ptr %ptr) {
; CHECK-LABEL: @store_ptr(
; CHECK-NEXT: store i8 0, ptr [[PTR:%.*]], align 1
; CHECK-NEXT: ret ptr [[PTR]]
;
store i8 0, ptr %ptr
%q = freeze ptr %ptr
ret ptr %q
}
define ptr @call_noundef_ptr(ptr %ptr) {
; CHECK-LABEL: @call_noundef_ptr(
; CHECK-NEXT: call void @f3(ptr noundef [[PTR:%.*]])
; CHECK-NEXT: ret ptr [[PTR]]
;
call void @f3(ptr noundef %ptr)
%q = freeze ptr %ptr
ret ptr %q
}
define ptr @invoke_noundef_ptr(ptr %ptr) personality i8 1 {
; CHECK-LABEL: @invoke_noundef_ptr(
; CHECK-NEXT: invoke void @f3(ptr noundef [[PTR:%.*]])
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[UNWIND:%.*]]
; CHECK: normal:
; CHECK-NEXT: ret ptr [[PTR]]
; CHECK: unwind:
; CHECK-NEXT: [[TMP1:%.*]] = landingpad ptr
; CHECK-NEXT: cleanup
; CHECK-NEXT: resume ptr [[PTR]]
;
%q = freeze ptr %ptr
invoke void @f3(ptr noundef %ptr) to label %normal unwind label %unwind
normal:
ret ptr %q
unwind:
landingpad ptr cleanup
resume ptr %q
}
define ptr @cmpxchg_ptr(ptr %ptr) {
; CHECK-LABEL: @cmpxchg_ptr(
; CHECK-NEXT: [[TMP1:%.*]] = cmpxchg ptr [[PTR:%.*]], i8 1, i8 2 acq_rel monotonic, align 1
; CHECK-NEXT: ret ptr [[PTR]]
;
cmpxchg ptr %ptr, i8 1, i8 2 acq_rel monotonic
%q = freeze ptr %ptr
ret ptr %q
}
define ptr @atomicrmw_ptr(ptr %ptr) {
; CHECK-LABEL: @atomicrmw_ptr(
; CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[PTR:%.*]], i8 1 acquire, align 1
; CHECK-NEXT: ret ptr [[PTR]]
;
atomicrmw add ptr %ptr, i8 1 acquire
%q = freeze ptr %ptr
ret ptr %q
}
define i1 @icmp(i32 %a, i32 %b) {
; CHECK-LABEL: @icmp(
; CHECK-NEXT: [[A_FR:%.*]] = freeze i32 [[A:%.*]]
; CHECK-NEXT: [[B_FR:%.*]] = freeze i32 [[B:%.*]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[A_FR]], [[B_FR]]
; CHECK-NEXT: ret i1 [[C]]
;
%a.fr = freeze i32 %a
%b.fr = freeze i32 %b
%c = icmp eq i32 %a.fr, %b.fr
%c.fr = freeze i1 %c
ret i1 %c.fr
}
define i1 @icmp_noopt(i32 %a, i32 %b) {
; CHECK-LABEL: @icmp_noopt(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[C_FR:%.*]] = freeze i1 [[C]]
; CHECK-NEXT: ret i1 [[C_FR]]
;
%c = icmp eq i32 %a, %b
%c.fr = freeze i1 %c
ret i1 %c.fr
}
define i1 @fcmp(float %x, float %y) {
; CHECK-LABEL: @fcmp(
; CHECK-NEXT: [[FX:%.*]] = freeze float [[X:%.*]]
; CHECK-NEXT: [[FY:%.*]] = freeze float [[Y:%.*]]
; CHECK-NEXT: [[C:%.*]] = fcmp oeq float [[FX]], [[FY]]
; CHECK-NEXT: ret i1 [[C]]
;
%fx = freeze float %x
%fy = freeze float %y
%c = fcmp oeq float %fx, %fy
%fc = freeze i1 %c
ret i1 %fc
}
define i1 @fcmp_noopt(float %x, float %y) {
; CHECK-LABEL: @fcmp_noopt(
; CHECK-NEXT: [[FX:%.*]] = freeze float [[X:%.*]]
; CHECK-NEXT: [[FY:%.*]] = freeze float [[Y:%.*]]
; CHECK-NEXT: [[C:%.*]] = fcmp nnan oeq float [[FX]], [[FY]]
; CHECK-NEXT: [[FC:%.*]] = freeze i1 [[C]]
; CHECK-NEXT: ret i1 [[FC]]
;
%fx = freeze float %x
%fy = freeze float %y
%c = fcmp nnan oeq float %fx, %fy
%fc = freeze i1 %c
ret i1 %fc
}
define i1 @brcond(i1 %c, i1 %c2) {
; CHECK-LABEL: @brcond(
; CHECK-NEXT: br i1 [[C:%.*]], label [[A:%.*]], label [[B:%.*]]
; CHECK: A:
; CHECK-NEXT: br i1 [[C2:%.*]], label [[A2:%.*]], label [[B]]
; CHECK: A2:
; CHECK-NEXT: ret i1 [[C]]
; CHECK: B:
; CHECK-NEXT: ret i1 [[C]]
;
br i1 %c, label %A, label %B
A:
br i1 %c2, label %A2, label %B
A2:
%f1 = freeze i1 %c
ret i1 %f1
B:
%f2 = freeze i1 %c
ret i1 %f2
}
define i32 @phi(i1 %cond, i1 %cond2, i32 %a0, i32 %a1) {
; CHECK-LABEL: @phi(
; CHECK-NEXT: ENTRY:
; CHECK-NEXT: [[A0_FR:%.*]] = freeze i32 [[A0:%.*]]
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: BB1:
; CHECK-NEXT: [[A1_FR:%.*]] = freeze i32 [[A1:%.*]]
; CHECK-NEXT: br i1 [[COND2:%.*]], label [[BB2]], label [[EXIT:%.*]]
; CHECK: BB2:
; CHECK-NEXT: [[PHI1:%.*]] = phi i32 [ [[A0_FR]], [[ENTRY:%.*]] ], [ [[A1_FR]], [[BB1]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: EXIT:
; CHECK-NEXT: [[PHI2:%.*]] = phi i32 [ [[A0_FR]], [[BB1]] ], [ [[PHI1]], [[BB2]] ]
; CHECK-NEXT: ret i32 [[PHI2]]
;
ENTRY:
%a0.fr = freeze i32 %a0
br i1 %cond, label %BB1, label %BB2
BB1:
%a1.fr = freeze i32 %a1
br i1 %cond2, label %BB2, label %EXIT
BB2:
%phi1 = phi i32 [%a0.fr, %ENTRY], [%a1.fr, %BB1]
br label %EXIT
EXIT:
%phi2 = phi i32 [%a0.fr, %BB1], [%phi1, %BB2]
%phi2.fr = freeze i32 %phi2
ret i32 %phi2.fr
}
define i32 @phi_noopt(i1 %cond, i1 %cond2, i32 %a0, i32 %a1) {
; CHECK-LABEL: @phi_noopt(
; CHECK-NEXT: ENTRY:
; CHECK-NEXT: [[A0_FR:%.*]] = freeze i32 [[A0:%.*]]
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: BB1:
; CHECK-NEXT: br i1 [[COND2:%.*]], label [[BB2]], label [[EXIT:%.*]]
; CHECK: BB2:
; CHECK-NEXT: [[PHI1:%.*]] = phi i32 [ [[A0_FR]], [[ENTRY:%.*]] ], [ [[A1:%.*]], [[BB1]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: EXIT:
; CHECK-NEXT: [[PHI2:%.*]] = phi i32 [ [[A0_FR]], [[BB1]] ], [ [[PHI1]], [[BB2]] ]
; CHECK-NEXT: [[PHI2_FR:%.*]] = freeze i32 [[PHI2]]
; CHECK-NEXT: ret i32 [[PHI2_FR]]
;
ENTRY:
%a0.fr = freeze i32 %a0
br i1 %cond, label %BB1, label %BB2
BB1:
br i1 %cond2, label %BB2, label %EXIT
BB2:
%phi1 = phi i32 [%a0.fr, %ENTRY], [%a1, %BB1]
br label %EXIT
EXIT:
%phi2 = phi i32 [%a0.fr, %BB1], [%phi1, %BB2]
%phi2.fr = freeze i32 %phi2
ret i32 %phi2.fr
}
define i32 @brcond_switch(i32 %x) {
; CHECK-LABEL: @brcond_switch(
; CHECK-NEXT: switch i32 [[X:%.*]], label [[EXIT:%.*]] [
; CHECK-NEXT: i32 0, label [[A:%.*]]
; CHECK-NEXT: ]
; CHECK: A:
; CHECK-NEXT: ret i32 [[X]]
; CHECK: EXIT:
; CHECK-NEXT: ret i32 [[X]]
;
switch i32 %x, label %EXIT [ i32 0, label %A ]
A:
%fr1 = freeze i32 %x
ret i32 %fr1
EXIT:
%fr2 = freeze i32 %x
ret i32 %fr2
}
declare i32 @any_num()
define i32 @brcond_call() {
; CHECK-LABEL: @brcond_call(
; CHECK-NEXT: [[X:%.*]] = call i32 @any_num()
; CHECK-NEXT: switch i32 [[X]], label [[EXIT:%.*]] [
; CHECK-NEXT: ]
; CHECK: EXIT:
; CHECK-NEXT: ret i32 [[X]]
;
%x = call i32 @any_num()
switch i32 %x, label %EXIT []
EXIT:
%y = freeze i32 %x
ret i32 %y
}
define i1 @brcond_noopt(i1 %c, i1 %c2) {
; CHECK-LABEL: @brcond_noopt(
; CHECK-NEXT: [[F:%.*]] = freeze i1 [[C:%.*]]
; CHECK-NEXT: call void @f1(i1 [[F]])
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
; CHECK: A:
; CHECK-NEXT: ret i1 false
; CHECK: B:
; CHECK-NEXT: ret i1 true
;
%f = freeze i1 %c
call void @f1(i1 %f) ; cannot optimize i1 %f to %c
call void @f2() ; .. because if f2() exits, `br %c` cannot be reached
br i1 %c, label %A, label %B
A:
ret i1 0
B:
ret i1 1
}
declare void @f1(i1)
declare void @f2()
declare void @f3(ptr)
declare void @f4(i8)