1
Fork 0

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](https://github.com/llvm/llvm-project/pull/68882) all constant-offset GEPs to i8, which has roughly the same effect as this change.

Fixes #121719.

Split out from #121577.

r? `@nikic`
This commit is contained in:
bors 2024-03-03 22:21:53 +00:00
commit 70aa0b86c0
16 changed files with 135 additions and 189 deletions

View file

@ -437,8 +437,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
let align = dest.align;
bx.store_with_flags(val, dest.llval, align, flags);
let llptr =
bx.inbounds_gep(bx.type_i8(), dest.llval, &[bx.const_usize(b_offset.bytes())]);
let llptr = bx.inbounds_ptradd(dest.llval, bx.const_usize(b_offset.bytes()));
let val = bx.from_immediate(b);
let align = dest.align.restrict_for_offset(b_offset);
bx.store_with_flags(val, llptr, align, flags);
@ -476,7 +475,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
let address = bx.ptrtoint(alloca, bx.type_isize());
let neg_address = bx.neg(address);
let offset = bx.and(neg_address, align_minus_1);
let dst = bx.inbounds_gep(bx.type_i8(), alloca, &[offset]);
let dst = bx.inbounds_ptradd(alloca, offset);
bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty());
// Store the allocated region and the extra to the indirect place.

View file

@ -9,7 +9,7 @@ use rustc_middle::mir;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty};
use rustc_target::abi::{Abi, Align, FieldsShape, Int, Pointer, TagEncoding};
use rustc_target::abi::{Align, FieldsShape, Int, Pointer, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
#[derive(Copy, Clone, Debug)]
@ -102,34 +102,14 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
// `simple` is called when we don't need to adjust the offset to
// the dynamic alignment of the field.
let mut simple = || {
let llval = match self.layout.abi {
_ if offset.bytes() == 0 => {
// Unions and newtypes only use an offset of 0.
// Also handles the first field of Scalar, ScalarPair, and Vector layouts.
self.llval
}
Abi::ScalarPair(..) => {
// FIXME(nikic): Generate this for all ABIs.
bx.inbounds_gep(bx.type_i8(), self.llval, &[bx.const_usize(offset.bytes())])
}
Abi::Scalar(_) | Abi::Vector { .. } if field.is_zst() => {
// ZST fields (even some that require alignment) are not included in Scalar,
// ScalarPair, and Vector layouts, so manually offset the pointer.
bx.gep(bx.cx().type_i8(), self.llval, &[bx.const_usize(offset.bytes())])
}
Abi::Scalar(_) => {
// All fields of Scalar layouts must have been handled by this point.
// Vector layouts have additional fields for each element of the vector, so don't panic in that case.
bug!(
"offset of non-ZST field `{:?}` does not match layout `{:#?}`",
field,
self.layout
);
}
_ => {
let ty = bx.backend_type(self.layout);
bx.struct_gep(ty, self.llval, bx.cx().backend_field_index(self.layout, ix))
}
let llval = if offset.bytes() == 0 {
self.llval
} else if field.is_zst() {
// FIXME(erikdesjardins): it should be fine to use inbounds for ZSTs too;
// keeping this logic for now to preserve previous behavior.
bx.ptradd(self.llval, bx.const_usize(offset.bytes()))
} else {
bx.inbounds_ptradd(self.llval, bx.const_usize(offset.bytes()))
};
PlaceRef {
llval,
@ -188,7 +168,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
debug!("struct_field_ptr: DST field offset: {:?}", offset);
// Adjust pointer.
let ptr = bx.gep(bx.cx().type_i8(), self.llval, &[offset]);
// FIXME(erikdesjardins): should be able to use inbounds here too.
let ptr = bx.ptradd(self.llval, offset);
PlaceRef { llval: ptr, llextra: self.llextra, layout: field, align: effective_field_align }
}

View file

@ -190,7 +190,12 @@ pub trait BuilderMethods<'a, 'tcx>:
ptr: Self::Value,
indices: &[Self::Value],
) -> Self::Value;
fn struct_gep(&mut self, ty: Self::Type, ptr: Self::Value, idx: u64) -> Self::Value;
fn ptradd(&mut self, ptr: Self::Value, offset: Self::Value) -> Self::Value {
self.gep(self.cx().type_i8(), ptr, &[offset])
}
fn inbounds_ptradd(&mut self, ptr: Self::Value, offset: Self::Value) -> Self::Value {
self.inbounds_gep(self.cx().type_i8(), ptr, &[offset])
}
fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;

View file

@ -113,7 +113,6 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool;
fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool;
fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64;
fn scalar_pair_element_backend_type(
&self,
layout: TyAndLayout<'tcx>,