|  | ; 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 | 
|  | } | 
|  |  | 
|  | ; Sanitizer will break optimization. | 
|  | define void @test_multiple_loads_select_asan(i1 %cmp) sanitize_address { | 
|  | ; CHECK-PRESERVE-CFG-LABEL: @test_multiple_loads_select_asan( | 
|  | ; CHECK-PRESERVE-CFG-NEXT:  entry: | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    [[ARGS_SROA_0:%.*]] = alloca ptr, align 8 | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    [[ARGS_SROA_1:%.*]] = alloca ptr, align 8 | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    [[SEL_SROA_SEL:%.*]] = select i1 [[CMP:%.*]], ptr [[ARGS_SROA_1]], ptr [[ARGS_SROA_0]] | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    [[ADDR_I8:%.*]] = load ptr, ptr [[SEL_SROA_SEL]], align 8 | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    call void @foo_i8(ptr [[ADDR_I8]]) | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    [[ADDR_I32:%.*]] = load ptr, ptr [[SEL_SROA_SEL]], align 8 | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    call void @foo_i32(ptr [[ADDR_I32]]) | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    ret void | 
|  | ; | 
|  | ; CHECK-MODIFY-CFG-LABEL: @test_multiple_loads_select_asan( | 
|  | ; CHECK-MODIFY-CFG-NEXT:  entry: | 
|  | ; CHECK-MODIFY-CFG-NEXT:    br i1 [[CMP:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]] | 
|  | ; CHECK-MODIFY-CFG:       entry.then: | 
|  | ; 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:    [[ADDR_I8:%.*]] = phi ptr [ undef, [[ENTRY_THEN]] ], [ undef, [[ENTRY_ELSE]] ] | 
|  | ; CHECK-MODIFY-CFG-NEXT:    call void @foo_i8(ptr [[ADDR_I8]]) | 
|  | ; CHECK-MODIFY-CFG-NEXT:    br i1 [[CMP]], label [[ENTRY_CONT_THEN:%.*]], label [[ENTRY_CONT_ELSE:%.*]] | 
|  | ; CHECK-MODIFY-CFG:       entry.cont.then: | 
|  | ; CHECK-MODIFY-CFG-NEXT:    br label [[ENTRY_CONT_CONT:%.*]] | 
|  | ; CHECK-MODIFY-CFG:       entry.cont.else: | 
|  | ; CHECK-MODIFY-CFG-NEXT:    br label [[ENTRY_CONT_CONT]] | 
|  | ; CHECK-MODIFY-CFG:       entry.cont.cont: | 
|  | ; CHECK-MODIFY-CFG-NEXT:    [[ADDR_I32:%.*]] = phi ptr [ undef, [[ENTRY_CONT_THEN]] ], [ undef, [[ENTRY_CONT_ELSE]] ] | 
|  | ; CHECK-MODIFY-CFG-NEXT:    call void @foo_i32(ptr [[ADDR_I32]]) | 
|  | ; CHECK-MODIFY-CFG-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 | 
|  | } | 
|  |  | 
|  | ; When promoting speculative instruction, metadata that may trigger immediate UB should be dropped. | 
|  | define void @load_of_select_with_noundef_nonnull(ptr %buffer, i1 %b) { | 
|  | ; CHECK-PRESERVE-CFG-LABEL: @load_of_select_with_noundef_nonnull( | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    [[UB_PTR:%.*]] = alloca ptr, align 8 | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    [[SELECT_PTR:%.*]] = select i1 [[B:%.*]], ptr [[BUFFER:%.*]], ptr [[UB_PTR]] | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    [[LOAD_PTR:%.*]] = load ptr, ptr [[SELECT_PTR]], align 8, !nonnull [[META1:![0-9]+]], !noundef [[META1]] | 
|  | ; CHECK-PRESERVE-CFG-NEXT:    ret void | 
|  | ; | 
|  | ; CHECK-MODIFY-CFG-LABEL: @load_of_select_with_noundef_nonnull( | 
|  | ; CHECK-MODIFY-CFG-NEXT:    br i1 [[B:%.*]], label [[DOTTHEN:%.*]], label [[DOTCONT:%.*]] | 
|  | ; CHECK-MODIFY-CFG:       .then: | 
|  | ; CHECK-MODIFY-CFG-NEXT:    [[LOAD_PTR_THEN_VAL:%.*]] = load ptr, ptr [[BUFFER:%.*]], align 8, !nonnull [[META2:![0-9]+]], !noundef [[META2]] | 
|  | ; CHECK-MODIFY-CFG-NEXT:    br label [[DOTCONT]] | 
|  | ; CHECK-MODIFY-CFG:       .cont: | 
|  | ; CHECK-MODIFY-CFG-NEXT:    [[LOAD_PTR:%.*]] = phi ptr [ [[LOAD_PTR_THEN_VAL]], [[DOTTHEN]] ], [ undef, [[TMP0:%.*]] ] | 
|  | ; CHECK-MODIFY-CFG-NEXT:    ret void | 
|  | ; | 
|  | %ub_ptr = alloca ptr | 
|  | %select_ptr = select i1 %b, ptr %buffer, ptr %ub_ptr | 
|  | %load_ptr = load ptr, ptr %select_ptr, !nonnull !1, !noundef !1 | 
|  | ret void | 
|  | } | 
|  |  | 
|  | !0  = !{!"branch_weights", i32 1,  i32 99} | 
|  | !1 = !{} | 
|  |  | 
|  | ; 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) |