-use super::{FunctionCx, LocalRef};
use super::place::PlaceRef;
+use super::{FunctionCx, LocalRef};
-use crate::MemFlags;
use crate::base;
use crate::glue;
use crate::traits::*;
+use crate::MemFlags;
-use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
use rustc::mir;
+use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
use rustc::ty;
-use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size};
+use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout};
use std::fmt;
/// A single LLVM value.
Immediate(V),
/// A pair of immediate LLVM values. Used by fat pointers too.
- Pair(V, V)
+ Pair(V, V),
}
/// An `OperandRef` is an "SSA" reference to a Rust value, along with
impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
pub fn new_zst<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
- layout: TyLayout<'tcx>
+ layout: TyLayout<'tcx>,
) -> OperandRef<'tcx, V> {
assert!(layout.is_zst());
OperandRef {
val: OperandValue::Immediate(bx.const_undef(bx.immediate_backend_type(layout))),
- layout
+ layout,
}
}
pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
- val: &'tcx ty::Const<'tcx>
+ val: &'tcx ty::Const<'tcx>,
) -> Self {
let layout = bx.layout_of(val.ty);
ConstValue::Scalar(x) => {
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,
- _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+ _ => bug!("from_const: invalid ByVal layout: {:#?}", layout),
};
- let llval = bx.scalar_to_backend(
- x,
- scalar,
- bx.immediate_backend_type(layout),
- );
+ let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
OperandValue::Immediate(llval)
- },
+ }
ConstValue::Slice { data, start, end } => {
let a_scalar = match layout.abi {
layout::Abi::ScalarPair(ref a, _) => a,
- _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
+ _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout),
};
let a = Scalar::from(Pointer::new(
bx.tcx().alloc_map.lock().create_memory_alloc(data),
Size::from_bytes(start as u64),
- )).into();
+ ))
+ .into();
let a_llval = bx.scalar_to_backend(
a,
a_scalar,
);
let b_llval = bx.const_usize((end - start) as u64);
OperandValue::Pair(a_llval, b_llval)
- },
+ }
ConstValue::ByRef { alloc, offset } => {
return bx.load_operand(bx.from_const_alloc(layout, alloc, offset));
- },
+ }
};
- OperandRef {
- val,
- layout
- }
+ OperandRef { val, layout }
}
/// Asserts that this operand refers to a scalar and returns
pub fn immediate(self) -> V {
match self.val {
OperandValue::Immediate(s) => s,
- _ => bug!("not immediate: {:?}", self)
+ _ => bug!("not immediate: {:?}", self),
}
}
- pub fn deref<Cx: LayoutTypeMethods<'tcx>>(
- self,
- cx: &Cx
- ) -> PlaceRef<'tcx, V> {
- let projected_ty = self.layout.ty.builtin_deref(true)
- .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty;
+ pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
+ let projected_ty = self
+ .layout
+ .ty
+ .builtin_deref(true)
+ .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self))
+ .ty;
let (llptr, llextra) = match self.val {
OperandValue::Immediate(llptr) => (llptr, None),
OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
- OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self)
+ OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self),
};
let layout = cx.layout_of(projected_ty);
- PlaceRef {
- llval: llptr,
- llextra,
- layout,
- align: layout.align.abi,
- }
+ PlaceRef { llval: llptr, llextra, layout, align: layout.align.abi }
}
/// If this operand is a `Pair`, we return an aggregate with the two values.
/// For other cases, see `immediate`.
pub fn immediate_or_packed_pair<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
- bx: &mut Bx
+ bx: &mut Bx,
) -> V {
if let OperandValue::Pair(a, b) = self.val {
let llty = bx.cx().backend_type(self.layout);
- debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}",
- self, llty);
+ debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty);
// Reconstruct the immediate aggregate.
let mut llpair = bx.cx().const_undef(llty);
let imm_a = base::from_immediate(bx, a);
pub fn from_immediate_or_packed_pair<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
llval: V,
- layout: TyLayout<'tcx>
+ layout: TyLayout<'tcx>,
) -> Self {
let val = if let layout::Abi::ScalarPair(ref a, ref b) = layout.abi {
- debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",
- llval, layout);
+ debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout);
// Deconstruct the immediate aggregate.
let a_llval = bx.extract_value(llval, 0);
pub fn extract_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
&self,
bx: &mut Bx,
- i: usize
+ i: usize,
) -> Self {
let field = self.layout.field(bx.cx(), i);
let offset = self.layout.fields.offset(i);
}
// Newtype of a scalar, scalar pair or vector.
- (OperandValue::Immediate(_), _) |
- (OperandValue::Pair(..), _) if field.size == self.layout.size => {
+ (OperandValue::Immediate(_), _) | (OperandValue::Pair(..), _)
+ if field.size == self.layout.size =>
+ {
assert_eq!(offset.bytes(), 0);
self.val
}
assert_eq!(field.size, a.value.size(bx.cx()));
OperandValue::Immediate(a_llval)
} else {
- assert_eq!(offset, a.value.size(bx.cx())
- .align_to(b.value.align(bx.cx()).abi));
+ assert_eq!(offset, a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi));
assert_eq!(field.size, b.value.size(bx.cx()));
OperandValue::Immediate(b_llval)
}
// `#[repr(simd)]` types are also immediate.
(OperandValue::Immediate(llval), &layout::Abi::Vector { .. }) => {
- OperandValue::Immediate(
- bx.extract_element(llval, bx.cx().const_usize(i as u64)))
+ OperandValue::Immediate(bx.extract_element(llval, bx.cx().const_usize(i as u64)))
}
- _ => 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.
// Bools in union fields needs to be truncated.
let to_immediate_or_cast = |bx: &mut Bx, val, ty| {
- if ty == bx.cx().type_i1() {
- bx.trunc(val, ty)
- } else {
- bx.bitcast(val, ty)
- }
+ if ty == bx.cx().type_i1() { bx.trunc(val, ty) } else { bx.bitcast(val, ty) }
};
match val {
*llval = to_immediate_or_cast(bx, *llval, bx.cx().immediate_backend_type(field));
}
OperandValue::Pair(ref mut a, ref mut b) => {
- *a = to_immediate_or_cast(bx, *a, bx.cx()
- .scalar_pair_element_backend_type(field, 0, true));
- *b = to_immediate_or_cast(bx, *b, bx.cx()
- .scalar_pair_element_backend_type(field, 1, true));
+ *a = to_immediate_or_cast(
+ bx,
+ *a,
+ bx.cx().scalar_pair_element_backend_type(field, 0, true),
+ );
+ *b = to_immediate_or_cast(
+ bx,
+ *b,
+ bx.cx().scalar_pair_element_backend_type(field, 1, true),
+ );
}
- OperandValue::Ref(..) => bug!()
+ OperandValue::Ref(..) => bug!(),
}
- OperandRef {
- val,
- layout: field
- }
+ OperandRef { val, layout: field }
}
}
pub fn store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
bx: &mut Bx,
- dest: PlaceRef<'tcx, V>
+ dest: PlaceRef<'tcx, V>,
) {
self.store_with_flags(bx, dest, MemFlags::empty());
}
pub fn volatile_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
bx: &mut Bx,
- dest: PlaceRef<'tcx, V>
+ dest: PlaceRef<'tcx, V>,
) {
self.store_with_flags(bx, dest, MemFlags::VOLATILE);
}
pub fn nontemporal_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
bx: &mut Bx,
- dest: PlaceRef<'tcx, V>
+ dest: PlaceRef<'tcx, V>,
) {
self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL);
}
}
match self {
OperandValue::Ref(r, None, source_align) => {
- base::memcpy_ty(bx, dest.llval, dest.align, r, source_align,
- dest.layout, flags)
+ base::memcpy_ty(bx, dest.llval, dest.align, r, source_align, dest.layout, flags)
}
OperandValue::Ref(_, Some(_), _) => {
bug!("cannot directly store unsized values");
OperandValue::Pair(a, b) => {
let (a_scalar, b_scalar) = match dest.layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
- _ => bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout)
+ _ => bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout),
};
let b_offset = a_scalar.value.size(bx).align_to(b_scalar.value.align(bx).abi);
pub fn store_unsized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
bx: &mut Bx,
- indirect_dest: PlaceRef<'tcx, V>
+ indirect_dest: PlaceRef<'tcx, V>,
) {
debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
let flags = MemFlags::empty();
// `indirect_dest` must have `*mut T` type. We extract `T` out of it.
- let unsized_ty = indirect_dest.layout.ty.builtin_deref(true)
- .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)).ty;
-
- let (llptr, llextra) =
- if let OperandValue::Ref(llptr, Some(llextra), _) = self {
- (llptr, llextra)
- } else {
- bug!("store_unsized called with a sized value")
- };
+ let unsized_ty = indirect_dest
+ .layout
+ .ty
+ .builtin_deref(true)
+ .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
+ .ty;
+
+ let (llptr, llextra) = if let OperandValue::Ref(llptr, Some(llextra), _) = self {
+ (llptr, llextra)
+ } else {
+ bug!("store_unsized called with a sized value")
+ };
// FIXME: choose an appropriate alignment, or use dynamic align somehow
let max_align = Align::from_bits(128).unwrap();
fn maybe_codegen_consume_direct(
&mut self,
bx: &mut Bx,
- place_ref: &mir::PlaceRef<'_, 'tcx>
+ place_ref: &mir::PlaceRef<'_, 'tcx>,
) -> Option<OperandRef<'tcx, Bx::Value>> {
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
- if let mir::PlaceBase::Local(index) = place_ref.base {
- match self.locals[*index] {
- LocalRef::Operand(Some(mut o)) => {
- // Moves out of scalar and scalar pair fields are trivial.
- for elem in place_ref.projection.iter() {
- match elem {
- mir::ProjectionElem::Field(ref f, _) => {
- o = o.extract_field(bx, f.index());
- }
- mir::ProjectionElem::Index(_) |
- mir::ProjectionElem::ConstantIndex { .. } => {
- // ZSTs don't require any actual memory access.
- // FIXME(eddyb) deduplicate this with the identical
- // checks in `codegen_consume` and `extract_field`.
- let elem = o.layout.field(bx.cx(), 0);
- if elem.is_zst() {
- o = OperandRef::new_zst(bx, elem);
- } else {
- return None;
- }
+ match self.locals[*place_ref.local] {
+ LocalRef::Operand(Some(mut o)) => {
+ // Moves out of scalar and scalar pair fields are trivial.
+ for elem in place_ref.projection.iter() {
+ match elem {
+ mir::ProjectionElem::Field(ref f, _) => {
+ o = o.extract_field(bx, f.index());
+ }
+ mir::ProjectionElem::Index(_)
+ | mir::ProjectionElem::ConstantIndex { .. } => {
+ // ZSTs don't require any actual memory access.
+ // FIXME(eddyb) deduplicate this with the identical
+ // checks in `codegen_consume` and `extract_field`.
+ let elem = o.layout.field(bx.cx(), 0);
+ if elem.is_zst() {
+ o = OperandRef::new_zst(bx, elem);
+ } else {
+ return None;
}
- _ => return None,
}
+ _ => return None,
}
-
- Some(o)
- }
- LocalRef::Operand(None) => {
- bug!("use of {:?} before def", place_ref);
- }
- LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
- // watch out for locals that do not have an
- // alloca; they are handled somewhat differently
- None
}
+
+ Some(o)
+ }
+ LocalRef::Operand(None) => {
+ bug!("use of {:?} before def", place_ref);
+ }
+ LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
+ // watch out for locals that do not have an
+ // alloca; they are handled somewhat differently
+ None
}
- } else {
- None
}
}
pub fn codegen_consume(
&mut self,
bx: &mut Bx,
- place_ref: &mir::PlaceRef<'_, 'tcx>
+ place_ref: &mir::PlaceRef<'_, 'tcx>,
) -> OperandRef<'tcx, Bx::Value> {
debug!("codegen_consume(place_ref={:?})", place_ref);
pub fn codegen_operand(
&mut self,
bx: &mut Bx,
- operand: &mir::Operand<'tcx>
+ operand: &mir::Operand<'tcx>,
) -> OperandRef<'tcx, Bx::Value> {
debug!("codegen_operand(operand={:?})", operand);
match *operand {
- mir::Operand::Copy(ref place) |
- mir::Operand::Move(ref place) => {
+ mir::Operand::Copy(ref place) | mir::Operand::Move(ref place) => {
self.codegen_consume(bx, &place.as_ref())
}
mir::Operand::Constant(ref constant) => {
- self.eval_mir_constant_to_operand(bx, constant)
- .unwrap_or_else(|err| {
- match err {
- // errored or at least linted
- ErrorHandled::Reported => {},
- ErrorHandled::TooGeneric => {
- bug!("codgen encountered polymorphic constant")
- },
- }
- // Allow RalfJ to sleep soundly knowing that even refactorings that remove
- // the above error (or silence it under some conditions) will not cause UB.
- bx.abort();
- // We still have to return an operand but it doesn't matter,
- // this code is unreachable.
- let ty = self.monomorphize(&constant.literal.ty);
- let layout = bx.cx().layout_of(ty);
- bx.load_operand(PlaceRef::new_sized(
- bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))),
- layout,
- ))
- })
+ self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|err| {
+ match err {
+ // errored or at least linted
+ ErrorHandled::Reported => {}
+ ErrorHandled::TooGeneric => bug!("codgen encountered polymorphic constant"),
+ }
+ // Allow RalfJ to sleep soundly knowing that even refactorings that remove
+ // the above error (or silence it under some conditions) will not cause UB.
+ bx.abort();
+ // We still have to return an operand but it doesn't matter,
+ // this code is unreachable.
+ let ty = self.monomorphize(&constant.literal.ty);
+ let layout = bx.cx().layout_of(ty);
+ bx.load_operand(PlaceRef::new_sized(
+ bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))),
+ layout,
+ ))
+ })
}
}
}