Auto merge of #52597 - oli-obk:promotion_simplify, r=nagisa

Promoteds are statics and statics have a place, not just a value

r? @eddyb

This makes everything around promoteds a little simpler
This commit is contained in:
bors 2018-07-24 13:10:06 +00:00
commit 6a3db033ad
57 changed files with 376 additions and 585 deletions

View file

@ -242,9 +242,11 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
g
}
pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
def_id: DefId,
is_mutable: bool) {
pub fn codegen_static<'a, 'tcx>(
cx: &CodegenCx<'a, 'tcx>,
def_id: DefId,
is_mutable: bool,
) {
unsafe {
let attrs = cx.tcx.codegen_fn_attrs(def_id);

View file

@ -507,14 +507,40 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
// promotes any complex rvalues to constants.
if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
match *arg {
// The shuffle array argument is usually not an explicit constant,
// but specified directly in the code. This means it gets promoted
// and we can then extract the value by evaluating the promoted.
mir::Operand::Copy(mir::Place::Promoted(box(index, ty))) |
mir::Operand::Move(mir::Place::Promoted(box(index, ty))) => {
let param_env = ty::ParamEnv::reveal_all();
let cid = mir::interpret::GlobalId {
instance: self.instance,
promoted: Some(index),
};
let c = bx.tcx().const_eval(param_env.and(cid));
let (llval, ty) = self.simd_shuffle_indices(
&bx,
terminator.source_info.span,
ty,
c,
);
return OperandRef {
val: Immediate(llval),
layout: bx.cx.layout_of(ty),
};
},
mir::Operand::Copy(_) |
mir::Operand::Move(_) => {
span_bug!(span, "shuffle indices must be constant");
}
mir::Operand::Constant(ref constant) => {
let c = self.eval_mir_constant(&bx, constant);
let (llval, ty) = self.simd_shuffle_indices(
&bx,
constant,
constant.span,
constant.ty,
c,
);
return OperandRef {
val: Immediate(llval),

View file

@ -25,6 +25,7 @@ use consts;
use type_of::LayoutLlvmExt;
use type_::Type;
use syntax::ast::Mutability;
use syntax::codemap::Span;
use super::super::callee;
use super::FunctionCx;
@ -117,13 +118,12 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
pub fn codegen_static_initializer<'a, 'tcx>(
cx: &CodegenCx<'a, 'tcx>,
def_id: DefId)
-> Result<(ValueRef, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>>
{
def_id: DefId,
) -> Result<(ValueRef, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>> {
let instance = ty::Instance::mono(cx.tcx, def_id);
let cid = GlobalId {
instance,
promoted: None
promoted: None,
};
let param_env = ty::ParamEnv::reveal_all();
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
@ -161,28 +161,19 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
bx: &Builder<'a, 'tcx>,
constant: &mir::Constant<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
match constant.literal {
mir::Literal::Promoted { index } => {
let param_env = ty::ParamEnv::reveal_all();
let cid = mir::interpret::GlobalId {
instance: self.instance,
promoted: Some(index),
};
bx.tcx().const_eval(param_env.and(cid))
}
mir::Literal::Value { value } => {
Ok(self.monomorphize(&value))
}
}.and_then(|c| self.fully_evaluate(bx, c))
let c = self.monomorphize(&constant.literal);
self.fully_evaluate(bx, c)
}
/// process constant containing SIMD shuffle indices
pub fn simd_shuffle_indices(
&mut self,
bx: &Builder<'a, 'tcx>,
constant: &mir::Constant<'tcx>,
span: Span,
ty: Ty<'tcx>,
constant: Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>>,
) -> (ValueRef, Ty<'tcx>) {
self.eval_mir_constant(bx, constant)
constant
.and_then(|c| {
let field_ty = c.ty.builtin_index().unwrap();
let fields = match c.ty.sty {
@ -217,11 +208,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
})
.unwrap_or_else(|e| {
e.report_as_error(
bx.tcx().at(constant.span),
bx.tcx().at(span),
"could not evaluate shuffle_indices at compile time",
);
// We've errored, so we don't have to produce working code.
let ty = self.monomorphize(&constant.ty);
let ty = self.monomorphize(&ty);
let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
(C_undef(llty), ty)
})

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use llvm::{ValueRef, LLVMConstInBoundsGEP};
use llvm::ValueRef;
use rustc::mir::interpret::ConstEvalErr;
use rustc::mir;
use rustc::mir::interpret::ConstValue;
@ -22,14 +22,12 @@ use common::{CodegenCx, C_undef, C_usize};
use builder::{Builder, MemFlags};
use value::Value;
use type_of::LayoutLlvmExt;
use type_::Type;
use consts;
use std::fmt;
use std::ptr;
use super::{FunctionCx, LocalRef};
use super::constant::{scalar_to_llvm, const_alloc_to_llvm};
use super::constant::scalar_to_llvm;
use super::place::PlaceRef;
/// The representation of a Rust value. The enum variant is in fact
@ -139,16 +137,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
OperandValue::Pair(a_llval, b_llval)
},
ConstValue::ByRef(alloc, offset) => {
let init = const_alloc_to_llvm(bx.cx, alloc);
let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
let llval = unsafe { LLVMConstInBoundsGEP(
consts::bitcast(base_addr, Type::i8p(bx.cx)),
&C_usize(bx.cx, offset.bytes()),
1,
)};
let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx));
},
};
@ -409,20 +398,12 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
self.eval_mir_constant(bx, constant)
.and_then(|c| OperandRef::from_const(bx, c))
.unwrap_or_else(|err| {
match constant.literal {
mir::Literal::Promoted { .. } => {
// this is unreachable as long as runtime
// and compile-time agree on values
// With floats that won't always be true
// so we generate an abort below
},
mir::Literal::Value { .. } => {
err.report_as_error(
bx.tcx().at(constant.span),
"could not evaluate constant operand",
);
},
}
err.report_as_error(
bx.tcx().at(constant.span),
"could not evaluate constant operand",
);
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
// the above error (or silence it under some conditions) will not cause UB
let fnname = bx.cx.get_intrinsic(&("llvm.trap"));
bx.call(fnname, &[], None);
// We've errored, so we don't have to produce working code.

View file

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use llvm::{self, ValueRef};
use llvm::{self, ValueRef, LLVMConstInBoundsGEP};
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, Size};
use rustc::mir;
use rustc::mir::tcx::PlaceTy;
use rustc_data_structures::indexed_vec::Idx;
@ -22,6 +22,7 @@ use type_of::LayoutLlvmExt;
use type_::Type;
use value::Value;
use glue;
use mir::constant::const_alloc_to_llvm;
use std::ptr;
@ -56,6 +57,24 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
}
}
pub fn from_const_alloc(
bx: &Builder<'a, 'tcx>,
layout: TyLayout<'tcx>,
alloc: &mir::interpret::Allocation,
offset: Size,
) -> PlaceRef<'tcx> {
let init = const_alloc_to_llvm(bx.cx, alloc);
let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
let llval = unsafe { LLVMConstInBoundsGEP(
consts::bitcast(base_addr, Type::i8p(bx.cx)),
&C_usize(bx.cx, offset.bytes()),
1,
)};
let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
PlaceRef::new_sized(llval, layout, alloc.align)
}
pub fn alloca(bx: &Builder<'a, 'tcx>, layout: TyLayout<'tcx>, name: &str)
-> PlaceRef<'tcx> {
debug!("alloca({:?}: {:?})", name, layout);
@ -421,6 +440,32 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
let result = match *place {
mir::Place::Local(_) => bug!(), // handled above
mir::Place::Promoted(box (index, ty)) => {
let param_env = ty::ParamEnv::reveal_all();
let cid = mir::interpret::GlobalId {
instance: self.instance,
promoted: Some(index),
};
let layout = cx.layout_of(self.monomorphize(&ty));
match bx.tcx().const_eval(param_env.and(cid)) {
Ok(val) => match val.val {
mir::interpret::ConstValue::ByRef(alloc, offset) => {
PlaceRef::from_const_alloc(bx, layout, alloc, offset)
}
_ => bug!("promoteds should have an allocation: {:?}", val),
},
Err(_) => {
// this is unreachable as long as runtime
// and compile-time agree on values
// With floats that won't always be true
// so we generate an abort
let fnname = bx.cx.get_intrinsic(&("llvm.trap"));
bx.call(fnname, &[], None);
let llval = C_undef(layout.llvm_type(bx.cx).ptr_to());
PlaceRef::new_sized(llval, layout, layout.align)
}
}
}
mir::Place::Static(box mir::Static { def_id, ty }) => {
let layout = cx.layout_of(self.monomorphize(&ty));
PlaceRef::new_sized(consts::get_static(cx, def_id), layout, layout.align)