| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | |
| ; RUN: opt < %s -passes=aggressive-instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=CHECK,LE | |
| ; RUN: opt < %s -passes=aggressive-instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=CHECK,BE | |
| @constarray1 = internal constant [8 x i8] c"\01\00\01\00\01\00\01\00", align 4 | |
| @constarray2 = internal constant [8 x i8] c"\FF\FF\01\00\01\00\01\00", align 4 | |
| @g = internal constant i32 42 | |
| @constptrarray = internal constant [4 x ptr] [ptr @g, ptr @g, ptr @g, ptr @g], align 4 | |
| @constpackedstruct = internal constant <{[8 x i8]}> <{[8 x i8] c"\01\00\01\00\01\00\01\00"}>, align 4 | |
| @conststruct = internal constant {i16, [8 x i8]} {i16 1, [8 x i8] c"\01\00\01\00\01\00\01\00"}, align 4 | |
| %struct = type { i128 } | |
| @global = internal constant %struct { i128 1 } | |
| ; TODO: this should be folded, but currently i128 is not folded. | |
| define i32 @no-gep-128-struct(i64 %idx){ | |
| ; CHECK-LABEL: @no-gep-128-struct( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @global, align 4 | |
| ; CHECK-NEXT: ret i32 [[TMP1]] | |
| ; | |
| %1 = load i32, ptr @global, align 4 | |
| ret i32 %1 | |
| } | |
| define i8 @inbounds_gep_load_i8_align2(i64 %idx){ | |
| ; CHECK-LABEL: @inbounds_gep_load_i8_align2( | |
| ; CHECK-NEXT: ret i8 1 | |
| ; | |
| %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx | |
| %2 = load i8, ptr %1, align 2 | |
| ret i8 %2 | |
| } | |
| ; can't be folded because access with i8 strides is not patterned. | |
| define i8 @inbounds_gep_load_i8_align1(i64 %idx){ | |
| ; CHECK-LABEL: @inbounds_gep_load_i8_align1( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constarray1, i64 [[IDX:%.*]] | |
| ; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 | |
| ; CHECK-NEXT: ret i8 [[TMP2]] | |
| ; | |
| %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx | |
| %2 = load i8, ptr %1, align 1 | |
| ret i8 %2 | |
| } | |
| ; can't be folded because volatile load cannot assure same results. | |
| define i8 @inbounds_gep_load_i8_align2_volatile(i64 %idx){ | |
| ; CHECK-LABEL: @inbounds_gep_load_i8_align2_volatile( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constarray1, i64 [[IDX:%.*]] | |
| ; CHECK-NEXT: [[TMP2:%.*]] = load volatile i8, ptr [[TMP1]], align 2 | |
| ; CHECK-NEXT: ret i8 [[TMP2]] | |
| ; | |
| %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx | |
| %2 = load volatile i8, ptr %1, align 2 | |
| ret i8 %2 | |
| } | |
| declare ptr @llvm.ptrmask.p0.i64(ptr , i64) | |
| ; can't be folded because ptrmask can change ptr, while preserving provenance | |
| ; This invalidates GEP indices analysis | |
| define i8 @inbounds_gep_load_i16_align1_ptrmasked(i64 %idx, i64 %mask){ | |
| ; CHECK-LABEL: @inbounds_gep_load_i16_align1_ptrmasked( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr @constarray1, i64 [[MASK:%.*]]) | |
| ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i16, ptr [[TMP1]], i64 [[IDX:%.*]] | |
| ; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[TMP2]], align 1 | |
| ; CHECK-NEXT: ret i8 [[TMP3]] | |
| ; | |
| %1 = call ptr @llvm.ptrmask.p0.i64(ptr @constarray1, i64 %mask) | |
| %2 = getelementptr inbounds i16, ptr %1, i64 %idx | |
| %3 = load i8, ptr %2, align 1 | |
| ret i8 %3 | |
| } | |
| define i32 @inbounds_gep_i16_load_i32_align1(i64 %idx){ | |
| ; LE-LABEL: @inbounds_gep_i16_load_i32_align1( | |
| ; LE-NEXT: ret i32 65537 | |
| ; | |
| ; BE-LABEL: @inbounds_gep_i16_load_i32_align1( | |
| ; BE-NEXT: ret i32 16777472 | |
| ; | |
| %1 = getelementptr inbounds i16, ptr @constarray1, i64 %idx | |
| %2 = load i32, ptr %1, align 1 | |
| ret i32 %2 | |
| } | |
| define i32 @inbounds_gep_i32_load_i32_align8(i64 %idx){ | |
| ; LE-LABEL: @inbounds_gep_i32_load_i32_align8( | |
| ; LE-NEXT: ret i32 65537 | |
| ; | |
| ; BE-LABEL: @inbounds_gep_i32_load_i32_align8( | |
| ; BE-NEXT: ret i32 16777472 | |
| ; | |
| %1 = getelementptr inbounds i32, ptr @constarray1, i64 %idx | |
| %2 = load i32, ptr %1, align 8 | |
| ret i32 %2 | |
| } | |
| define i32 @inbounds_gep_i32_load_i32_const_offset(i64 %idx){ | |
| ; LE-LABEL: @inbounds_gep_i32_load_i32_const_offset( | |
| ; LE-NEXT: ret i32 65537 | |
| ; | |
| ; BE-LABEL: @inbounds_gep_i32_load_i32_const_offset( | |
| ; BE-NEXT: ret i32 16777472 | |
| ; | |
| %1 = getelementptr inbounds i16, ptr @constarray2, i64 1 | |
| %2 = getelementptr inbounds i32, ptr %1, i64 %idx | |
| %3 = load i32, ptr %2, align 4 | |
| ret i32 %3 | |
| } | |
| define i32 @gep_load_i32_align2_const_offset(i64 %idx){ | |
| ; LE-LABEL: @gep_load_i32_align2_const_offset( | |
| ; LE-NEXT: ret i32 65537 | |
| ; | |
| ; BE-LABEL: @gep_load_i32_align2_const_offset( | |
| ; BE-NEXT: ret i32 16777472 | |
| ; | |
| %1 = getelementptr i16, ptr @constarray1, i64 -2 | |
| %2 = getelementptr [3 x i16], ptr %1, i64 %idx | |
| %3 = load i32, ptr %2, align 2 | |
| ret i32 %3 | |
| } | |
| ; can't be folded because if gep is non-inbounds, | |
| ; the offsets are silently-wrapped with two’s complement arithmetic(mod 2**64). | |
| ; So the load operand can be a base pointer of constarray2. | |
| define i32 @gep_load_i32_align2_const_offset_wrap(i64 %idx){ | |
| ; CHECK-LABEL: @gep_load_i32_align2_const_offset_wrap( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i16, ptr @constarray2, i64 -2 | |
| ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr [3 x i16], ptr [[TMP1]], i64 [[IDX:%.*]] | |
| ; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 2 | |
| ; CHECK-NEXT: ret i32 [[TMP3]] | |
| ; | |
| %1 = getelementptr i16, ptr @constarray2, i64 -2 | |
| %2 = getelementptr [3 x i16], ptr %1, i64 %idx | |
| %3 = load i32, ptr %2, align 2 | |
| ret i32 %3 | |
| } | |
| define i32 @gep_load_i32_align2_const_offset_nusw(i64 %idx){ | |
| ; LE-LABEL: @gep_load_i32_align2_const_offset_nusw( | |
| ; LE-NEXT: ret i32 65537 | |
| ; | |
| ; BE-LABEL: @gep_load_i32_align2_const_offset_nusw( | |
| ; BE-NEXT: ret i32 16777472 | |
| ; | |
| %1 = getelementptr nusw i16, ptr @constarray2, i64 -2 | |
| %2 = getelementptr nusw [3 x i16], ptr %1, i64 %idx | |
| %3 = load i32, ptr %2, align 2 | |
| ret i32 %3 | |
| } | |
| define i32 @inbounds_gep_i32_load_i32_const_ptr_array(i64 %idx){ | |
| ; CHECK-LABEL: @inbounds_gep_i32_load_i32_const_ptr_array( | |
| ; CHECK-NEXT: ret i32 42 | |
| ; | |
| %1 = getelementptr inbounds ptr, ptr @constptrarray, i64 %idx | |
| %2 = load ptr, ptr %1, align 4 | |
| %3 = load i32, ptr %2, align 4 | |
| ret i32 %3 | |
| } | |
| define i32 @inbounds_gep_i32_load_i32_align4_packedstruct(i64 %idx){ | |
| ; LE-LABEL: @inbounds_gep_i32_load_i32_align4_packedstruct( | |
| ; LE-NEXT: ret i32 65537 | |
| ; | |
| ; BE-LABEL: @inbounds_gep_i32_load_i32_align4_packedstruct( | |
| ; BE-NEXT: ret i32 16777472 | |
| ; | |
| %1 = getelementptr inbounds i32, ptr @constpackedstruct, i64 %idx | |
| %2 = load i32, ptr %1, align 4 | |
| ret i32 %2 | |
| } | |
| ; can't be folded because results are not equal | |
| define i32 @inbounds_gep_i8_load_i32_align1_packedstruct(i64 %idx){ | |
| ; CHECK-LABEL: @inbounds_gep_i8_load_i32_align1_packedstruct( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constpackedstruct, i64 [[IDX:%.*]] | |
| ; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 1 | |
| ; CHECK-NEXT: ret i32 [[TMP2]] | |
| ; | |
| %1 = getelementptr inbounds i8, ptr @constpackedstruct, i64 %idx | |
| %2 = load i32, ptr %1, align 1 | |
| ret i32 %2 | |
| } | |
| define i32 @inbounds_gep_i32_load_i32_align4_struct_with_const_offset(i64 %idx){ | |
| ; LE-LABEL: @inbounds_gep_i32_load_i32_align4_struct_with_const_offset( | |
| ; LE-NEXT: ret i32 65537 | |
| ; | |
| ; BE-LABEL: @inbounds_gep_i32_load_i32_align4_struct_with_const_offset( | |
| ; BE-NEXT: ret i32 16777472 | |
| ; | |
| %1 = getelementptr inbounds i16, ptr @conststruct, i64 1 | |
| %2 = getelementptr inbounds i32, ptr %1, i64 %idx | |
| %3 = load i32, ptr %2, align 4 | |
| ret i32 %3 | |
| } | |