Skip to content

Commit beed25b

Browse files
remove struct_gep, use manual layout calculations for va_arg
1 parent 123015e commit beed25b

File tree

6 files changed

+71
-111
lines changed

6 files changed

+71
-111
lines changed

compiler/rustc_codegen_gcc/src/builder.rs

+9-29
Original file line numberDiff line numberDiff line change
@@ -834,10 +834,17 @@ 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_gep(
843+
self.type_i8(),
844+
place.llval,
845+
&[self.const_usize(b_offset.bytes())],
846+
)
847+
};
841848
let llty = place.layout.scalar_pair_element_gcc_type(self, i);
842849
let load = self.load(llty, llptr, align);
843850
scalar_load_metadata(self, load, scalar);
@@ -971,33 +978,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
971978
result.get_address(None)
972979
}
973980

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-
1001981
/* Casts */
1002982
fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
1003983
// TODO(antoyo): check that it indeed truncate the value.

compiler/rustc_codegen_llvm/src/builder.rs

-5
Original file line numberDiff line numberDiff line change
@@ -778,11 +778,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
778778
}
779779
}
780780

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-
786781
/* Casts */
787782
fn trunc(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
788783
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
@@ -1301,13 +1301,6 @@ extern "C" {
13011301
NumIndices: c_uint,
13021302
Name: *const c_char,
13031303
) -> &'a Value;
1304-
pub fn LLVMBuildStructGEP2<'a>(
1305-
B: &Builder<'a>,
1306-
Ty: &'a Type,
1307-
Pointer: &'a Value,
1308-
Idx: c_uint,
1309-
Name: *const c_char,
1310-
) -> &'a Value;
13111304

13121305
// Casts
13131306
pub fn LLVMBuildTrunc<'a>(

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

@@ -324,42 +323,6 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
324323
self.scalar_llvm_type_at(cx, scalar)
325324
}
326325

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

compiler/rustc_codegen_llvm/src/va_arg.rs

+62-32
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,35 @@ 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_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(ptr_offset)]);
113+
let vr_top = bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(2 * ptr_offset)]);
114+
let gr_offs = bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(3 * ptr_offset)]);
115+
let vr_offs = bx.inbounds_gep(
116+
bx.type_i8(),
117+
va_list_addr,
118+
&[bx.cx.const_usize(3 * ptr_offset + i32_offset)],
119+
);
120+
97121
let layout = bx.cx.layout_of(target_ty);
98122

99123
let maybe_reg = bx.append_sibling_block("va_arg.maybe_reg");
@@ -104,16 +128,12 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
104128
let offset_align = Align::from_bytes(4).unwrap();
105129

106130
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));
131+
let (reg_off, reg_top, slot_size) = if gr_type {
110132
let nreg = (layout.size.bytes() + 7) / 8;
111-
(gr_offs, va_list_layout.llvm_field_index(bx.cx, 1), nreg * 8)
133+
(gr_offs, gr_top, nreg * 8)
112134
} else {
113-
let vr_off =
114-
bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 4));
115135
let nreg = (layout.size.bytes() + 15) / 16;
116-
(vr_off, va_list_layout.llvm_field_index(bx.cx, 2), nreg * 16)
136+
(vr_offs, vr_top, nreg * 16)
117137
};
118138

119139
// if the offset >= 0 then the value will be on the stack
@@ -141,8 +161,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
141161

142162
bx.switch_to_block(in_reg);
143163
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);
164+
let top = bx.load(top_type, reg_top, dl.pointer_align.abi);
146165

147166
// reg_value = *(@top + reg_off_v);
148167
let mut reg_addr = bx.gep(bx.type_i8(), top, &[reg_off_v]);
@@ -173,11 +192,33 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
173192
list: OperandRef<'tcx, &'ll Value>,
174193
target_ty: Ty<'tcx>,
175194
) -> &'ll Value {
195+
let dl = bx.cx.data_layout();
196+
176197
// Implementation of the s390x ELF ABI calling convention for va_args see
177198
// https://github.com/IBM/s390x-abi (chapter 1.2.4)
199+
//
200+
// typedef struct __va_list_tag {
201+
// long __gpr;
202+
// long __fpr;
203+
// void *__overflow_arg_area;
204+
// void *__reg_save_area;
205+
// } va_list[1];
178206
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);
207+
208+
// There is no padding between fields since `long` and `void*` both have size=8 align=8.
209+
// https://github.com/IBM/s390x-abi (Table 1.1.: Scalar types)
210+
let i64_offset = 8;
211+
let ptr_offset = 8;
212+
let gpr = va_list_addr;
213+
let fpr = bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(i64_offset)]);
214+
let overflow_arg_area =
215+
bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(2 * i64_offset)]);
216+
let reg_save_area = bx.inbounds_gep(
217+
bx.type_i8(),
218+
va_list_addr,
219+
&[bx.cx.const_usize(2 * i64_offset + ptr_offset)],
220+
);
221+
181222
let layout = bx.cx.layout_of(target_ty);
182223

183224
let in_reg = bx.append_sibling_block("va_arg.in_reg");
@@ -192,15 +233,10 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
192233
let padding = padded_size - unpadded_size;
193234

194235
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) };
236+
let (max_regs, reg_count, reg_save_index, reg_padding) =
237+
if gpr_type { (5, gpr, 2, padding) } else { (4, fpr, 16, 0) };
197238

198239
// 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-
);
204240
let reg_count_v = bx.load(bx.type_i64(), reg_count, Align::from_bytes(8).unwrap());
205241
let use_regs = bx.icmp(IntPredicate::IntULT, reg_count_v, bx.const_u64(max_regs));
206242
bx.cond_br(use_regs, in_reg, in_mem);
@@ -209,9 +245,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
209245
bx.switch_to_block(in_reg);
210246

211247
// 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);
248+
let reg_ptr_v = bx.load(bx.type_ptr(), reg_save_area, dl.pointer_align.abi);
215249
let scaled_reg_count = bx.mul(reg_count_v, bx.const_u64(8));
216250
let reg_off = bx.add(scaled_reg_count, bx.const_u64(reg_save_index * 8 + reg_padding));
217251
let reg_addr = bx.gep(bx.type_i8(), reg_ptr_v, &[reg_off]);
@@ -225,27 +259,23 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
225259
bx.switch_to_block(in_mem);
226260

227261
// 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);
262+
let arg_ptr_v =
263+
bx.load(bx.type_ptr(), overflow_arg_area, bx.tcx().data_layout.pointer_align.abi);
231264
let arg_off = bx.const_u64(padding);
232265
let mem_addr = bx.gep(bx.type_i8(), arg_ptr_v, &[arg_off]);
233266

234267
// Update the argument overflow area pointer.
235268
let arg_size = bx.cx().const_u64(padded_size);
236269
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);
270+
bx.store(new_arg_ptr_v, overflow_arg_area, dl.pointer_align.abi);
238271
bx.br(end);
239272

240273
// Return the appropriate result.
241274
bx.switch_to_block(end);
242275
let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
243276
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-
};
277+
let val_addr =
278+
if indirect { bx.load(bx.cx.type_ptr(), val_addr, dl.pointer_align.abi) } else { val_addr };
249279
bx.load(val_type, val_addr, layout.align.abi)
250280
}
251281

compiler/rustc_codegen_ssa/src/traits/builder.rs

-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ pub trait BuilderMethods<'a, 'tcx>:
190190
ptr: Self::Value,
191191
indices: &[Self::Value],
192192
) -> Self::Value;
193-
fn struct_gep(&mut self, ty: Self::Type, ptr: Self::Value, idx: u64) -> Self::Value;
194193

195194
fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
196195
fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;

0 commit comments

Comments
 (0)