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:
commit
70aa0b86c0
16 changed files with 135 additions and 189 deletions
|
@ -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.
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue