1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG 3; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG 4 5%st.half = type { half } 6 7; Allow speculateSelectInstLoads to fold load and select 8; even if there is an intervening bitcast. 9define <2 x i16> @test_load_bitcast_select(i1 %cond1, i1 %cond2) { 10; CHECK-LABEL: @test_load_bitcast_select( 11; CHECK-NEXT: entry: 12; CHECK-NEXT: [[TMP0:%.*]] = bitcast half 0xHFFFF to i16 13; CHECK-NEXT: [[TMP1:%.*]] = bitcast half 0xH0000 to i16 14; CHECK-NEXT: [[LD1_SROA_SPECULATED:%.*]] = select i1 [[COND1:%.*]], i16 [[TMP0]], i16 [[TMP1]] 15; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i16> poison, i16 [[LD1_SROA_SPECULATED]], i32 0 16; CHECK-NEXT: [[TMP2:%.*]] = bitcast half 0xHFFFF to i16 17; CHECK-NEXT: [[TMP3:%.*]] = bitcast half 0xH0000 to i16 18; CHECK-NEXT: [[LD2_SROA_SPECULATED:%.*]] = select i1 [[COND2:%.*]], i16 [[TMP2]], i16 [[TMP3]] 19; CHECK-NEXT: [[V2:%.*]] = insertelement <2 x i16> [[V1]], i16 [[LD2_SROA_SPECULATED]], i32 1 20; CHECK-NEXT: ret <2 x i16> [[V2]] 21; 22entry: 23 %true = alloca half, align 2 24 %false = alloca half, align 2 25 store half 0xHFFFF, ptr %true, align 2 26 store half 0xH0000, ptr %false, align 2 27 %sel1 = select i1 %cond1, ptr %true, ptr %false 28 %ld1 = load i16, ptr %sel1, align 2 29 %v1 = insertelement <2 x i16> poison, i16 %ld1, i32 0 30 %sel2 = select i1 %cond2, ptr %true, ptr %false 31 %ld2 = load i16, ptr %sel2, align 2 32 %v2 = insertelement <2 x i16> %v1, i16 %ld2, i32 1 33 ret <2 x i16> %v2 34} 35 36%st.args = type { i32, ptr } 37 38; A bitcasted load and a direct load of select. 39define void @test_multiple_loads_select(i1 %cmp) { 40; CHECK-LABEL: @test_multiple_loads_select( 41; CHECK-NEXT: entry: 42; CHECK-NEXT: [[ADDR_I8_SROA_SPECULATED:%.*]] = select i1 [[CMP:%.*]], ptr undef, ptr undef 43; CHECK-NEXT: call void @foo_i8(ptr [[ADDR_I8_SROA_SPECULATED]]) 44; CHECK-NEXT: [[ADDR_I32_SROA_SPECULATED:%.*]] = select i1 [[CMP]], ptr undef, ptr undef 45; CHECK-NEXT: call void @foo_i32(ptr [[ADDR_I32_SROA_SPECULATED]]) 46; CHECK-NEXT: ret void 47; 48entry: 49 %args = alloca [2 x %st.args], align 16 50 %arr1 = getelementptr inbounds [2 x %st.args], ptr %args, i64 0, i64 1 51 %sel = select i1 %cmp, ptr %arr1, ptr %args 52 %addr = getelementptr inbounds %st.args, ptr %sel, i64 0, i32 1 53 %addr.i8 = load ptr, ptr %addr, align 8 54 call void @foo_i8(ptr %addr.i8) 55 %addr.i32 = load ptr, ptr %addr, align 8 56 call void @foo_i32 (ptr %addr.i32) 57 ret void 58} 59 60; Sanitizer will break optimization. 61define void @test_multiple_loads_select_asan(i1 %cmp) sanitize_address { 62; CHECK-PRESERVE-CFG-LABEL: @test_multiple_loads_select_asan( 63; CHECK-PRESERVE-CFG-NEXT: entry: 64; CHECK-PRESERVE-CFG-NEXT: [[ARGS_SROA_0:%.*]] = alloca ptr, align 8 65; CHECK-PRESERVE-CFG-NEXT: [[ARGS_SROA_1:%.*]] = alloca ptr, align 8 66; CHECK-PRESERVE-CFG-NEXT: [[SEL_SROA_SEL:%.*]] = select i1 [[CMP:%.*]], ptr [[ARGS_SROA_1]], ptr [[ARGS_SROA_0]] 67; CHECK-PRESERVE-CFG-NEXT: [[ADDR_I8:%.*]] = load ptr, ptr [[SEL_SROA_SEL]], align 8 68; CHECK-PRESERVE-CFG-NEXT: call void @foo_i8(ptr [[ADDR_I8]]) 69; CHECK-PRESERVE-CFG-NEXT: [[ADDR_I32:%.*]] = load ptr, ptr [[SEL_SROA_SEL]], align 8 70; CHECK-PRESERVE-CFG-NEXT: call void @foo_i32(ptr [[ADDR_I32]]) 71; CHECK-PRESERVE-CFG-NEXT: ret void 72; 73; CHECK-MODIFY-CFG-LABEL: @test_multiple_loads_select_asan( 74; CHECK-MODIFY-CFG-NEXT: entry: 75; CHECK-MODIFY-CFG-NEXT: br i1 [[CMP:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]] 76; CHECK-MODIFY-CFG: entry.then: 77; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT:%.*]] 78; CHECK-MODIFY-CFG: entry.else: 79; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] 80; CHECK-MODIFY-CFG: entry.cont: 81; CHECK-MODIFY-CFG-NEXT: [[ADDR_I8:%.*]] = phi ptr [ undef, [[ENTRY_THEN]] ], [ undef, [[ENTRY_ELSE]] ] 82; CHECK-MODIFY-CFG-NEXT: call void @foo_i8(ptr [[ADDR_I8]]) 83; CHECK-MODIFY-CFG-NEXT: br i1 [[CMP]], label [[ENTRY_CONT_THEN:%.*]], label [[ENTRY_CONT_ELSE:%.*]] 84; CHECK-MODIFY-CFG: entry.cont.then: 85; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT_CONT:%.*]] 86; CHECK-MODIFY-CFG: entry.cont.else: 87; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT_CONT]] 88; CHECK-MODIFY-CFG: entry.cont.cont: 89; CHECK-MODIFY-CFG-NEXT: [[ADDR_I32:%.*]] = phi ptr [ undef, [[ENTRY_CONT_THEN]] ], [ undef, [[ENTRY_CONT_ELSE]] ] 90; CHECK-MODIFY-CFG-NEXT: call void @foo_i32(ptr [[ADDR_I32]]) 91; CHECK-MODIFY-CFG-NEXT: ret void 92; 93entry: 94 %args = alloca [2 x %st.args], align 16 95 %arr1 = getelementptr inbounds [2 x %st.args], ptr %args, i64 0, i64 1 96 %sel = select i1 %cmp, ptr %arr1, ptr %args 97 %addr = getelementptr inbounds %st.args, ptr %sel, i64 0, i32 1 98 %addr.i8 = load ptr, ptr %addr, align 8 99 call void @foo_i8(ptr %addr.i8) 100 %addr.i32 = load ptr, ptr %addr, align 8 101 call void @foo_i32 (ptr %addr.i32) 102 ret void 103} 104 105declare void @foo_i8(ptr) 106declare void @foo_i32(ptr) 107 108; Lifetime intrinsics should not prevent dereferenceability inferrence. 109define i32 @interfering_lifetime(ptr %data, i64 %indvars.iv) { 110; CHECK-LABEL: @interfering_lifetime( 111; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] 112; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 113; CHECK-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 114; CHECK-NEXT: [[I3_SROA_SPECULATE_LOAD_FALSE:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 115; CHECK-NEXT: [[I3_SROA_SPECULATED:%.*]] = select i1 [[CMP_I_I]], i32 0, i32 [[I3_SROA_SPECULATE_LOAD_FALSE]] 116; CHECK-NEXT: ret i32 [[I3_SROA_SPECULATED]] 117; 118 %min = alloca i32, align 4 119 %arrayidx = getelementptr inbounds i32, ptr %data, i64 %indvars.iv 120 %i1 = load i32, ptr %arrayidx, align 4 121 call void @llvm.lifetime.start.p0(i64 4, ptr %min) 122 store i32 0, ptr %min, align 4 123 %cmp.i.i = icmp slt i32 %i1, 0 124 %__b.__a.i.i = select i1 %cmp.i.i, ptr %min, ptr %arrayidx 125 %i3 = load i32, ptr %__b.__a.i.i, align 4 126 ret i32 %i3 127} 128 129; We should recursively evaluate select's. 130define i32 @clamp_load_to_constant_range(ptr %data, i64 %indvars.iv) { 131; CHECK-PRESERVE-CFG-LABEL: @clamp_load_to_constant_range( 132; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 133; CHECK-PRESERVE-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 134; CHECK-PRESERVE-CFG-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] 135; CHECK-PRESERVE-CFG-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MIN]]) 136; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 137; CHECK-PRESERVE-CFG-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MAX]]) 138; CHECK-PRESERVE-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 139; CHECK-PRESERVE-CFG-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 140; CHECK-PRESERVE-CFG-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 141; CHECK-PRESERVE-CFG-NEXT: [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0) 142; CHECK-PRESERVE-CFG-NEXT: [[__B___A_I_I:%.*]] = select i1 [[CMP_I_I]], ptr [[MIN]], ptr [[ARRAYIDX]] 143; CHECK-PRESERVE-CFG-NEXT: [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095 144; CHECK-PRESERVE-CFG-NEXT: [[__B___A_I2_I:%.*]] = select i1 [[CMP_I1_I]], ptr [[MAX]], ptr [[__B___A_I_I]] 145; CHECK-PRESERVE-CFG-NEXT: [[I3:%.*]] = load i32, ptr [[__B___A_I2_I]], align 4 146; CHECK-PRESERVE-CFG-NEXT: ret i32 [[I3]] 147; 148; CHECK-MODIFY-CFG-LABEL: @clamp_load_to_constant_range( 149; CHECK-MODIFY-CFG-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] 150; CHECK-MODIFY-CFG-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 151; CHECK-MODIFY-CFG-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 152; CHECK-MODIFY-CFG-NEXT: [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0) 153; CHECK-MODIFY-CFG-NEXT: [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095 154; CHECK-MODIFY-CFG-NEXT: br i1 [[CMP_I1_I]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]] 155; CHECK-MODIFY-CFG: .else: 156; CHECK-MODIFY-CFG-NEXT: br i1 [[CMP_I_I]], label [[DOTELSE_CONT:%.*]], label [[DOTELSE_ELSE:%.*]] 157; CHECK-MODIFY-CFG: .else.else: 158; CHECK-MODIFY-CFG-NEXT: [[I3_ELSE_VAL_ELSE_VAL:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 159; CHECK-MODIFY-CFG-NEXT: br label [[DOTELSE_CONT]] 160; CHECK-MODIFY-CFG: .else.cont: 161; CHECK-MODIFY-CFG-NEXT: [[I3_ELSE_VAL:%.*]] = phi i32 [ 0, [[DOTELSE]] ], [ [[I3_ELSE_VAL_ELSE_VAL]], [[DOTELSE_ELSE]] ] 162; CHECK-MODIFY-CFG-NEXT: br label [[DOTCONT]] 163; CHECK-MODIFY-CFG: .cont: 164; CHECK-MODIFY-CFG-NEXT: [[I3:%.*]] = phi i32 [ 4095, [[TMP0:%.*]] ], [ [[I3_ELSE_VAL]], [[DOTELSE_CONT]] ] 165; CHECK-MODIFY-CFG-NEXT: ret i32 [[I3]] 166; 167 %min = alloca i32, align 4 168 %max = alloca i32, align 4 169 %arrayidx = getelementptr inbounds i32, ptr %data, i64 %indvars.iv 170 call void @llvm.lifetime.start.p0(i64 4, ptr %min) 171 store i32 0, ptr %min, align 4 172 call void @llvm.lifetime.start.p0(i64 4, ptr %max) 173 store i32 4095, ptr %max, align 4 174 %i1 = load i32, ptr %arrayidx, align 4 175 %cmp.i.i = icmp slt i32 %i1, 0 176 %i2 = tail call i32 @llvm.smax.i32(i32 %i1, i32 0) 177 %__b.__a.i.i = select i1 %cmp.i.i, ptr %min, ptr %arrayidx 178 %cmp.i1.i = icmp ugt i32 %i2, 4095 179 %__b.__a.i2.i = select i1 %cmp.i1.i, ptr %max, ptr %__b.__a.i.i 180 %i3 = load i32, ptr %__b.__a.i2.i, align 4 181 ret i32 %i3 182} 183 184define i32 @non_speculatable_load_of_select(i1 %cond, ptr %else.addr) { 185; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select( 186; CHECK-PRESERVE-CFG-NEXT: entry: 187; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 188; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 189; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0:![0-9]+]] 190; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 191; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 192; 193; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select( 194; CHECK-MODIFY-CFG-NEXT: entry: 195; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[ENTRY_CONT:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF0:![0-9]+]] 196; CHECK-MODIFY-CFG: entry.else: 197; CHECK-MODIFY-CFG-NEXT: [[R_ELSE_VAL:%.*]] = load i32, ptr [[ELSE_ADDR:%.*]], align 4 198; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] 199; CHECK-MODIFY-CFG: entry.cont: 200; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] 201; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 202; 203entry: 204 %min = alloca i32, align 4 205 store i32 0, ptr %min, align 4 206 %addr = select i1 %cond, ptr %min, ptr %else.addr, !prof !0 207 %r = load i32, ptr %addr, align 4 208 ret i32 %r 209} 210define i32 @non_speculatable_load_of_select_inverted(i1 %cond, ptr %then.addr) { 211; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_inverted( 212; CHECK-PRESERVE-CFG-NEXT: entry: 213; CHECK-PRESERVE-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 214; CHECK-PRESERVE-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 215; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] 216; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 217; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 218; 219; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_inverted( 220; CHECK-MODIFY-CFG-NEXT: entry: 221; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]], !prof [[PROF1:![0-9]+]] 222; CHECK-MODIFY-CFG: entry.then: 223; CHECK-MODIFY-CFG-NEXT: [[R_THEN_VAL:%.*]] = load i32, ptr [[THEN_ADDR:%.*]], align 4 224; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] 225; CHECK-MODIFY-CFG: entry.cont: 226; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 4095, [[ENTRY:%.*]] ] 227; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 228; 229entry: 230 %max = alloca i32, align 4 231 store i32 4095, ptr %max, align 4 232 %addr = select i1 %cond, ptr %then.addr, ptr %max, !prof !0 233 %r = load i32, ptr %addr, align 4 234 ret i32 %r 235} 236 237define i32 @non_speculatable_volatile_load_of_select(i1 %cond, ptr %else.addr) { 238; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_volatile_load_of_select( 239; CHECK-PRESERVE-CFG-NEXT: entry: 240; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 241; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 242; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]] 243; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 244; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 245; 246; CHECK-MODIFY-CFG-LABEL: @non_speculatable_volatile_load_of_select( 247; CHECK-MODIFY-CFG-NEXT: entry: 248; CHECK-MODIFY-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 249; CHECK-MODIFY-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 250; CHECK-MODIFY-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF1]] 251; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 252; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 253; 254entry: 255 %min = alloca i32, align 4 256 store i32 0, ptr %min, align 4 257 %addr = select i1 %cond, ptr %min, ptr %else.addr, !prof !0 258 %r = load volatile i32, ptr %addr, align 4 259 ret i32 %r 260} 261define i32 @non_speculatable_volatile_load_of_select_inverted(i1 %cond, ptr %then.addr) { 262; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_volatile_load_of_select_inverted( 263; CHECK-PRESERVE-CFG-NEXT: entry: 264; CHECK-PRESERVE-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 265; CHECK-PRESERVE-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 266; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] 267; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 268; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 269; 270; CHECK-MODIFY-CFG-LABEL: @non_speculatable_volatile_load_of_select_inverted( 271; CHECK-MODIFY-CFG-NEXT: entry: 272; CHECK-MODIFY-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 273; CHECK-MODIFY-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 274; CHECK-MODIFY-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF1]] 275; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 276; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 277; 278entry: 279 %max = alloca i32, align 4 280 store i32 4095, ptr %max, align 4 281 %addr = select i1 %cond, ptr %then.addr, ptr %max, !prof !0 282 %r = load volatile i32, ptr %addr, align 4 283 ret i32 %r 284} 285 286define i32 @non_speculatable_atomic_unord_load_of_select(i1 %cond, ptr %else.addr) { 287; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_atomic_unord_load_of_select( 288; CHECK-PRESERVE-CFG-NEXT: entry: 289; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 290; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 291; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]] 292; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4 293; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 294; 295; CHECK-MODIFY-CFG-LABEL: @non_speculatable_atomic_unord_load_of_select( 296; CHECK-MODIFY-CFG-NEXT: entry: 297; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF1]] 298; CHECK-MODIFY-CFG: entry.then: 299; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT:%.*]] 300; CHECK-MODIFY-CFG: entry.else: 301; CHECK-MODIFY-CFG-NEXT: [[R_ELSE_VAL:%.*]] = load atomic i32, ptr [[ELSE_ADDR:%.*]] unordered, align 4 302; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] 303; CHECK-MODIFY-CFG: entry.cont: 304; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY_THEN]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] 305; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 306; 307entry: 308 %min = alloca i32, align 4 309 store i32 0, ptr %min, align 4 310 %addr = select i1 %cond, ptr %min, ptr %else.addr, !prof !0 311 %r = load atomic i32, ptr %addr unordered, align 4 312 ret i32 %r 313} 314define i32 @non_speculatable_atomic_unord_load_of_select_inverted(i1 %cond, ptr %then.addr) { 315; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted( 316; CHECK-PRESERVE-CFG-NEXT: entry: 317; CHECK-PRESERVE-CFG-NEXT: [[MAX:%.*]] = alloca i32, align 4 318; CHECK-PRESERVE-CFG-NEXT: store i32 4095, ptr [[MAX]], align 4 319; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] 320; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4 321; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 322; 323; CHECK-MODIFY-CFG-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted( 324; CHECK-MODIFY-CFG-NEXT: entry: 325; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF1]] 326; CHECK-MODIFY-CFG: entry.then: 327; CHECK-MODIFY-CFG-NEXT: [[R_THEN_VAL:%.*]] = load atomic i32, ptr [[THEN_ADDR:%.*]] unordered, align 4 328; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT:%.*]] 329; CHECK-MODIFY-CFG: entry.else: 330; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] 331; CHECK-MODIFY-CFG: entry.cont: 332; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 4095, [[ENTRY_ELSE]] ] 333; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 334; 335entry: 336 %max = alloca i32, align 4 337 store i32 4095, ptr %max, align 4 338 %addr = select i1 %cond, ptr %then.addr, ptr %max, !prof !0 339 %r = load atomic i32, ptr %addr unordered, align 4 340 ret i32 %r 341} 342 343define i32 @non_speculatable_load_of_select_outer(i1 %cond_inner, i1 %cond_outer, ptr %data_then, ptr %data_else) { 344; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_outer( 345; CHECK-PRESERVE-CFG-NEXT: entry: 346; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 347; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 348; CHECK-PRESERVE-CFG-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] 349; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN]], ptr [[ADDR_DATA]], !prof [[PROF0]] 350; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 351; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 352; 353; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_outer( 354; CHECK-MODIFY-CFG-NEXT: entry: 355; CHECK-MODIFY-CFG-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] 356; CHECK-MODIFY-CFG-NEXT: br i1 [[COND_OUTER:%.*]], label [[ENTRY_CONT:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF0]] 357; CHECK-MODIFY-CFG: entry.else: 358; CHECK-MODIFY-CFG-NEXT: [[R_ELSE_VAL:%.*]] = load i32, ptr [[ADDR_DATA]], align 4 359; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] 360; CHECK-MODIFY-CFG: entry.cont: 361; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] 362; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 363; 364entry: 365 %min = alloca i32, align 4 366 store i32 0, ptr %min, align 4 367 %addr.data = select i1 %cond_inner, ptr %data_then, ptr %data_else, !prof !0 368 %addr = select i1 %cond_outer, ptr %min, ptr %addr.data, !prof !0 369 %r = load i32, ptr %addr, align 4 370 ret i32 %r 371} 372define i32 @non_speculatable_load_of_select_outer_inverted(i1 %cond_inner, i1 %cond_outer, ptr %data_then, ptr %data_else) { 373; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_outer_inverted( 374; CHECK-PRESERVE-CFG-NEXT: entry: 375; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 376; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 377; CHECK-PRESERVE-CFG-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] 378; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[ADDR_DATA]], ptr [[MIN]], !prof [[PROF0]] 379; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 380; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 381; 382; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_outer_inverted( 383; CHECK-MODIFY-CFG-NEXT: entry: 384; CHECK-MODIFY-CFG-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] 385; CHECK-MODIFY-CFG-NEXT: br i1 [[COND_OUTER:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]], !prof [[PROF1]] 386; CHECK-MODIFY-CFG: entry.then: 387; CHECK-MODIFY-CFG-NEXT: [[R_THEN_VAL:%.*]] = load i32, ptr [[ADDR_DATA]], align 4 388; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]] 389; CHECK-MODIFY-CFG: entry.cont: 390; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 0, [[ENTRY:%.*]] ] 391; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 392; 393entry: 394 %min = alloca i32, align 4 395 store i32 0, ptr %min, align 4 396 %addr.data = select i1 %cond_inner, ptr %data_then, ptr %data_else, !prof !0 397 %addr = select i1 %cond_outer, ptr %addr.data, ptr %min, !prof !0 398 %r = load i32, ptr %addr, align 4 399 ret i32 %r 400} 401 402define i32 @non_speculatable_load_of_select_inner(i1 %cond_inner, i1 %cond_outer, ptr %data_else, ptr %min_else) { 403; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_inner( 404; CHECK-PRESERVE-CFG-NEXT: entry: 405; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 406; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 407; CHECK-PRESERVE-CFG-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF0]] 408; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] 409; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 410; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 411; 412; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_inner( 413; CHECK-MODIFY-CFG-NEXT: entry: 414; CHECK-MODIFY-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 415; CHECK-MODIFY-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 416; CHECK-MODIFY-CFG-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF1]] 417; CHECK-MODIFY-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] 418; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 419; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 420; 421entry: 422 %min = alloca i32, align 4 423 store i32 0, ptr %min, align 4 424 %min.addr.data = select i1 %cond_inner, ptr %min, ptr %min_else, !prof !0 425 %addr = select i1 %cond_outer, ptr %min.addr.data, ptr %data_else, !prof !0 426 %r = load i32, ptr %addr, align 4 427 ret i32 %r 428} 429define i32 @non_speculatable_load_of_select_inner_inverted(i1 %cond_inner, i1 %cond_outer, ptr %data_else, ptr %min_then) { 430; CHECK-PRESERVE-CFG-LABEL: @non_speculatable_load_of_select_inner_inverted( 431; CHECK-PRESERVE-CFG-NEXT: entry: 432; CHECK-PRESERVE-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 433; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 434; CHECK-PRESERVE-CFG-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF0]] 435; CHECK-PRESERVE-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] 436; CHECK-PRESERVE-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 437; CHECK-PRESERVE-CFG-NEXT: ret i32 [[R]] 438; 439; CHECK-MODIFY-CFG-LABEL: @non_speculatable_load_of_select_inner_inverted( 440; CHECK-MODIFY-CFG-NEXT: entry: 441; CHECK-MODIFY-CFG-NEXT: [[MIN:%.*]] = alloca i32, align 4 442; CHECK-MODIFY-CFG-NEXT: store i32 0, ptr [[MIN]], align 4 443; CHECK-MODIFY-CFG-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF1]] 444; CHECK-MODIFY-CFG-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] 445; CHECK-MODIFY-CFG-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 446; CHECK-MODIFY-CFG-NEXT: ret i32 [[R]] 447; 448entry: 449 %min = alloca i32, align 4 450 store i32 0, ptr %min, align 4 451 %min.addr.data = select i1 %cond_inner, ptr %min_then, ptr %min, !prof !0 452 %addr = select i1 %cond_outer, ptr %min.addr.data, ptr %data_else, !prof !0 453 %r = load i32, ptr %addr, align 4 454 ret i32 %r 455} 456 457; When promoting speculative instruction, metadata that may trigger immediate UB should be dropped. 458define void @load_of_select_with_noundef_nonnull(ptr %buffer, i1 %b) { 459; CHECK-PRESERVE-CFG-LABEL: @load_of_select_with_noundef_nonnull( 460; CHECK-PRESERVE-CFG-NEXT: [[UB_PTR:%.*]] = alloca ptr, align 8 461; CHECK-PRESERVE-CFG-NEXT: [[SELECT_PTR:%.*]] = select i1 [[B:%.*]], ptr [[BUFFER:%.*]], ptr [[UB_PTR]] 462; CHECK-PRESERVE-CFG-NEXT: [[LOAD_PTR:%.*]] = load ptr, ptr [[SELECT_PTR]], align 8, !nonnull [[META1:![0-9]+]], !noundef [[META1]] 463; CHECK-PRESERVE-CFG-NEXT: ret void 464; 465; CHECK-MODIFY-CFG-LABEL: @load_of_select_with_noundef_nonnull( 466; CHECK-MODIFY-CFG-NEXT: br i1 [[B:%.*]], label [[DOTTHEN:%.*]], label [[DOTCONT:%.*]] 467; CHECK-MODIFY-CFG: .then: 468; CHECK-MODIFY-CFG-NEXT: [[LOAD_PTR_THEN_VAL:%.*]] = load ptr, ptr [[BUFFER:%.*]], align 8, !nonnull [[META2:![0-9]+]], !noundef [[META2]] 469; CHECK-MODIFY-CFG-NEXT: br label [[DOTCONT]] 470; CHECK-MODIFY-CFG: .cont: 471; CHECK-MODIFY-CFG-NEXT: [[LOAD_PTR:%.*]] = phi ptr [ [[LOAD_PTR_THEN_VAL]], [[DOTTHEN]] ], [ undef, [[TMP0:%.*]] ] 472; CHECK-MODIFY-CFG-NEXT: ret void 473; 474 %ub_ptr = alloca ptr 475 %select_ptr = select i1 %b, ptr %buffer, ptr %ub_ptr 476 %load_ptr = load ptr, ptr %select_ptr, !nonnull !1, !noundef !1 477 ret void 478} 479 480!0 = !{!"branch_weights", i32 1, i32 99} 481!1 = !{} 482 483; Ensure that the branch metadata is reversed to match the reversals above. 484 485declare void @llvm.lifetime.start.p0(i64, ptr ) 486declare void @llvm.lifetime.end.p0(i64, ptr) 487declare i32 @llvm.smax.i32(i32, i32) 488