llvm/llvm/test/Transforms/SROA/select-load.ll

; 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)