141 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=instcombine -S | FileCheck %s3 4declare noalias ptr @calloc(i32, i32) nounwind allockind("alloc,zeroed") allocsize(0,1) "alloc-family"="malloc"5declare void @free(ptr) allockind("free") "alloc-family"="malloc"6 7; Test load from uninitialized alloca - should be removed and replaced with undef8define i32 @test_load_uninitialized_alloca() {9; CHECK-LABEL: @test_load_uninitialized_alloca(10; CHECK-NEXT: ret i32 undef11;12 %a = alloca i3213 %v = load i32, ptr %a14 ret i32 %v15}16 17; Test load from zero-initialized malloc - should be removed and replaced with zero18define i32 @test_load_zero_initialized_malloc() {19; CHECK-LABEL: @test_load_zero_initialized_malloc(20; CHECK-NEXT: ret i32 021;22 %a = call ptr @calloc(i32 1, i32 4)23 %v = load i32, ptr %a24 call void @free(ptr %a)25 ret i32 %v26}27 28; Test memcpy from uninitialized source - should be removed29define void @test_memcpy_from_uninitialized_alloca(ptr %dest) {30; CHECK-LABEL: @test_memcpy_from_uninitialized_alloca(31; CHECK-NEXT: ret void32;33 %src = alloca i32, align 134 call void @llvm.memcpy.p0.p0.i32(ptr %src, ptr %src, i32 4, i1 false)35 call void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 4, i1 false)36 ret void37}38 39; Test memcpy from zeroed source - should transform to memset with zero40define void @test_memcpy_from_uninitialized_calloc(ptr %dest) {41; CHECK-LABEL: @test_memcpy_from_uninitialized_calloc(42; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(16) [[DEST:%.*]], i8 0, i32 16, i1 false)43; CHECK-NEXT: ret void44;45 %src = call ptr @calloc(i32 1, i32 16)46 call void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 16, i1 false)47 call void @free(ptr %src)48 ret void49}50 51; Test mixed read/write pattern - should not be removable due to write before read52define i32 @test_write_then_read_alloca() {53; CHECK-LABEL: @test_write_then_read_alloca(54; CHECK-NEXT: [[A:%.*]] = alloca i32, align 455; CHECK-NEXT: store i8 42, ptr [[A]], align 156; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 457; CHECK-NEXT: ret i32 [[V]]58;59 %a = alloca i3260 store i8 42, ptr %a61 %v = load i32, ptr %a62 ret i32 %v63}64 65; Test read then write pattern - should not be removable due to conflicting access66define void @test_read_then_write_alloca() {67; CHECK-LABEL: @test_read_then_write_alloca(68; CHECK-NEXT: [[A:%.*]] = alloca i32, align 469; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 470; CHECK-NEXT: [[V8:%.*]] = trunc i32 [[V]] to i871; CHECK-NEXT: store i8 [[V8]], ptr [[A]], align 172; CHECK-NEXT: ret void73;74 %a = alloca i3275 %v = load i32, ptr %a76 %v8 = trunc i32 %v to i877 store i8 %v8, ptr %a78 ret void79}80 81; Test load through GEP from uninitialized alloca82define i8 @test_load_gep_uninitialized_alloca() {83; CHECK-LABEL: @test_load_gep_uninitialized_alloca(84; CHECK-NEXT: ret i8 undef85;86 %a = alloca [4 x i8]87 %gep = getelementptr [4 x i8], ptr %a, i32 0, i32 288 %v = load i8, ptr %gep89 ret i8 %v90}91 92; Test load through bitcast from uninitialized alloca93define i16 @test_load_bitcast_uninitialized_alloca() {94; CHECK-LABEL: @test_load_bitcast_uninitialized_alloca(95; CHECK-NEXT: ret i16 undef96;97 %a = alloca i3298 %bc = bitcast ptr %a to ptr99 %v = load i16, ptr %bc100 ret i16 %v101}102 103; Test memmove from zero-initialized malloc104define void @test_memmove_from_zero_initialized_malloc(ptr %dest) {105; CHECK-LABEL: @test_memmove_from_zero_initialized_malloc(106; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(32) [[DEST:%.*]], i8 0, i32 32, i1 false)107; CHECK-NEXT: ret void108;109 %src = call ptr @calloc(i32 8, i32 4)110 call void @llvm.memmove.p0.p0.i32(ptr %dest, ptr %src, i32 32, i1 false)111 call void @free(ptr %src)112 ret void113}114 115; Test multiple loads from same uninitialized alloca116define { i32, i32 } @test_multiple_loads_uninitialized_alloca() {117; CHECK-LABEL: @test_multiple_loads_uninitialized_alloca(118; CHECK-NEXT: ret { i32, i32 } undef119;120 %a = alloca [2 x i32]121 %gep1 = getelementptr [2 x i32], ptr %a, i32 0, i32 0122 %gep2 = getelementptr [2 x i32], ptr %a, i32 0, i32 1123 %v1 = load i32, ptr %gep1124 %v2 = load i32, ptr %gep2125 %ret = insertvalue { i32, i32 } { i32 undef, i32 poison }, i32 %v1, 0126 %ret2 = insertvalue { i32, i32 } %ret, i32 %v2, 1127 ret { i32, i32 } %ret2128}129 130; Test that volatile operations prevent removal131define i32 @test_volatile_load_prevents_removal() {132; CHECK-LABEL: @test_volatile_load_prevents_removal(133; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4134; CHECK-NEXT: [[V:%.*]] = load volatile i32, ptr [[A]], align 4135; CHECK-NEXT: ret i32 [[V]]136;137 %a = alloca i32138 %v = load volatile i32, ptr %a139 ret i32 %v140}141