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