Skip to content

Commit 432fffa

Browse files
committed
Auto merge of rust-lang#118991 - nikic:scalar-pair, r=nagisa
Separate immediate and in-memory ScalarPair representation Currently, we assume that ScalarPair is always represented using a two-element struct, both as an immediate value and when stored in memory. This currently works fairly well, but runs into problems with rust-lang#116672, where a ScalarPair involving an i128 type can no longer be represented as a two-element struct in memory. For example, the tuple `(i32, i128)` needs to be represented in-memory as `{ i32, [3 x i32], i128 }` to satisfy alignment requirements. Using `{ i32, i128 }` instead will result in the second element being stored at the wrong offset (prior to LLVM 18). Resolve this issue by no longer requiring that the immediate and in-memory type for ScalarPair are the same. The in-memory type will now look the same as for normal struct types (and will include padding filler and similar), while the immediate type stays a simple two-element struct type. This also means that booleans in immediate ScalarPair are now represented as i1 rather than i8, just like we do everywhere else. The core change here is to llvm_type (which now treats ScalarPair as a normal struct) and immediate_llvm_type (which returns the two-element struct that llvm_type used to produce). The rest is fixing things up to no longer assume these are the same. In particular, this switches places that try to get pointers to the ScalarPair elements to use byte-geps instead of struct-geps.
2 parents 6bc08a7 + 3cd6cde commit 432fffa

16 files changed

+80
-74
lines changed

Diff for: compiler/rustc_codegen_llvm/src/abi.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::type_::Type;
66
use crate::type_of::LayoutLlvmExt;
77
use crate::value::Value;
88

9-
use rustc_codegen_ssa::mir::operand::OperandValue;
9+
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
1010
use rustc_codegen_ssa::mir::place::PlaceRef;
1111
use rustc_codegen_ssa::traits::*;
1212
use rustc_codegen_ssa::MemFlags;
@@ -253,7 +253,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
253253
bx.lifetime_end(llscratch, scratch_size);
254254
}
255255
} else {
256-
OperandValue::Immediate(val).store(bx, dst);
256+
OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst);
257257
}
258258
}
259259

Diff for: compiler/rustc_codegen_llvm/src/builder.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -558,10 +558,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
558558
OperandValue::Immediate(self.to_immediate(llval, place.layout))
559559
} else if let abi::Abi::ScalarPair(a, b) = place.layout.abi {
560560
let b_offset = a.size(self).align_to(b.align(self).abi);
561-
let pair_ty = place.layout.llvm_type(self);
562561

563562
let mut load = |i, scalar: abi::Scalar, layout, align, offset| {
564-
let llptr = self.struct_gep(pair_ty, place.llval, i as u64);
563+
let llptr = if i == 0 {
564+
place.llval
565+
} else {
566+
self.inbounds_gep(
567+
self.type_i8(),
568+
place.llval,
569+
&[self.const_usize(b_offset.bytes())],
570+
)
571+
};
565572
let llty = place.layout.scalar_pair_element_llvm_type(self, i, false);
566573
let load = self.load(llty, llptr, align);
567574
scalar_load_metadata(self, load, scalar, layout, offset);

Diff for: compiler/rustc_codegen_llvm/src/intrinsic.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
179179
unsafe {
180180
llvm::LLVMSetAlignment(load, align);
181181
}
182-
self.to_immediate(load, self.layout_of(tp_ty))
182+
if !result.layout.is_zst() {
183+
self.store(load, result.llval, result.align);
184+
}
185+
return;
183186
}
184187
sym::volatile_store => {
185188
let dst = args[0].deref(self.cx());

Diff for: compiler/rustc_codegen_llvm/src/type_of.rs

+19-14
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,7 @@ fn uncached_llvm_type<'a, 'tcx>(
2626
let element = layout.scalar_llvm_type_at(cx, element);
2727
return cx.type_vector(element, count);
2828
}
29-
Abi::ScalarPair(..) => {
30-
return cx.type_struct(
31-
&[
32-
layout.scalar_pair_element_llvm_type(cx, 0, false),
33-
layout.scalar_pair_element_llvm_type(cx, 1, false),
34-
],
35-
false,
36-
);
37-
}
38-
Abi::Uninhabited | Abi::Aggregate { .. } => {}
29+
Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalarPair(..) => {}
3930
}
4031

4132
let name = match layout.ty.kind() {
@@ -275,11 +266,25 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
275266
}
276267

277268
fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
278-
if let Abi::Scalar(scalar) = self.abi {
279-
if scalar.is_bool() {
280-
return cx.type_i1();
269+
match self.abi {
270+
Abi::Scalar(scalar) => {
271+
if scalar.is_bool() {
272+
return cx.type_i1();
273+
}
281274
}
282-
}
275+
Abi::ScalarPair(..) => {
276+
// An immediate pair always contains just the two elements, without any padding
277+
// filler, as it should never be stored to memory.
278+
return cx.type_struct(
279+
&[
280+
self.scalar_pair_element_llvm_type(cx, 0, true),
281+
self.scalar_pair_element_llvm_type(cx, 1, true),
282+
],
283+
false,
284+
);
285+
}
286+
_ => {}
287+
};
283288
self.llvm_type(cx)
284289
}
285290

Diff for: compiler/rustc_codegen_ssa/src/mir/operand.rs

+7-12
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
231231
bx: &mut Bx,
232232
) -> V {
233233
if let OperandValue::Pair(a, b) = self.val {
234-
let llty = bx.cx().backend_type(self.layout);
234+
let llty = bx.cx().immediate_backend_type(self.layout);
235235
debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty);
236236
// Reconstruct the immediate aggregate.
237237
let mut llpair = bx.cx().const_poison(llty);
238-
let imm_a = bx.from_immediate(a);
239-
let imm_b = bx.from_immediate(b);
240-
llpair = bx.insert_value(llpair, imm_a, 0);
241-
llpair = bx.insert_value(llpair, imm_b, 1);
238+
llpair = bx.insert_value(llpair, a, 0);
239+
llpair = bx.insert_value(llpair, b, 1);
242240
llpair
243241
} else {
244242
self.immediate()
@@ -251,14 +249,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
251249
llval: V,
252250
layout: TyAndLayout<'tcx>,
253251
) -> Self {
254-
let val = if let Abi::ScalarPair(a, b) = layout.abi {
252+
let val = if let Abi::ScalarPair(..) = layout.abi {
255253
debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout);
256254

257255
// Deconstruct the immediate aggregate.
258256
let a_llval = bx.extract_value(llval, 0);
259-
let a_llval = bx.to_immediate_scalar(a_llval, a);
260257
let b_llval = bx.extract_value(llval, 1);
261-
let b_llval = bx.to_immediate_scalar(b_llval, b);
262258
OperandValue::Pair(a_llval, b_llval)
263259
} else {
264260
OperandValue::Immediate(llval)
@@ -435,15 +431,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
435431
let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else {
436432
bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout);
437433
};
438-
let ty = bx.backend_type(dest.layout);
439434
let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi);
440435

441-
let llptr = bx.struct_gep(ty, dest.llval, 0);
442436
let val = bx.from_immediate(a);
443437
let align = dest.align;
444-
bx.store_with_flags(val, llptr, align, flags);
438+
bx.store_with_flags(val, dest.llval, align, flags);
445439

446-
let llptr = bx.struct_gep(ty, dest.llval, 1);
440+
let llptr =
441+
bx.inbounds_gep(bx.type_i8(), dest.llval, &[bx.const_usize(b_offset.bytes())]);
447442
let val = bx.from_immediate(b);
448443
let align = dest.align.restrict_for_offset(b_offset);
449444
bx.store_with_flags(val, llptr, align, flags);

Diff for: compiler/rustc_codegen_ssa/src/mir/place.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -108,20 +108,17 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
108108
// Also handles the first field of Scalar, ScalarPair, and Vector layouts.
109109
self.llval
110110
}
111-
Abi::ScalarPair(a, b)
112-
if offset == a.size(bx.cx()).align_to(b.align(bx.cx()).abi) =>
113-
{
114-
// Offset matches second field.
115-
let ty = bx.backend_type(self.layout);
116-
bx.struct_gep(ty, self.llval, 1)
111+
Abi::ScalarPair(..) => {
112+
// FIXME(nikic): Generate this for all ABIs.
113+
bx.inbounds_gep(bx.type_i8(), self.llval, &[bx.const_usize(offset.bytes())])
117114
}
118-
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => {
115+
Abi::Scalar(_) | Abi::Vector { .. } if field.is_zst() => {
119116
// ZST fields (even some that require alignment) are not included in Scalar,
120117
// ScalarPair, and Vector layouts, so manually offset the pointer.
121118
bx.gep(bx.cx().type_i8(), self.llval, &[bx.const_usize(offset.bytes())])
122119
}
123-
Abi::Scalar(_) | Abi::ScalarPair(..) => {
124-
// All fields of Scalar and ScalarPair layouts must have been handled by this point.
120+
Abi::Scalar(_) => {
121+
// All fields of Scalar layouts must have been handled by this point.
125122
// Vector layouts have additional fields for each element of the vector, so don't panic in that case.
126123
bug!(
127124
"offset of non-ZST field `{:?}` does not match layout `{:#?}`",

Diff for: tests/codegen/align-byval.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,21 @@ pub struct ForceAlign16 {
106106
pub unsafe fn call_na1(x: NaturalAlign1) {
107107
// CHECK: start:
108108

109-
// m68k: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 1
110-
// m68k: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}} [[ALLOCA]])
109+
// m68k: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 1
110+
// m68k: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}} [[ALLOCA]])
111111

112-
// wasm: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 1
113-
// wasm: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}} [[ALLOCA]])
112+
// wasm: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 1
113+
// wasm: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}} [[ALLOCA]])
114114

115115
// x86_64-linux: call void @natural_align_1(i16
116116

117117
// x86_64-windows: call void @natural_align_1(i16
118118

119-
// i686-linux: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 4
120-
// i686-linux: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}} [[ALLOCA]])
119+
// i686-linux: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 4
120+
// i686-linux: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}} [[ALLOCA]])
121121

122-
// i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 4
123-
// i686-windows: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}} [[ALLOCA]])
122+
// i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 4
123+
// i686-windows: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}} [[ALLOCA]])
124124
natural_align_1(x);
125125
}
126126

@@ -199,17 +199,17 @@ pub unsafe fn call_fa16(x: ForceAlign16) {
199199
}
200200

201201
extern "C" {
202-
// m68k: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}})
202+
// m68k: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}})
203203

204-
// wasm: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}})
204+
// wasm: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}})
205205

206206
// x86_64-linux: declare void @natural_align_1(i16)
207207

208208
// x86_64-windows: declare void @natural_align_1(i16)
209209

210-
// i686-linux: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}})
210+
// i686-linux: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}})
211211

212-
// i686-windows: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}})
212+
// i686-windows: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}})
213213
fn natural_align_1(x: NaturalAlign1);
214214

215215
// m68k: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}})

Diff for: tests/codegen/align-struct.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 {
5757
// CHECK-LABEL: @enum4
5858
#[no_mangle]
5959
pub fn enum4(a: i32) -> Enum4 {
60-
// CHECK: %e4 = alloca { i32, i32 }, align 4
60+
// CHECK: %e4 = alloca %Enum4, align 4
6161
let e4 = Enum4::A(a);
6262
e4
6363
}

Diff for: tests/codegen/function-arguments-noopt.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub fn struct_call(x: S, f: fn(S) -> S) -> S {
5555
f(x)
5656
}
5757

58-
// CHECK: { i8, i8 } @enum_(i1 zeroext %x.0, i8 %x.1)
58+
// CHECK: { i1, i8 } @enum_(i1 zeroext %x.0, i8 %x.1)
5959
#[no_mangle]
6060
pub fn enum_(x: Option<u8>) -> Option<u8> {
6161
x
@@ -64,6 +64,6 @@ pub fn enum_(x: Option<u8>) -> Option<u8> {
6464
// CHECK-LABEL: @enum_call
6565
#[no_mangle]
6666
pub fn enum_call(x: Option<u8>, f: fn(Option<u8>) -> Option<u8>) -> Option<u8> {
67-
// CHECK: call { i8, i8 } %f(i1 zeroext %x.0, i8 %x.1)
67+
// CHECK: call { i1, i8 } %f(i1 zeroext %x.0, i8 %x.1)
6868
f(x)
6969
}

Diff for: tests/codegen/function-arguments.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
275275
x
276276
}
277277

278-
// CHECK: { i8, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1)
278+
// CHECK: { i1, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1)
279279
#[no_mangle]
280280
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
281281
x

Diff for: tests/codegen/intrinsics/transmute.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ pub unsafe fn check_byte_from_bool(x: bool) -> u8 {
190190
// CHECK-LABEL: @check_to_pair(
191191
#[no_mangle]
192192
pub unsafe fn check_to_pair(x: u64) -> Option<i32> {
193-
// CHECK: %_0 = alloca { i32, i32 }, align 4
193+
// CHECK: %_0 = alloca %"core::option::Option<i32>", align 4
194194
// CHECK: store i64 %x, ptr %_0, align 4
195195
transmute(x)
196196
}
@@ -203,10 +203,10 @@ pub unsafe fn check_from_pair(x: Option<i32>) -> u64 {
203203
const { assert!(std::mem::align_of::<Option<i32>>() == 4) };
204204

205205
// CHECK: %_0 = alloca i64, align 8
206-
// CHECK: store i32 %x.0, ptr %0, align 8
207-
// CHECK: store i32 %x.1, ptr %1, align 4
208-
// CHECK: %2 = load i64, ptr %_0, align 8
209-
// CHECK: ret i64 %2
206+
// CHECK: store i32 %x.0, ptr %_0, align 8
207+
// CHECK: store i32 %x.1, ptr %0, align 4
208+
// CHECK: %[[R:.+]] = load i64, ptr %_0, align 8
209+
// CHECK: ret i64 %[[R]]
210210
transmute(x)
211211
}
212212

Diff for: tests/codegen/personality_lifetimes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub fn test() {
2424
let _s = S;
2525
// Check that the personality slot alloca gets a lifetime start in each cleanup block, not just
2626
// in the first one.
27-
// CHECK: [[SLOT:%[0-9]+]] = alloca { ptr, i32 }
27+
// CHECK: [[SLOT:%[0-9]+]] = alloca { ptr, i32{{.*}} }
2828
// CHECK-LABEL: cleanup:
2929
// CHECK: call void @llvm.lifetime.start.{{.*}}({{.*}})
3030
// CHECK-LABEL: cleanup1:

Diff for: tests/codegen/refs.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ pub fn helper(_: usize) {
1313
pub fn ref_dst(s: &[u8]) {
1414
// We used to generate an extra alloca and memcpy to ref the dst, so check that we copy
1515
// directly to the alloca for "x"
16-
// CHECK: [[X0:%[0-9]+]] = getelementptr inbounds { ptr, [[USIZE]] }, {{.*}} %x, i32 0, i32 0
17-
// CHECK: store ptr %s.0, {{.*}} [[X0]]
18-
// CHECK: [[X1:%[0-9]+]] = getelementptr inbounds { ptr, [[USIZE]] }, {{.*}} %x, i32 0, i32 1
16+
// CHECK: store ptr %s.0, {{.*}} %x
17+
// CHECK: [[X1:%[0-9]+]] = getelementptr inbounds i8, {{.*}} %x, {{i32 4|i64 8}}
1918
// CHECK: store [[USIZE]] %s.1, {{.*}} [[X1]]
2019

2120
let x = &*s;

Diff for: tests/codegen/scalar-pair-bool.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,25 @@
22

33
#![crate_type = "lib"]
44

5-
// CHECK: define{{.*}}{ i8, i8 } @pair_bool_bool(i1 noundef zeroext %pair.0, i1 noundef zeroext %pair.1)
5+
// CHECK: define{{.*}}{ i1, i1 } @pair_bool_bool(i1 noundef zeroext %pair.0, i1 noundef zeroext %pair.1)
66
#[no_mangle]
77
pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) {
88
pair
99
}
1010

11-
// CHECK: define{{.*}}{ i8, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 noundef %pair.1)
11+
// CHECK: define{{.*}}{ i1, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 noundef %pair.1)
1212
#[no_mangle]
1313
pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) {
1414
pair
1515
}
1616

17-
// CHECK: define{{.*}}{ i32, i8 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef zeroext %pair.1)
17+
// CHECK: define{{.*}}{ i32, i1 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef zeroext %pair.1)
1818
#[no_mangle]
1919
pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) {
2020
pair
2121
}
2222

23-
// CHECK: define{{.*}}{ i8, i8 } @pair_and_or(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1)
23+
// CHECK: define{{.*}}{ i1, i1 } @pair_and_or(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1)
2424
#[no_mangle]
2525
pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
2626
// Make sure it can operate directly on the unpacked args

Diff for: tests/codegen/slice-iter-nonnull.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// CHECK-LABEL: @slice_iter_next(
1616
#[no_mangle]
1717
pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> {
18-
// CHECK: %[[ENDP:.+]] = getelementptr{{.+}}ptr %it,{{.+}} 1
18+
// CHECK: %[[ENDP:.+]] = getelementptr inbounds i8, ptr %it, {{i32 4|i64 8}}
1919
// CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
2020
// CHECK-SAME: !nonnull
2121
// CHECK-SAME: !noundef
@@ -32,7 +32,7 @@ pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32
3232
// CHECK-LABEL: @slice_iter_next_back(
3333
#[no_mangle]
3434
pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> {
35-
// CHECK: %[[ENDP:.+]] = getelementptr{{.+}}ptr %it,{{.+}} 1
35+
// CHECK: %[[ENDP:.+]] = getelementptr inbounds i8, ptr %it, {{i32 4|i64 8}}
3636
// CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
3737
// CHECK-SAME: !nonnull
3838
// CHECK-SAME: !noundef
@@ -84,7 +84,7 @@ pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> {
8484
// CHECK-LABEL: @slice_iter_is_empty
8585
#[no_mangle]
8686
pub fn slice_iter_is_empty(it: &std::slice::Iter<'_, u32>) -> bool {
87-
// CHECK: %[[ENDP:.+]] = getelementptr{{.+}}ptr %it,{{.+}} 1
87+
// CHECK: %[[ENDP:.+]] = getelementptr inbounds i8, ptr %it, {{i32 4|i64 8}}
8888
// CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
8989
// CHECK-SAME: !nonnull
9090
// CHECK-SAME: !noundef
@@ -100,7 +100,7 @@ pub fn slice_iter_is_empty(it: &std::slice::Iter<'_, u32>) -> bool {
100100
// CHECK-LABEL: @slice_iter_len
101101
#[no_mangle]
102102
pub fn slice_iter_len(it: &std::slice::Iter<'_, u32>) -> usize {
103-
// CHECK: %[[ENDP:.+]] = getelementptr{{.+}}ptr %it,{{.+}} 1
103+
// CHECK: %[[ENDP:.+]] = getelementptr inbounds i8, ptr %it, {{i32 4|i64 8}}
104104
// CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
105105
// CHECK-SAME: !nonnull
106106
// CHECK-SAME: !noundef

Diff for: tests/codegen/zst-offset.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn scalar_layout(s: &(u64, ())) {
2222
// CHECK-LABEL: @scalarpair_layout
2323
#[no_mangle]
2424
pub fn scalarpair_layout(s: &(u64, u32, ())) {
25-
// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 12
25+
// CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 12
2626
let x = &s.2;
2727
witness(&x); // keep variable in an alloca
2828
}

0 commit comments

Comments
 (0)