mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 19:58:32 +00:00
Auto merge of #76071 - khyperia:configurable_to_immediate, r=eddyb
Make to_immediate/from_immediate configurable by backends `librustc_codegen_ssa` has the concept of an immediate vs. memory type, and `librustc_codegen_llvm` uses this distinction to implement `bool`s being `i8` in memory, and `i1` in immediate contexts. However, some of that implementation leaked into `codegen_ssa` when converting to/from immediate values. So, move those methods into builder traits, so that behavior can be configured by backends. This is useful if a backend is able to keep bools as bools, or, needs to do more trickery than just bools to bytes. (Note that there's already a large amount of things abstracted with "immediate types" - this is just bringing this particular thing in line to be abstracted as well) --- Pinging @eddyb since that's who I was talking about this change with when they suggested I submit a PR.
This commit is contained in:
commit
6f1bbf5ee0
@ -6,7 +6,6 @@ use crate::type_::Type;
|
|||||||
use crate::type_of::LayoutLlvmExt;
|
use crate::type_of::LayoutLlvmExt;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use libc::{c_char, c_uint};
|
use libc::{c_char, c_uint};
|
||||||
use rustc_codegen_ssa::base::to_immediate;
|
|
||||||
use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, TypeKind};
|
use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, TypeKind};
|
||||||
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
||||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||||
@ -367,6 +366,20 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
(self.extract_value(res, 0), self.extract_value(res, 1))
|
(self.extract_value(res, 0), self.extract_value(res, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_immediate(&mut self, val: Self::Value) -> Self::Value {
|
||||||
|
if self.cx().val_ty(val) == self.cx().type_i1() {
|
||||||
|
self.zext(val, self.cx().type_i8())
|
||||||
|
} else {
|
||||||
|
val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_immediate_scalar(&mut self, val: Self::Value, scalar: &abi::Scalar) -> Self::Value {
|
||||||
|
if scalar.is_bool() {
|
||||||
|
return self.trunc(val, self.cx().type_i1());
|
||||||
|
}
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
fn alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value {
|
fn alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value {
|
||||||
let mut bx = Builder::with_cx(self.cx);
|
let mut bx = Builder::with_cx(self.cx);
|
||||||
bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) });
|
bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) });
|
||||||
@ -471,7 +484,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
}
|
}
|
||||||
load
|
load
|
||||||
});
|
});
|
||||||
OperandValue::Immediate(to_immediate(self, llval, place.layout))
|
OperandValue::Immediate(self.to_immediate(llval, place.layout))
|
||||||
} else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
|
} else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
|
||||||
let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
|
let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
|
||||||
|
|
||||||
@ -479,7 +492,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
let llptr = self.struct_gep(place.llval, i as u64);
|
let llptr = self.struct_gep(place.llval, i as u64);
|
||||||
let load = self.load(llptr, align);
|
let load = self.load(llptr, align);
|
||||||
scalar_load_metadata(self, load, scalar);
|
scalar_load_metadata(self, load, scalar);
|
||||||
if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
|
self.to_immediate_scalar(load, scalar)
|
||||||
};
|
};
|
||||||
|
|
||||||
OperandValue::Pair(
|
OperandValue::Pair(
|
||||||
|
@ -8,7 +8,7 @@ use crate::va_arg::emit_va_arg;
|
|||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
|
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
|
||||||
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
|
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
|
||||||
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
||||||
use rustc_codegen_ssa::glue;
|
use rustc_codegen_ssa::glue;
|
||||||
@ -301,7 +301,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMSetAlignment(load, align);
|
llvm::LLVMSetAlignment(load, align);
|
||||||
}
|
}
|
||||||
to_immediate(self, load, self.layout_of(tp_ty))
|
self.to_immediate(load, self.layout_of(tp_ty))
|
||||||
}
|
}
|
||||||
sym::volatile_store => {
|
sym::volatile_store => {
|
||||||
let dst = args[0].deref(self.cx());
|
let dst = args[0].deref(self.cx());
|
||||||
|
@ -38,7 +38,7 @@ use rustc_middle::middle::cstore::EncodedMetadata;
|
|||||||
use rustc_middle::middle::cstore::{self, LinkagePreference};
|
use rustc_middle::middle::cstore::{self, LinkagePreference};
|
||||||
use rustc_middle::middle::lang_items;
|
use rustc_middle::middle::lang_items;
|
||||||
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
|
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
|
||||||
use rustc_middle::ty::layout::{self, HasTyCtxt, TyAndLayout};
|
use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
|
||||||
use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
|
use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||||
@ -48,7 +48,7 @@ use rustc_session::utils::NativeLibKind;
|
|||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_symbol_mangling::test as symbol_names_test;
|
use rustc_symbol_mangling::test as symbol_names_test;
|
||||||
use rustc_target::abi::{Abi, Align, LayoutOf, Scalar, VariantIdx};
|
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
@ -330,35 +330,6 @@ pub fn wants_msvc_seh(sess: &Session) -> bool {
|
|||||||
sess.target.target.options.is_like_msvc
|
sess.target.target.options.is_like_msvc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|
||||||
bx: &mut Bx,
|
|
||||||
val: Bx::Value,
|
|
||||||
) -> Bx::Value {
|
|
||||||
if bx.cx().val_ty(val) == bx.cx().type_i1() { bx.zext(val, bx.cx().type_i8()) } else { val }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|
||||||
bx: &mut Bx,
|
|
||||||
val: Bx::Value,
|
|
||||||
layout: layout::TyAndLayout<'_>,
|
|
||||||
) -> Bx::Value {
|
|
||||||
if let Abi::Scalar(ref scalar) = layout.abi {
|
|
||||||
return to_immediate_scalar(bx, val, scalar);
|
|
||||||
}
|
|
||||||
val
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_immediate_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|
||||||
bx: &mut Bx,
|
|
||||||
val: Bx::Value,
|
|
||||||
scalar: &Scalar,
|
|
||||||
) -> Bx::Value {
|
|
||||||
if scalar.is_bool() {
|
|
||||||
return bx.trunc(val, bx.cx().type_i1());
|
|
||||||
}
|
|
||||||
val
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
dst: Bx::Value,
|
dst: Bx::Value,
|
||||||
|
@ -1143,7 +1143,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We store bools as `i8` so we need to truncate to `i1`.
|
// We store bools as `i8` so we need to truncate to `i1`.
|
||||||
llval = base::to_immediate(bx, llval, arg.layout);
|
llval = bx.to_immediate(llval, arg.layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +147,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
|
|||||||
debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty);
|
debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty);
|
||||||
// Reconstruct the immediate aggregate.
|
// Reconstruct the immediate aggregate.
|
||||||
let mut llpair = bx.cx().const_undef(llty);
|
let mut llpair = bx.cx().const_undef(llty);
|
||||||
let imm_a = base::from_immediate(bx, a);
|
let imm_a = bx.from_immediate(a);
|
||||||
let imm_b = base::from_immediate(bx, b);
|
let imm_b = bx.from_immediate(b);
|
||||||
llpair = bx.insert_value(llpair, imm_a, 0);
|
llpair = bx.insert_value(llpair, imm_a, 0);
|
||||||
llpair = bx.insert_value(llpair, imm_b, 1);
|
llpair = bx.insert_value(llpair, imm_b, 1);
|
||||||
llpair
|
llpair
|
||||||
@ -168,9 +168,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
|
|||||||
|
|
||||||
// Deconstruct the immediate aggregate.
|
// Deconstruct the immediate aggregate.
|
||||||
let a_llval = bx.extract_value(llval, 0);
|
let a_llval = bx.extract_value(llval, 0);
|
||||||
let a_llval = base::to_immediate_scalar(bx, a_llval, a);
|
let a_llval = bx.to_immediate_scalar(a_llval, a);
|
||||||
let b_llval = bx.extract_value(llval, 1);
|
let b_llval = bx.extract_value(llval, 1);
|
||||||
let b_llval = base::to_immediate_scalar(bx, b_llval, b);
|
let b_llval = bx.to_immediate_scalar(b_llval, b);
|
||||||
OperandValue::Pair(a_llval, b_llval)
|
OperandValue::Pair(a_llval, b_llval)
|
||||||
} else {
|
} else {
|
||||||
OperandValue::Immediate(llval)
|
OperandValue::Immediate(llval)
|
||||||
@ -220,29 +220,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
|
|||||||
_ => bug!("OperandRef::extract_field({:?}): not applicable", self),
|
_ => bug!("OperandRef::extract_field({:?}): not applicable", self),
|
||||||
};
|
};
|
||||||
|
|
||||||
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
|
match (&mut val, &field.abi) {
|
||||||
// Bools in union fields needs to be truncated.
|
(OperandValue::Immediate(llval), _) => {
|
||||||
let to_immediate_or_cast = |bx: &mut Bx, val, ty| {
|
// Bools in union fields needs to be truncated.
|
||||||
if ty == bx.cx().type_i1() { bx.trunc(val, ty) } else { bx.bitcast(val, ty) }
|
*llval = bx.to_immediate(*llval, field);
|
||||||
};
|
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
|
||||||
|
*llval = bx.bitcast(*llval, bx.cx().immediate_backend_type(field));
|
||||||
match val {
|
|
||||||
OperandValue::Immediate(ref mut llval) => {
|
|
||||||
*llval = to_immediate_or_cast(bx, *llval, bx.cx().immediate_backend_type(field));
|
|
||||||
}
|
}
|
||||||
OperandValue::Pair(ref mut a, ref mut b) => {
|
(OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => {
|
||||||
*a = to_immediate_or_cast(
|
// Bools in union fields needs to be truncated.
|
||||||
bx,
|
*a = bx.to_immediate_scalar(*a, a_abi);
|
||||||
*a,
|
*b = bx.to_immediate_scalar(*b, b_abi);
|
||||||
bx.cx().scalar_pair_element_backend_type(field, 0, true),
|
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
|
||||||
);
|
*a = bx.bitcast(*a, bx.cx().scalar_pair_element_backend_type(field, 0, true));
|
||||||
*b = to_immediate_or_cast(
|
*b = bx.bitcast(*b, bx.cx().scalar_pair_element_backend_type(field, 1, true));
|
||||||
bx,
|
|
||||||
*b,
|
|
||||||
bx.cx().scalar_pair_element_backend_type(field, 1, true),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
OperandValue::Ref(..) => bug!(),
|
(OperandValue::Pair(..), _) => bug!(),
|
||||||
|
(OperandValue::Ref(..), _) => bug!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
OperandRef { val, layout: field }
|
OperandRef { val, layout: field }
|
||||||
@ -302,7 +296,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
|
|||||||
bug!("cannot directly store unsized values");
|
bug!("cannot directly store unsized values");
|
||||||
}
|
}
|
||||||
OperandValue::Immediate(s) => {
|
OperandValue::Immediate(s) => {
|
||||||
let val = base::from_immediate(bx, s);
|
let val = bx.from_immediate(s);
|
||||||
bx.store_with_flags(val, dest.llval, dest.align, flags);
|
bx.store_with_flags(val, dest.llval, dest.align, flags);
|
||||||
}
|
}
|
||||||
OperandValue::Pair(a, b) => {
|
OperandValue::Pair(a, b) => {
|
||||||
@ -313,12 +307,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
|
|||||||
let b_offset = a_scalar.value.size(bx).align_to(b_scalar.value.align(bx).abi);
|
let b_offset = a_scalar.value.size(bx).align_to(b_scalar.value.align(bx).abi);
|
||||||
|
|
||||||
let llptr = bx.struct_gep(dest.llval, 0);
|
let llptr = bx.struct_gep(dest.llval, 0);
|
||||||
let val = base::from_immediate(bx, a);
|
let val = bx.from_immediate(a);
|
||||||
let align = dest.align;
|
let align = dest.align;
|
||||||
bx.store_with_flags(val, llptr, align, flags);
|
bx.store_with_flags(val, llptr, align, flags);
|
||||||
|
|
||||||
let llptr = bx.struct_gep(dest.llval, 1);
|
let llptr = bx.struct_gep(dest.llval, 1);
|
||||||
let val = base::from_immediate(bx, b);
|
let val = bx.from_immediate(b);
|
||||||
let align = dest.align.restrict_for_offset(b_offset);
|
let align = dest.align.restrict_for_offset(b_offset);
|
||||||
bx.store_with_flags(val, llptr, align, flags);
|
bx.store_with_flags(val, llptr, align, flags);
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use llvm.memset.p0i8.* to initialize byte arrays
|
// Use llvm.memset.p0i8.* to initialize byte arrays
|
||||||
let v = base::from_immediate(&mut bx, v);
|
let v = bx.from_immediate(v);
|
||||||
if bx.cx().val_ty(v) == bx.cx().type_i8() {
|
if bx.cx().val_ty(v) == bx.cx().type_i8() {
|
||||||
bx.memset(start, v, size, dest.align, MemFlags::empty());
|
bx.memset(start, v, size, dest.align, MemFlags::empty());
|
||||||
return bx;
|
return bx;
|
||||||
|
@ -13,9 +13,9 @@ use crate::mir::operand::OperandRef;
|
|||||||
use crate::mir::place::PlaceRef;
|
use crate::mir::place::PlaceRef;
|
||||||
use crate::MemFlags;
|
use crate::MemFlags;
|
||||||
|
|
||||||
use rustc_middle::ty::layout::HasParamEnv;
|
use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Abi, Align, Scalar, Size};
|
||||||
use rustc_target::spec::HasTargetSpec;
|
use rustc_target::spec::HasTargetSpec;
|
||||||
|
|
||||||
use std::iter::TrustedLen;
|
use std::iter::TrustedLen;
|
||||||
@ -115,6 +115,16 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||||||
rhs: Self::Value,
|
rhs: Self::Value,
|
||||||
) -> (Self::Value, Self::Value);
|
) -> (Self::Value, Self::Value);
|
||||||
|
|
||||||
|
fn from_immediate(&mut self, val: Self::Value) -> Self::Value;
|
||||||
|
fn to_immediate(&mut self, val: Self::Value, layout: TyAndLayout<'_>) -> Self::Value {
|
||||||
|
if let Abi::Scalar(ref scalar) = layout.abi {
|
||||||
|
self.to_immediate_scalar(val, scalar)
|
||||||
|
} else {
|
||||||
|
val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_immediate_scalar(&mut self, val: Self::Value, scalar: &Scalar) -> Self::Value;
|
||||||
|
|
||||||
fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
|
fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
|
||||||
fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
|
fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
|
||||||
fn array_alloca(&mut self, ty: Self::Type, len: Self::Value, align: Align) -> Self::Value;
|
fn array_alloca(&mut self, ty: Self::Type, len: Self::Value, align: Align) -> Self::Value;
|
||||||
|
Loading…
Reference in New Issue
Block a user