| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG |
| ; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG |
| |
| %st.half = type { half } |
| |
| ; Allow speculateSelectInstLoads to fold load and select |
| ; even if there is an intervening bitcast. |
| define <2 x i16> @test_load_bitcast_select(i1 %cond1, i1 %cond2) { |
| ; CHECK-LABEL: @test_load_bitcast_select( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = bitcast half 0xHFFFF to i16 |
| ; CHECK-NEXT: [[TMP1:%.*]] = bitcast half 0xH0000 to i16 |
| ; CHECK-NEXT: [[LD1_SROA_SPECULATED:%.*]] = select i1 [[COND1:%.*]], i16 [[TMP0]], i16 [[TMP1]] |
| ; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i16> poison, i16 [[LD1_SROA_SPECULATED]], i32 0 |
| ; CHECK-NEXT: [[TMP2:%.*]] = bitcast half 0xHFFFF to i16 |
| ; CHECK-NEXT: [[TMP3:%.*]] = bitcast half 0xH0000 to i16 |
| ; CHECK-NEXT: [[LD2_SROA_SPECULATED:%.*]] = select i1 [[COND2:%.*]], i16 [[TMP2]], i16 [[TMP3]] |
| ; CHECK-NEXT: [[V2:%.*]] = insertelement <2 x i16> [[V1]], i16 [[LD2_SROA_SPECULATED]], i32 1 |
| ; CHECK-NEXT: ret <2 x i16> [[V2]] |
| ; |
| entry: |
| %true = alloca half, align 2 |
| %false = alloca half, align 2 |
| store half 0xHFFFF, ptr %true, align 2 |
| store half 0xH0000, ptr %false, align 2 |
| %sel1 = select i1 %cond1, ptr %true, ptr %false |
| %ld1 = load i16, ptr %sel1, align 2 |
| %v1 = insertelement <2 x i16> poison, i16 %ld1, i32 0 |
| %sel2 = select i1 %cond2, ptr %true, ptr %false |
| %ld2 = load i16, ptr %sel2, align 2 |
| %v2 = insertelement <2 x i16> %v1, i16 %ld2, i32 1 |
| ret <2 x i16> %v2 |
| } |
| |
| %st.args = type { i32, ptr } |
| |
| ; A bitcasted load and a direct load of select. |
| define void @test_multiple_loads_select(i1 %cmp){ |
| ; CHECK-LABEL: @test_multiple_loads_select( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADDR_I8_SROA_SPECULATED:%.*]] = select i1 [[CMP:%.*]], ptr undef, ptr undef |
| ; CHECK-NEXT: call void @foo_i8(ptr [[ADDR_I8_SROA_SPECULATED]]) |
| ; CHECK-NEXT: [[ADDR_I32_SROA_SPECULATED:%.*]] = select i1 [[CMP]], ptr undef, ptr undef |
| ; CHECK-NEXT: call void @foo_i32(ptr [[ADDR_I32_SROA_SPECULATED]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %args = alloca [2 x %st.args], align 16 |
| %arr1 = getelementptr inbounds [2 x %st.args], ptr %args, i64 0, i64 1 |
| %sel = select i1 %cmp, ptr %arr1, ptr %args |
| %addr = getelementptr inbounds %st.args, ptr %sel, i64 0, i32 1 |
| %addr.i8 = load ptr, ptr %addr, align 8 |
| call void @foo_i8(ptr %addr.i8) |
| %addr.i32 = load ptr, ptr %addr, align 8 |
| call void @foo_i32 (ptr %addr.i32) |
| ret void |
| } |
| |
| declare void @foo_i8(ptr) |
| declare void @foo_i32(ptr) |
| |
| ; Lifetime intrinsics should not prevent dereferenceability inferrence. |
| define i32 @interfering_lifetime(ptr %data, i64 %indvars.iv) { |
| ; CHECK-LABEL: @interfering_lifetime( |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] |
| ; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 |
| ; CHECK-NEXT: [[I3_SROA_SPECULATE_LOAD_FALSE:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-NEXT: [[I3_SROA_SPECULATED:%.*]] = select i1 [[CMP_I_I]], i32 0, i32 [[I3_SROA_SPECULATE_LOAD_FALSE]] |
| ; CHECK-NEXT: ret i32 [[I3_SROA_SPECULATED]] |
| ; |
| %min = alloca i32, align 4 |
| %arrayidx = getelementptr inbounds i32, ptr %data, i64 %indvars.iv |
| %i1 = load i32, ptr %arrayidx, align 4 |
| call void @llvm.lifetime.start.p0(i64 4, ptr %min) |
| store i32 0, ptr %min, align 4 |
| %cmp.i.i = icmp slt i32 %i1, 0 |
| %__b.__a.i.i = select i1 %cmp.i.i, ptr %min, ptr %arrayidx |
| %i3 = load i32, ptr %__b.__a.i.i, align 4 |
| ret i32 %i3 |
| } |
| |
| ; We should recursively evaluate select's. |
| define i32 @clamp_load_to_constant_range(ptr %data, i64 %indvars.iv) { |
| ; CHECK-PRESERVE-CFG-LABEL: @clamp_load_to_constant_range( |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] |
| ; CHECK-PRESERVE-CFG-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MIN]]) |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MAX]]) |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 |
| ; CHECK-PRESERVE-CFG-NEXT: [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0) |
| ; CHECK-PRESERVE-CFG-NEXT: [[__B___A_I_I:%.*]] = select i1 [[CMP_I_I]], ptr [[MIN]], ptr [[ARRAYIDX]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095 |
| ; CHECK-PRESERVE-CFG-NEXT: [[__B___A_I2_I:%.*]] = select i1 [[CMP_I1_I]], ptr [[MAX]], ptr [[__B___A_I_I]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[I3:%.*]] = load i32, ptr [[__B___A_I2_I]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[I3]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @clamp_load_to_constant_range( |
| ; CHECK-MODIFY-CFG-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] |
| ; CHECK-MODIFY-CFG-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 |
| ; CHECK-MODIFY-CFG-NEXT: [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0) |
| ; CHECK-MODIFY-CFG-NEXT: [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095 |
| ; CHECK-MODIFY-CFG-NEXT: br i1 [[CMP_I1_I]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]] |
| ; CHECK-MODIFY-CFG: .else: |
| ; CHECK-MODIFY-CFG-NEXT: br i1 [[CMP_I_I]], label [[DOTELSE_CONT:%.*]], label [[DOTELSE_ELSE:%.*]] |
| ; CHECK-MODIFY-CFG: .else.else: |
| ; CHECK-MODIFY-CFG-NEXT: [[I3_ELSE_VAL_ELSE_VAL:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: br label [[DOTELSE_CONT]] |
| ; CHECK-MODIFY-CFG: .else.cont: |
| ; CHECK-MODIFY-CFG-NEXT: [[I3_ELSE_VAL:%.*]] = phi i32 [ 0, [[DOTELSE]] ], [ [[I3_ELSE_VAL_ELSE_VAL]], [[DOTELSE_ELSE]] ] |
| ; CHECK-MODIFY-CFG-NEXT: br label [[DOTCONT]] |
| ; CHECK-MODIFY-CFG: .cont: |
| ; CHECK-MODIFY-CFG-NEXT: [[I3:%.*]] = phi i32 [ 4095, [[TMP0:%.*]] ], [ [[I3_ELSE_VAL]], [[DOTELSE_CONT]] ] |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[I3]] |
| ; |
| %min = alloca i32, align 4 |
| %max = alloca i32, align 4 |
| %arrayidx = getelementptr inbounds i32, ptr %data, i64 %indvars.iv |
| call void @llvm.lifetime.start.p0(i64 4, ptr %min) |
| store i32 0, ptr %min, align 4 |
| call void @llvm.lifetime.start.p0(i64 4, ptr %max) |
| store i32 4095, ptr %max, align 4 |
| %i1 = load i32, ptr %arrayidx, align 4 |
| %cmp.i.i = icmp slt i32 %i1, 0 |
| %i2 = tail call i32 @llvm.smax.i32(i32 %i1, i32 0) |
| %__b.__a.i.i = select i1 %cmp.i.i, ptr %min, ptr %arrayidx |
| %cmp.i1.i = icmp ugt i32 %i2, 4095 |
| %__b.__a.i2.i = select i1 %cmp.i1.i, ptr %max, ptr %__b.__a.i.i |
| %i3 = load i32, ptr %__b.__a.i2.i, align 4 |
| ret i32 %i3 |
| } |
| |
| define i32 @non_speculatable_load_of_select(i1 %cond, ptr %else.addr) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0:![0-9]+]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[ENTRY_CONT:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF0:![0-9]+]] |
| ; CHECK-MODIFY-CFG: entry.else: |
| ; CHECK-MODIFY-CFG-NEXT: [[R_ELSE_VAL:%.*]] = load i32, ptr [[ELSE_ADDR:%.*]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] |
| ; CHECK-MODIFY-CFG: entry.cont: |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %min = alloca i32, align 4 |
| store i32 0, ptr %min, align 4 |
| %addr = select i1 %cond, ptr %min, ptr %else.addr, !prof !0 |
| %r = load i32, ptr %addr, align 4 |
| ret i32 %r |
| } |
| define i32 @non_speculatable_load_of_select_inverted(i1 %cond, ptr %then.addr) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_inverted( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_inverted( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]], !prof [[PROF1:![0-9]+]] |
| ; CHECK-MODIFY-CFG: entry.then: |
| ; CHECK-MODIFY-CFG-NEXT: [[R_THEN_VAL:%.*]] = load i32, ptr [[THEN_ADDR:%.*]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] |
| ; CHECK-MODIFY-CFG: entry.cont: |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 4095, [[ENTRY:%.*]] ] |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %max = alloca i32, align 4 |
| store i32 4095, ptr %max, align 4 |
| %addr = select i1 %cond, ptr %then.addr, ptr %max, !prof !0 |
| %r = load i32, ptr %addr, align 4 |
| ret i32 %r |
| } |
| |
| define i32 @non_speculatable_volatile_load_of_select(i1 %cond, ptr %else.addr) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_volatile_load_of_select( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_volatile_load_of_select( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-MODIFY-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %min = alloca i32, align 4 |
| store i32 0, ptr %min, align 4 |
| %addr = select i1 %cond, ptr %min, ptr %else.addr, !prof !0 |
| %r = load volatile i32, ptr %addr, align 4 |
| ret i32 %r |
| } |
| define i32 @non_speculatable_volatile_load_of_select_inverted(i1 %cond, ptr %then.addr) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_volatile_load_of_select_inverted( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_volatile_load_of_select_inverted( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 |
| ; CHECK-MODIFY-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %max = alloca i32, align 4 |
| store i32 4095, ptr %max, align 4 |
| %addr = select i1 %cond, ptr %then.addr, ptr %max, !prof !0 |
| %r = load volatile i32, ptr %addr, align 4 |
| ret i32 %r |
| } |
| |
| define i32 @non_speculatable_atomic_unord_load_of_select(i1 %cond, ptr %else.addr) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_atomic_unord_load_of_select( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_atomic_unord_load_of_select( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG: entry.then: |
| ; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT:%.*]] |
| ; CHECK-MODIFY-CFG: entry.else: |
| ; CHECK-MODIFY-CFG-NEXT: [[R_ELSE_VAL:%.*]] = load atomic i32, ptr [[ELSE_ADDR:%.*]] unordered, align 4 |
| ; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] |
| ; CHECK-MODIFY-CFG: entry.cont: |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY_THEN]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %min = alloca i32, align 4 |
| store i32 0, ptr %min, align 4 |
| %addr = select i1 %cond, ptr %min, ptr %else.addr, !prof !0 |
| %r = load atomic i32, ptr %addr unordered, align 4 |
| ret i32 %r |
| } |
| define i32 @non_speculatable_atomic_unord_load_of_select_inverted(i1 %cond, ptr %then.addr) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG: entry.then: |
| ; CHECK-MODIFY-CFG-NEXT: [[R_THEN_VAL:%.*]] = load atomic i32, ptr [[THEN_ADDR:%.*]] unordered, align 4 |
| ; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT:%.*]] |
| ; CHECK-MODIFY-CFG: entry.else: |
| ; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] |
| ; CHECK-MODIFY-CFG: entry.cont: |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 4095, [[ENTRY_ELSE]] ] |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %max = alloca i32, align 4 |
| store i32 4095, ptr %max, align 4 |
| %addr = select i1 %cond, ptr %then.addr, ptr %max, !prof !0 |
| %r = load atomic i32, ptr %addr unordered, align 4 |
| ret i32 %r |
| } |
| |
| define i32 @non_speculatable_load_of_select_outer(i1 %cond_inner, i1 %cond_outer, ptr %data_then, ptr %data_else) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_outer( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN]], ptr [[ADDR_DATA]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_outer( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG-NEXT: br i1 [[COND_OUTER:%.*]], label [[ENTRY_CONT:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF0]] |
| ; CHECK-MODIFY-CFG: entry.else: |
| ; CHECK-MODIFY-CFG-NEXT: [[R_ELSE_VAL:%.*]] = load i32, ptr [[ADDR_DATA]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] |
| ; CHECK-MODIFY-CFG: entry.cont: |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %min = alloca i32, align 4 |
| store i32 0, ptr %min, align 4 |
| %addr.data = select i1 %cond_inner, ptr %data_then, ptr %data_else, !prof !0 |
| %addr = select i1 %cond_outer, ptr %min, ptr %addr.data, !prof !0 |
| %r = load i32, ptr %addr, align 4 |
| ret i32 %r |
| } |
| define i32 @non_speculatable_load_of_select_outer_inverted(i1 %cond_inner, i1 %cond_outer, ptr %data_then, ptr %data_else) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_outer_inverted( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[ADDR_DATA]], ptr [[MIN]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_outer_inverted( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG-NEXT: br i1 [[COND_OUTER:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG: entry.then: |
| ; CHECK-MODIFY-CFG-NEXT: [[R_THEN_VAL:%.*]] = load i32, ptr [[ADDR_DATA]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] |
| ; CHECK-MODIFY-CFG: entry.cont: |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 0, [[ENTRY:%.*]] ] |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %min = alloca i32, align 4 |
| store i32 0, ptr %min, align 4 |
| %addr.data = select i1 %cond_inner, ptr %data_then, ptr %data_else, !prof !0 |
| %addr = select i1 %cond_outer, ptr %addr.data, ptr %min, !prof !0 |
| %r = load i32, ptr %addr, align 4 |
| ret i32 %r |
| } |
| |
| define i32 @non_speculatable_load_of_select_inner(i1 %cond_inner, i1 %cond_outer, ptr %data_else, ptr %min_else) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_inner( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_inner( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-MODIFY-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %min = alloca i32, align 4 |
| store i32 0, ptr %min, align 4 |
| %min.addr.data = select i1 %cond_inner, ptr %min, ptr %min_else, !prof !0 |
| %addr = select i1 %cond_outer, ptr %min.addr.data, ptr %data_else, !prof !0 |
| %r = load i32, ptr %addr, align 4 |
| ret i32 %r |
| } |
| define i32 @non_speculatable_load_of_select_inner_inverted(i1 %cond_inner, i1 %cond_outer, ptr %data_else, ptr %min_then) { |
| ; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_inner_inverted( |
| ; CHECK-PRESERVE-CFG-NEXT: entry: |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] |
| ; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 |
| ; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] |
| ; |
| ; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_inner_inverted( |
| ; CHECK-MODIFY-CFG-NEXT: entry: |
| ; CHECK-MODIFY-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 |
| ; CHECK-MODIFY-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] |
| ; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 |
| ; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] |
| ; |
| entry: |
| %min = alloca i32, align 4 |
| store i32 0, ptr %min, align 4 |
| %min.addr.data = select i1 %cond_inner, ptr %min_then, ptr %min, !prof !0 |
| %addr = select i1 %cond_outer, ptr %min.addr.data, ptr %data_else, !prof !0 |
| %r = load i32, ptr %addr, align 4 |
| ret i32 %r |
| } |
| |
| !0 = !{!"branch_weights", i32 1, i32 99} |
| |
| ; Ensure that the branch metadata is reversed to match the reversals above. |
| |
| declare void @llvm.lifetime.start.p0(i64, ptr ) |
| declare void @llvm.lifetime.end.p0(i64, ptr) |
| declare i32 @llvm.smax.i32(i32, i32) |