1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=aggressive-instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=CHECK,LE 3; RUN: opt < %s -passes=aggressive-instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=CHECK,BE 4 5 6@constarray1 = internal constant [8 x i8] c"\01\00\01\00\01\00\01\00", align 4 7@constarray2 = internal constant [8 x i8] c"\FF\FF\01\00\01\00\01\00", align 4 8 9@g = internal constant i32 42 10@constptrarray = internal constant [4 x ptr] [ptr @g, ptr @g, ptr @g, ptr @g], align 4 11 12@constpackedstruct = internal constant <{[8 x i8]}> <{[8 x i8] c"\01\00\01\00\01\00\01\00"}>, align 4 13@conststruct = internal constant {i16, [8 x i8]} {i16 1, [8 x i8] c"\01\00\01\00\01\00\01\00"}, align 4 14 15%struct = type { i128 } 16@global = internal constant %struct { i128 1 } 17; TODO: this should be folded, but currently i128 is not folded. 18define i32 @no-gep-128-struct(i64 %idx){ 19; CHECK-LABEL: @no-gep-128-struct( 20; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @global, align 4 21; CHECK-NEXT: ret i32 [[TMP1]] 22; 23 %1 = load i32, ptr @global, align 4 24 ret i32 %1 25} 26 27define i8 @inbounds_gep_load_i8_align2(i64 %idx){ 28; CHECK-LABEL: @inbounds_gep_load_i8_align2( 29; CHECK-NEXT: ret i8 1 30; 31 %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx 32 %2 = load i8, ptr %1, align 2 33 ret i8 %2 34} 35 36; can't be folded because access with i8 strides is not patterned. 37define i8 @inbounds_gep_load_i8_align1(i64 %idx){ 38; CHECK-LABEL: @inbounds_gep_load_i8_align1( 39; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constarray1, i64 [[IDX:%.*]] 40; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 41; CHECK-NEXT: ret i8 [[TMP2]] 42; 43 %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx 44 %2 = load i8, ptr %1, align 1 45 ret i8 %2 46} 47 48; can't be folded because volatile load cannot assure same results. 49define i8 @inbounds_gep_load_i8_align2_volatile(i64 %idx){ 50; CHECK-LABEL: @inbounds_gep_load_i8_align2_volatile( 51; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constarray1, i64 [[IDX:%.*]] 52; CHECK-NEXT: [[TMP2:%.*]] = load volatile i8, ptr [[TMP1]], align 2 53; CHECK-NEXT: ret i8 [[TMP2]] 54; 55 %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx 56 %2 = load volatile i8, ptr %1, align 2 57 ret i8 %2 58} 59 60declare ptr @llvm.ptrmask.p0.i64(ptr , i64) 61 62; can't be folded because ptrmask can change ptr, while preserving provenance 63; This invalidates GEP indices analysis 64define i8 @inbounds_gep_load_i16_align1_ptrmasked(i64 %idx, i64 %mask){ 65; CHECK-LABEL: @inbounds_gep_load_i16_align1_ptrmasked( 66; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr @constarray1, i64 [[MASK:%.*]]) 67; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i16, ptr [[TMP1]], i64 [[IDX:%.*]] 68; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[TMP2]], align 1 69; CHECK-NEXT: ret i8 [[TMP3]] 70; 71 %1 = call ptr @llvm.ptrmask.p0.i64(ptr @constarray1, i64 %mask) 72 %2 = getelementptr inbounds i16, ptr %1, i64 %idx 73 %3 = load i8, ptr %2, align 1 74 ret i8 %3 75} 76 77define i32 @inbounds_gep_i16_load_i32_align1(i64 %idx){ 78; LE-LABEL: @inbounds_gep_i16_load_i32_align1( 79; LE-NEXT: ret i32 65537 80; 81; BE-LABEL: @inbounds_gep_i16_load_i32_align1( 82; BE-NEXT: ret i32 16777472 83; 84 %1 = getelementptr inbounds i16, ptr @constarray1, i64 %idx 85 %2 = load i32, ptr %1, align 1 86 ret i32 %2 87} 88 89define i32 @inbounds_gep_i32_load_i32_align8(i64 %idx){ 90; LE-LABEL: @inbounds_gep_i32_load_i32_align8( 91; LE-NEXT: ret i32 65537 92; 93; BE-LABEL: @inbounds_gep_i32_load_i32_align8( 94; BE-NEXT: ret i32 16777472 95; 96 %1 = getelementptr inbounds i32, ptr @constarray1, i64 %idx 97 %2 = load i32, ptr %1, align 8 98 ret i32 %2 99} 100 101define i32 @inbounds_gep_i32_load_i32_const_offset(i64 %idx){ 102; LE-LABEL: @inbounds_gep_i32_load_i32_const_offset( 103; LE-NEXT: ret i32 65537 104; 105; BE-LABEL: @inbounds_gep_i32_load_i32_const_offset( 106; BE-NEXT: ret i32 16777472 107; 108 %1 = getelementptr inbounds i16, ptr @constarray2, i64 1 109 %2 = getelementptr inbounds i32, ptr %1, i64 %idx 110 %3 = load i32, ptr %2, align 4 111 ret i32 %3 112} 113 114define i32 @gep_load_i32_align2_const_offset(i64 %idx){ 115; LE-LABEL: @gep_load_i32_align2_const_offset( 116; LE-NEXT: ret i32 65537 117; 118; BE-LABEL: @gep_load_i32_align2_const_offset( 119; BE-NEXT: ret i32 16777472 120; 121 %1 = getelementptr i16, ptr @constarray1, i64 -2 122 %2 = getelementptr [3 x i16], ptr %1, i64 %idx 123 %3 = load i32, ptr %2, align 2 124 ret i32 %3 125} 126 127; can't be folded because if gep is non-inbounds, 128; the offsets are silently-wrapped with two’s complement arithmetic(mod 2**64). 129; So the load operand can be a base pointer of constarray2. 130define i32 @gep_load_i32_align2_const_offset_wrap(i64 %idx){ 131; CHECK-LABEL: @gep_load_i32_align2_const_offset_wrap( 132; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i16, ptr @constarray2, i64 -2 133; CHECK-NEXT: [[TMP2:%.*]] = getelementptr [3 x i16], ptr [[TMP1]], i64 [[IDX:%.*]] 134; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 2 135; CHECK-NEXT: ret i32 [[TMP3]] 136; 137 %1 = getelementptr i16, ptr @constarray2, i64 -2 138 %2 = getelementptr [3 x i16], ptr %1, i64 %idx 139 %3 = load i32, ptr %2, align 2 140 ret i32 %3 141} 142 143define i32 @inbounds_gep_i32_load_i32_const_ptr_array(i64 %idx){ 144; CHECK-LABEL: @inbounds_gep_i32_load_i32_const_ptr_array( 145; CHECK-NEXT: ret i32 42 146; 147 %1 = getelementptr inbounds ptr, ptr @constptrarray, i64 %idx 148 %2 = load ptr, ptr %1, align 4 149 %3 = load i32, ptr %2, align 4 150 ret i32 %3 151} 152 153define i32 @inbounds_gep_i32_load_i32_align4_packedstruct(i64 %idx){ 154; LE-LABEL: @inbounds_gep_i32_load_i32_align4_packedstruct( 155; LE-NEXT: ret i32 65537 156; 157; BE-LABEL: @inbounds_gep_i32_load_i32_align4_packedstruct( 158; BE-NEXT: ret i32 16777472 159; 160 %1 = getelementptr inbounds i32, ptr @constpackedstruct, i64 %idx 161 %2 = load i32, ptr %1, align 4 162 ret i32 %2 163} 164 165; can't be folded because results are not equal 166define i32 @inbounds_gep_i8_load_i32_align1_packedstruct(i64 %idx){ 167; CHECK-LABEL: @inbounds_gep_i8_load_i32_align1_packedstruct( 168; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constpackedstruct, i64 [[IDX:%.*]] 169; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 1 170; CHECK-NEXT: ret i32 [[TMP2]] 171; 172 %1 = getelementptr inbounds i8, ptr @constpackedstruct, i64 %idx 173 %2 = load i32, ptr %1, align 1 174 ret i32 %2 175} 176 177define i32 @inbounds_gep_i32_load_i32_align4_struct_with_const_offset(i64 %idx){ 178; LE-LABEL: @inbounds_gep_i32_load_i32_align4_struct_with_const_offset( 179; LE-NEXT: ret i32 65537 180; 181; BE-LABEL: @inbounds_gep_i32_load_i32_align4_struct_with_const_offset( 182; BE-NEXT: ret i32 16777472 183; 184 %1 = getelementptr inbounds i16, ptr @conststruct, i64 1 185 %2 = getelementptr inbounds i32, ptr %1, i64 %idx 186 %3 = load i32, ptr %2, align 4 187 ret i32 %3 188} 189 190