diff options
| author | Josh Stone <jistone@redhat.com> | 2018-06-15 15:47:54 -0700 |
|---|---|---|
| committer | Josh Stone <jistone@redhat.com> | 2018-07-05 09:59:52 -0700 |
| commit | e5789765606baebd983bd9b1c870cb8b57a0627b (patch) | |
| tree | 865811bcbcead24fb5448ee44e53ae0a07370aeb /src/librustc_codegen_llvm | |
| parent | 94eb1760551096363ec04e42367b6b195592dbd8 (diff) | |
| download | rust-e5789765606baebd983bd9b1c870cb8b57a0627b.tar.gz rust-e5789765606baebd983bd9b1c870cb8b57a0627b.zip | |
Store scalar pair bools as i8 in memory
We represent `bool` as `i1` in a `ScalarPair`, unlike other aggregates,
to optimize IR for checked operators and the like. With this patch, we
still do so when the pair is an immediate value, but we use the `i8`
memory type when the value is loaded or stored as an LLVM aggregate.
So `(bool, bool)` looks like an `{ i1, i1 }` immediate, but `{ i8, i8 }`
in memory. When a pair is a direct function argument, `PassMode::Pair`,
it is still passed using the immediate `i1` type, but as a return value
it will use the `i8` memory type. Also, `bool`-like` enum tags will now
use scalar pairs when possible, where they were previously excluded due
to optimization issues.
Diffstat (limited to 'src/librustc_codegen_llvm')
| -rw-r--r-- | src/librustc_codegen_llvm/abi.rs | 4 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/base.rs | 15 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/mir/operand.rs | 23 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/mir/place.rs | 6 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/mir/rvalue.rs | 4 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/type_of.rs | 25 |
6 files changed, 41 insertions, 36 deletions
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 6b5baa402b4..4ff31ec7d1c 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -582,8 +582,8 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Ignore => continue, PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), PassMode::Pair(..) => { - llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0)); - llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1)); + llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true)); + llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } PassMode::Cast(cast) => cast.llvm_type(cx), diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index a4709739a23..4605b5f3f1d 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -265,8 +265,8 @@ pub fn unsize_thin_ptr<'a, 'tcx>( } let (lldata, llextra) = result.unwrap(); // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0)), - bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1))) + (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0, true)), + bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1, true))) } _ => bug!("unsize_thin_ptr: called on bad types"), } @@ -396,9 +396,14 @@ pub fn from_immediate(bx: &Builder, val: ValueRef) -> ValueRef { pub fn to_immediate(bx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef { if let layout::Abi::Scalar(ref scalar) = layout.abi { - if scalar.is_bool() { - return bx.trunc(val, Type::i1(bx.cx)); - } + return to_immediate_scalar(bx, val, scalar); + } + val +} + +pub fn to_immediate_scalar(bx: &Builder, val: ValueRef, scalar: &layout::Scalar) -> ValueRef { + if scalar.is_bool() { + return bx.trunc(val, Type::i1(bx.cx)); } val } diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index 3d3a4400bd8..3069a155d1f 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -128,13 +128,13 @@ impl<'a, 'tcx> OperandRef<'tcx> { bx.cx, a, a_scalar, - layout.scalar_pair_element_llvm_type(bx.cx, 0), + layout.scalar_pair_element_llvm_type(bx.cx, 0, true), ); let b_llval = scalar_to_llvm( bx.cx, b, b_scalar, - layout.scalar_pair_element_llvm_type(bx.cx, 1), + layout.scalar_pair_element_llvm_type(bx.cx, 1, true), ); OperandValue::Pair(a_llval, b_llval) }, @@ -193,8 +193,8 @@ impl<'a, 'tcx> OperandRef<'tcx> { self, llty); // Reconstruct the immediate aggregate. let mut llpair = C_undef(llty); - llpair = bx.insert_value(llpair, a, 0); - llpair = bx.insert_value(llpair, b, 1); + llpair = bx.insert_value(llpair, base::from_immediate(bx, a), 0); + llpair = bx.insert_value(llpair, base::from_immediate(bx, b), 1); llpair } else { self.immediate() @@ -206,13 +206,14 @@ impl<'a, 'tcx> OperandRef<'tcx> { llval: ValueRef, layout: TyLayout<'tcx>) -> OperandRef<'tcx> { - let val = if layout.is_llvm_scalar_pair() { + let val = if let layout::Abi::ScalarPair(ref a, ref b) = layout.abi { debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout); // Deconstruct the immediate aggregate. - OperandValue::Pair(bx.extract_value(llval, 0), - bx.extract_value(llval, 1)) + let a_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 0), a); + let b_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 1), b); + OperandValue::Pair(a_llval, b_llval) } else { OperandValue::Immediate(llval) }; @@ -264,8 +265,8 @@ impl<'a, 'tcx> OperandRef<'tcx> { *llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx)); } OperandValue::Pair(ref mut a, ref mut b) => { - *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0)); - *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1)); + *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0, true)); + *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1, true)); } OperandValue::Ref(..) => bug!() } @@ -308,10 +309,10 @@ impl<'a, 'tcx> OperandValue { } OperandValue::Pair(a, b) => { for (i, &x) in [a, b].iter().enumerate() { - let mut llptr = bx.struct_gep(dest.llval, i as u64); + let llptr = bx.struct_gep(dest.llval, i as u64); // Make sure to always store i1 as i8. if common::val_ty(x) == Type::i1(bx.cx) { - llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); + assert_eq!(common::val_ty(llptr), Type::i8p(bx.cx)); } let val = base::from_immediate(bx, x); bx.store_with_flags(val, llptr, dest.align, flags); diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index 2a1e3980adb..36dcd04b02e 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -16,7 +16,7 @@ use rustc::mir::tcx::PlaceTy; use rustc_data_structures::indexed_vec::Idx; use base; use builder::Builder; -use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big}; +use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big, val_ty}; use consts; use type_of::LayoutLlvmExt; use type_::Type; @@ -127,10 +127,10 @@ impl<'a, 'tcx> PlaceRef<'tcx> { OperandValue::Immediate(base::to_immediate(bx, llval, self.layout)) } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi { let load = |i, scalar: &layout::Scalar| { - let mut llptr = bx.struct_gep(self.llval, i as u64); + let llptr = bx.struct_gep(self.llval, i as u64); // Make sure to always load i1 as i8. if scalar.is_bool() { - llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); + assert_eq!(val_ty(llptr), Type::i8p(bx.cx)); } let load = bx.load(llptr, self.align); scalar_load_metadata(load, scalar); diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs index 0fd81c6074e..2e81fc16a58 100644 --- a/src/librustc_codegen_llvm/mir/rvalue.rs +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // HACK(eddyb) have to bitcast pointers // until LLVM removes pointee types. let lldata = bx.pointercast(lldata, - cast.scalar_pair_element_llvm_type(bx.cx, 0)); + cast.scalar_pair_element_llvm_type(bx.cx, 0, true)); OperandValue::Pair(lldata, llextra) } OperandValue::Immediate(lldata) => { @@ -251,7 +251,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let OperandValue::Pair(data_ptr, meta) = operand.val { if cast.is_llvm_scalar_pair() { let data_cast = bx.pointercast(data_ptr, - cast.scalar_pair_element_llvm_type(bx.cx, 0)); + cast.scalar_pair_element_llvm_type(bx.cx, 0, true)); OperandValue::Pair(data_cast, meta) } else { // cast to thin-ptr // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 88b75ff9c09..195f1c3b85a 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -47,8 +47,8 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } layout::Abi::ScalarPair(..) => { return Type::struct_(cx, &[ - layout.scalar_pair_element_llvm_type(cx, 0), - layout.scalar_pair_element_llvm_type(cx, 1), + layout.scalar_pair_element_llvm_type(cx, 0, false), + layout.scalar_pair_element_llvm_type(cx, 1, false), ], false); } layout::Abi::Uninhabited | @@ -206,7 +206,7 @@ pub trait LayoutLlvmExt<'tcx> { fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: &layout::Scalar, offset: Size) -> Type; fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - index: usize) -> Type; + index: usize, immediate: bool) -> Type; fn llvm_field_index(&self, index: usize) -> u64; fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo>; @@ -340,7 +340,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - index: usize) -> Type { + index: usize, immediate: bool) -> Type { // HACK(eddyb) special-case fat pointers until LLVM removes // pointee types, to avoid bitcasting every `OperandRef::deref`. match self.ty.sty { @@ -350,7 +350,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } ty::TyAdt(def, _) if def.is_box() => { let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); - return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index); + return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); } _ => {} } @@ -361,14 +361,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { }; let scalar = [a, b][index]; - // Make sure to return the same type `immediate_llvm_type` would, - // to avoid dealing with two types and the associated conversions. - // This means that `(bool, bool)` is represented as `{i1, i1}`, - // both in memory and as an immediate, while `bool` is typically - // `i8` in memory and only `i1` when immediate. While we need to - // load/store `bool` as `i8` to avoid crippling LLVM optimizations, - // `i1` in a LLVM aggregate is valid and mostly equivalent to `i8`. - if scalar.is_bool() { + // Make sure to return the same type `immediate_llvm_type` would when + // dealing with an immediate pair. This means that `(bool, bool)` is + // effectively represented as `{i8, i8}` in memory and `{i1, i1}` as an + // immediate, just like `bool` is typically `i8` in memory and only `i1` + // when immediate. We need to load/store `bool` as `i8` to avoid + // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. + if immediate && scalar.is_bool() { return Type::i1(cx); } |
