Skip to content

Commit 70aa0b8

Browse files
committed
Auto merge of #121665 - erikdesjardins:ptradd, r=nikic
Always generate GEP i8 / ptradd for struct offsets This implements #98615, and goes a bit further to remove `struct_gep` entirely. Upstream LLVM is in the beginning stages of [migrating to `ptradd`](https://discourse.llvm.org/t/rfc-replacing-getelementptr-with-ptradd/68699). LLVM 19 will [canonicalize](llvm/llvm-project#68882) all constant-offset GEPs to i8, which has roughly the same effect as this change. Fixes #121719. Split out from #121577. r? `@nikic`
2 parents 516b616 + 4016510 commit 70aa0b8

File tree

16 files changed

+135
-189
lines changed

16 files changed

+135
-189
lines changed

compiler/rustc_codegen_gcc/src/builder.rs

+5-29
Original file line numberDiff line numberDiff line change
@@ -834,10 +834,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
834834
}
835835
else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
836836
let b_offset = a.size(self).align_to(b.align(self).abi);
837-
let pair_type = place.layout.gcc_type(self);
838837

839838
let mut load = |i, scalar: &abi::Scalar, align| {
840-
let llptr = self.struct_gep(pair_type, place.llval, i as u64);
839+
let llptr = if i == 0 {
840+
place.llval
841+
} else {
842+
self.inbounds_ptradd(place.llval, self.const_usize(b_offset.bytes()))
843+
};
841844
let llty = place.layout.scalar_pair_element_gcc_type(self, i);
842845
let load = self.load(llty, llptr, align);
843846
scalar_load_metadata(self, load, scalar);
@@ -971,33 +974,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
971974
result.get_address(None)
972975
}
973976

974-
fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
975-
// FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
976-
assert_eq!(idx as usize as u64, idx);
977-
let value = ptr.dereference(None).to_rvalue();
978-
979-
if value_type.dyncast_array().is_some() {
980-
let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
981-
let element = self.context.new_array_access(None, value, index);
982-
element.get_address(None)
983-
}
984-
else if let Some(vector_type) = value_type.dyncast_vector() {
985-
let array_type = vector_type.get_element_type().make_pointer();
986-
let array = self.bitcast(ptr, array_type);
987-
let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
988-
let element = self.context.new_array_access(None, array, index);
989-
element.get_address(None)
990-
}
991-
else if let Some(struct_type) = value_type.is_struct() {
992-
// NOTE: due to opaque pointers now being used, we need to bitcast here.
993-
let ptr = self.bitcast_if_needed(ptr, value_type.make_pointer());
994-
ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None)
995-
}
996-
else {
997-
panic!("Unexpected type {:?}", value_type);
998-
}
999-
}
1000-
1001977
/* Casts */
1002978
fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
1003979
// TODO(antoyo): check that it indeed truncate the value.

compiler/rustc_codegen_gcc/src/type_of.rs

-23
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ pub trait LayoutGccExt<'tcx> {
151151
fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
152152
fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>;
153153
fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc>;
154-
fn gcc_field_index(&self, index: usize) -> u64;
155154
fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>;
156155
}
157156

@@ -306,24 +305,6 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
306305
self.scalar_gcc_type_at(cx, scalar, offset)
307306
}
308307

309-
fn gcc_field_index(&self, index: usize) -> u64 {
310-
match self.abi {
311-
Abi::Scalar(_) | Abi::ScalarPair(..) => {
312-
bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
313-
}
314-
_ => {}
315-
}
316-
match self.fields {
317-
FieldsShape::Primitive | FieldsShape::Union(_) => {
318-
bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
319-
}
320-
321-
FieldsShape::Array { .. } => index as u64,
322-
323-
FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2,
324-
}
325-
}
326-
327308
fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo> {
328309
if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) {
329310
return pointee;
@@ -353,10 +334,6 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
353334
layout.is_gcc_scalar_pair()
354335
}
355336

356-
fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 {
357-
layout.gcc_field_index(index)
358-
}
359-
360337
fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, _immediate: bool) -> Type<'gcc> {
361338
layout.scalar_pair_element_gcc_type(self, index)
362339
}

compiler/rustc_codegen_llvm/src/builder.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -603,11 +603,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
603603
let llptr = if i == 0 {
604604
place.llval
605605
} else {
606-
self.inbounds_gep(
607-
self.type_i8(),
608-
place.llval,
609-
&[self.const_usize(b_offset.bytes())],
610-
)
606+
self.inbounds_ptradd(place.llval, self.const_usize(b_offset.bytes()))
611607
};
612608
let llty = place.layout.scalar_pair_element_llvm_type(self, i, false);
613609
let load = self.load(llty, llptr, align);
@@ -778,11 +774,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
778774
}
779775
}
780776

781-
fn struct_gep(&mut self, ty: &'ll Type, ptr: &'ll Value, idx: u64) -> &'ll Value {
782-
assert_eq!(idx as c_uint as u64, idx);
783-
unsafe { llvm::LLVMBuildStructGEP2(self.llbuilder, ty, ptr, idx as c_uint, UNNAMED) }
784-
}
785-
786777
/* Casts */
787778
fn trunc(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
788779
unsafe { llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty, UNNAMED) }

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

-7
Original file line numberDiff line numberDiff line change
@@ -1306,13 +1306,6 @@ extern "C" {
13061306
NumIndices: c_uint,
13071307
Name: *const c_char,
13081308
) -> &'a Value;
1309-
pub fn LLVMBuildStructGEP2<'a>(
1310-
B: &Builder<'a>,
1311-
Ty: &'a Type,
1312-
Pointer: &'a Value,
1313-
Idx: c_uint,
1314-
Name: *const c_char,
1315-
) -> &'a Value;
13161309

13171310
// Casts
13181311
pub fn LLVMBuildTrunc<'a>(

compiler/rustc_codegen_llvm/src/type_.rs

-3
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,6 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
261261
fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool {
262262
layout.is_llvm_scalar_pair()
263263
}
264-
fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 {
265-
layout.llvm_field_index(self, index)
266-
}
267264
fn scalar_pair_element_backend_type(
268265
&self,
269266
layout: TyAndLayout<'tcx>,

compiler/rustc_codegen_llvm/src/type_of.rs

-37
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ pub trait LayoutLlvmExt<'tcx> {
174174
index: usize,
175175
immediate: bool,
176176
) -> &'a Type;
177-
fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64;
178177
fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type>;
179178
}
180179

@@ -326,42 +325,6 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
326325
self.scalar_llvm_type_at(cx, scalar)
327326
}
328327

329-
fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64 {
330-
match self.abi {
331-
Abi::Scalar(_) | Abi::ScalarPair(..) => {
332-
bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self)
333-
}
334-
_ => {}
335-
}
336-
match self.fields {
337-
FieldsShape::Primitive | FieldsShape::Union(_) => {
338-
bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self)
339-
}
340-
341-
FieldsShape::Array { .. } => index as u64,
342-
343-
FieldsShape::Arbitrary { .. } => {
344-
let variant_index = match self.variants {
345-
Variants::Single { index } => Some(index),
346-
_ => None,
347-
};
348-
349-
// Look up llvm field if indexes do not match memory order due to padding. If
350-
// `field_remapping` is `None` no padding was used and the llvm field index
351-
// matches the memory index.
352-
match cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
353-
Some(TypeLowering { field_remapping: Some(ref remap), .. }) => {
354-
remap[index] as u64
355-
}
356-
Some(_) => self.fields.memory_index(index) as u64,
357-
None => {
358-
bug!("TyAndLayout::llvm_field_index({:?}): type info not found", self)
359-
}
360-
}
361-
}
362-
}
363-
}
364-
365328
fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type> {
366329
debug_assert!(self.is_sized());
367330

compiler/rustc_codegen_llvm/src/va_arg.rs

+61-39
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
4444

4545
let aligned_size = size.align_to(slot_size).bytes() as i32;
4646
let full_direct_size = bx.cx().const_i32(aligned_size);
47-
let next = bx.inbounds_gep(bx.type_i8(), addr, &[full_direct_size]);
47+
let next = bx.inbounds_ptradd(addr, full_direct_size);
4848
bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi);
4949

5050
if size.bytes() < slot_size.bytes() && bx.tcx().sess.target.endian == Endian::Big {
5151
let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
52-
let adjusted = bx.inbounds_gep(bx.type_i8(), addr, &[adjusted_size]);
52+
let adjusted = bx.inbounds_ptradd(addr, adjusted_size);
5353
(adjusted, addr_align)
5454
} else {
5555
(addr, addr_align)
@@ -89,11 +89,31 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
8989
list: OperandRef<'tcx, &'ll Value>,
9090
target_ty: Ty<'tcx>,
9191
) -> &'ll Value {
92+
let dl = bx.cx.data_layout();
93+
9294
// Implementation of the AAPCS64 calling convention for va_args see
9395
// https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
96+
//
97+
// typedef struct va_list {
98+
// void * stack; // next stack param
99+
// void * gr_top; // end of GP arg reg save area
100+
// void * vr_top; // end of FP/SIMD arg reg save area
101+
// int gr_offs; // offset from gr_top to next GP register arg
102+
// int vr_offs; // offset from vr_top to next FP/SIMD register arg
103+
// } va_list;
94104
let va_list_addr = list.immediate();
95-
let va_list_layout = list.deref(bx.cx).layout;
96-
let va_list_ty = va_list_layout.llvm_type(bx);
105+
106+
// There is no padding between fields since `void*` is size=8 align=8, `int` is size=4 align=4.
107+
// See https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
108+
// Table 1, Byte size and byte alignment of fundamental data types
109+
// Table 3, Mapping of C & C++ built-in data types
110+
let ptr_offset = 8;
111+
let i32_offset = 4;
112+
let gr_top = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(ptr_offset));
113+
let vr_top = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * ptr_offset));
114+
let gr_offs = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(3 * ptr_offset));
115+
let vr_offs = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(3 * ptr_offset + i32_offset));
116+
97117
let layout = bx.cx.layout_of(target_ty);
98118

99119
let maybe_reg = bx.append_sibling_block("va_arg.maybe_reg");
@@ -104,16 +124,12 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
104124
let offset_align = Align::from_bytes(4).unwrap();
105125

106126
let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
107-
let (reg_off, reg_top_index, slot_size) = if gr_type {
108-
let gr_offs =
109-
bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 3));
127+
let (reg_off, reg_top, slot_size) = if gr_type {
110128
let nreg = (layout.size.bytes() + 7) / 8;
111-
(gr_offs, va_list_layout.llvm_field_index(bx.cx, 1), nreg * 8)
129+
(gr_offs, gr_top, nreg * 8)
112130
} else {
113-
let vr_off =
114-
bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 4));
115131
let nreg = (layout.size.bytes() + 15) / 16;
116-
(vr_off, va_list_layout.llvm_field_index(bx.cx, 2), nreg * 16)
132+
(vr_offs, vr_top, nreg * 16)
117133
};
118134

119135
// if the offset >= 0 then the value will be on the stack
@@ -141,15 +157,14 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
141157

142158
bx.switch_to_block(in_reg);
143159
let top_type = bx.type_ptr();
144-
let top = bx.struct_gep(va_list_ty, va_list_addr, reg_top_index);
145-
let top = bx.load(top_type, top, bx.tcx().data_layout.pointer_align.abi);
160+
let top = bx.load(top_type, reg_top, dl.pointer_align.abi);
146161

147162
// reg_value = *(@top + reg_off_v);
148-
let mut reg_addr = bx.gep(bx.type_i8(), top, &[reg_off_v]);
163+
let mut reg_addr = bx.ptradd(top, reg_off_v);
149164
if bx.tcx().sess.target.endian == Endian::Big && layout.size.bytes() != slot_size {
150165
// On big-endian systems the value is right-aligned in its slot.
151166
let offset = bx.const_i32((slot_size - layout.size.bytes()) as i32);
152-
reg_addr = bx.gep(bx.type_i8(), reg_addr, &[offset]);
167+
reg_addr = bx.ptradd(reg_addr, offset);
153168
}
154169
let reg_type = layout.llvm_type(bx);
155170
let reg_value = bx.load(reg_type, reg_addr, layout.align.abi);
@@ -173,11 +188,29 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
173188
list: OperandRef<'tcx, &'ll Value>,
174189
target_ty: Ty<'tcx>,
175190
) -> &'ll Value {
191+
let dl = bx.cx.data_layout();
192+
176193
// Implementation of the s390x ELF ABI calling convention for va_args see
177194
// https://github.com/IBM/s390x-abi (chapter 1.2.4)
195+
//
196+
// typedef struct __va_list_tag {
197+
// long __gpr;
198+
// long __fpr;
199+
// void *__overflow_arg_area;
200+
// void *__reg_save_area;
201+
// } va_list[1];
178202
let va_list_addr = list.immediate();
179-
let va_list_layout = list.deref(bx.cx).layout;
180-
let va_list_ty = va_list_layout.llvm_type(bx);
203+
204+
// There is no padding between fields since `long` and `void*` both have size=8 align=8.
205+
// https://github.com/IBM/s390x-abi (Table 1.1.: Scalar types)
206+
let i64_offset = 8;
207+
let ptr_offset = 8;
208+
let gpr = va_list_addr;
209+
let fpr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(i64_offset));
210+
let overflow_arg_area = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * i64_offset));
211+
let reg_save_area =
212+
bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * i64_offset + ptr_offset));
213+
181214
let layout = bx.cx.layout_of(target_ty);
182215

183216
let in_reg = bx.append_sibling_block("va_arg.in_reg");
@@ -192,15 +225,10 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
192225
let padding = padded_size - unpadded_size;
193226

194227
let gpr_type = indirect || !layout.is_single_fp_element(bx.cx);
195-
let (max_regs, reg_count_field, reg_save_index, reg_padding) =
196-
if gpr_type { (5, 0, 2, padding) } else { (4, 1, 16, 0) };
228+
let (max_regs, reg_count, reg_save_index, reg_padding) =
229+
if gpr_type { (5, gpr, 2, padding) } else { (4, fpr, 16, 0) };
197230

198231
// Check whether the value was passed in a register or in memory.
199-
let reg_count = bx.struct_gep(
200-
va_list_ty,
201-
va_list_addr,
202-
va_list_layout.llvm_field_index(bx.cx, reg_count_field),
203-
);
204232
let reg_count_v = bx.load(bx.type_i64(), reg_count, Align::from_bytes(8).unwrap());
205233
let use_regs = bx.icmp(IntPredicate::IntULT, reg_count_v, bx.const_u64(max_regs));
206234
bx.cond_br(use_regs, in_reg, in_mem);
@@ -209,12 +237,10 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
209237
bx.switch_to_block(in_reg);
210238

211239
// Work out the address of the value in the register save area.
212-
let reg_ptr =
213-
bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 3));
214-
let reg_ptr_v = bx.load(bx.type_ptr(), reg_ptr, bx.tcx().data_layout.pointer_align.abi);
240+
let reg_ptr_v = bx.load(bx.type_ptr(), reg_save_area, dl.pointer_align.abi);
215241
let scaled_reg_count = bx.mul(reg_count_v, bx.const_u64(8));
216242
let reg_off = bx.add(scaled_reg_count, bx.const_u64(reg_save_index * 8 + reg_padding));
217-
let reg_addr = bx.gep(bx.type_i8(), reg_ptr_v, &[reg_off]);
243+
let reg_addr = bx.ptradd(reg_ptr_v, reg_off);
218244

219245
// Update the register count.
220246
let new_reg_count_v = bx.add(reg_count_v, bx.const_u64(1));
@@ -225,27 +251,23 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
225251
bx.switch_to_block(in_mem);
226252

227253
// Work out the address of the value in the argument overflow area.
228-
let arg_ptr =
229-
bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 2));
230-
let arg_ptr_v = bx.load(bx.type_ptr(), arg_ptr, bx.tcx().data_layout.pointer_align.abi);
254+
let arg_ptr_v =
255+
bx.load(bx.type_ptr(), overflow_arg_area, bx.tcx().data_layout.pointer_align.abi);
231256
let arg_off = bx.const_u64(padding);
232-
let mem_addr = bx.gep(bx.type_i8(), arg_ptr_v, &[arg_off]);
257+
let mem_addr = bx.ptradd(arg_ptr_v, arg_off);
233258

234259
// Update the argument overflow area pointer.
235260
let arg_size = bx.cx().const_u64(padded_size);
236-
let new_arg_ptr_v = bx.inbounds_gep(bx.type_i8(), arg_ptr_v, &[arg_size]);
237-
bx.store(new_arg_ptr_v, arg_ptr, bx.tcx().data_layout.pointer_align.abi);
261+
let new_arg_ptr_v = bx.inbounds_ptradd(arg_ptr_v, arg_size);
262+
bx.store(new_arg_ptr_v, overflow_arg_area, dl.pointer_align.abi);
238263
bx.br(end);
239264

240265
// Return the appropriate result.
241266
bx.switch_to_block(end);
242267
let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
243268
let val_type = layout.llvm_type(bx);
244-
let val_addr = if indirect {
245-
bx.load(bx.cx.type_ptr(), val_addr, bx.tcx().data_layout.pointer_align.abi)
246-
} else {
247-
val_addr
248-
};
269+
let val_addr =
270+
if indirect { bx.load(bx.cx.type_ptr(), val_addr, dl.pointer_align.abi) } else { val_addr };
249271
bx.load(val_type, val_addr, layout.align.abi)
250272
}
251273

0 commit comments

Comments
 (0)