; 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)