Skip to content

Commit 877b93a

Browse files
committed
Move shifting code out of expr and into somewhere more accessible
1 parent 81ff2c2 commit 877b93a

File tree

3 files changed

+88
-63
lines changed

3 files changed

+88
-63
lines changed

src/librustc_trans/trans/base.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ use trans::intrinsic;
7575
use trans::machine;
7676
use trans::machine::{llsize_of, llsize_of_real};
7777
use trans::meth;
78+
use trans::mir;
7879
use trans::monomorphize;
7980
use trans::tvec;
8081
use trans::type_::Type;
@@ -1231,7 +1232,10 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
12311232
false
12321233
};
12331234

1235+
let mir = ccx.mir_map().get(&id);
1236+
12341237
let mut fcx = FunctionContext {
1238+
mir: mir,
12351239
llfn: llfndecl,
12361240
llenv: None,
12371241
llretslotptr: Cell::new(None),
@@ -1571,7 +1575,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
15711575
llfndecl: ValueRef,
15721576
param_substs: &'tcx Substs<'tcx>,
15731577
fn_ast_id: ast::NodeId,
1574-
_attributes: &[ast::Attribute],
1578+
attributes: &[ast::Attribute],
15751579
output_type: ty::FnOutput<'tcx>,
15761580
abi: Abi,
15771581
closure_env: closure::ClosureEnv<'b>) {
@@ -1600,6 +1604,12 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
16001604
&arena);
16011605
let mut bcx = init_function(&fcx, false, output_type);
16021606

1607+
if attributes.iter().any(|item| item.check_name("rustc_mir")) {
1608+
mir::trans_mir(bcx);
1609+
fcx.cleanup();
1610+
return;
1611+
}
1612+
16031613
// cleanup scope for the incoming arguments
16041614
let fn_cleanup_debug_loc =
16051615
debuginfo::get_cleanup_debug_loc_for_ast_node(ccx, fn_ast_id, body.span, true);

src/librustc_trans/trans/common.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub use self::ExprOrMethodCall::*;
1616

1717
use session::Session;
1818
use llvm;
19-
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef};
19+
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind};
2020
use llvm::{True, False, Bool};
2121
use middle::cfg;
2222
use middle::def;
@@ -40,6 +40,7 @@ use middle::traits;
4040
use middle::ty::{self, HasTypeFlags, Ty};
4141
use middle::ty::fold::{TypeFolder, TypeFoldable};
4242
use rustc_front::hir;
43+
use rustc_mir::repr::Mir;
4344
use util::nodemap::{FnvHashMap, NodeMap};
4445

4546
use arena::TypedArena;
@@ -328,6 +329,11 @@ impl<'tcx> DropFlagHintsMap<'tcx> {
328329
// Function context. Every LLVM function we create will have one of
329330
// these.
330331
pub struct FunctionContext<'a, 'tcx: 'a> {
332+
// The MIR for this function. At present, this is optional because
333+
// we only have MIR available for things that are local to the
334+
// crate.
335+
pub mir: Option<&'a Mir<'tcx>>,
336+
331337
// The ValueRef returned from a call to llvm::LLVMAddFunction; the
332338
// address of the first instruction in the sequence of
333339
// instructions for this function that will go in the .text
@@ -407,6 +413,10 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
407413
}
408414

409415
impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
416+
pub fn mir(&self) -> &'a Mir<'tcx> {
417+
self.mir.unwrap()
418+
}
419+
410420
pub fn arg_offset(&self) -> usize {
411421
self.env_arg_pos() + if self.llenv.is_some() { 1 } else { 0 }
412422
}
@@ -644,6 +654,10 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
644654
}
645655
pub fn sess(&self) -> &'blk Session { self.fcx.ccx.sess() }
646656

657+
pub fn mir(&self) -> &'blk Mir<'tcx> {
658+
self.fcx.mir()
659+
}
660+
647661
pub fn name(&self, name: ast::Name) -> String {
648662
name.to_string()
649663
}
@@ -1132,3 +1146,65 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
11321146
ccx.sess().bug(&format!("no variant for {:?}::{}", adt_def, inlined_vid))
11331147
})
11341148
}
1149+
1150+
// To avoid UB from LLVM, these two functions mask RHS with an
1151+
// appropriate mask unconditionally (i.e. the fallback behavior for
1152+
// all shifts). For 32- and 64-bit types, this matches the semantics
1153+
// of Java. (See related discussion on #1877 and #10183.)
1154+
1155+
pub fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1156+
lhs: ValueRef,
1157+
rhs: ValueRef,
1158+
binop_debug_loc: DebugLoc) -> ValueRef {
1159+
let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs);
1160+
// #1877, #10183: Ensure that input is always valid
1161+
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
1162+
build::Shl(bcx, lhs, rhs, binop_debug_loc)
1163+
}
1164+
1165+
pub fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1166+
lhs_t: Ty<'tcx>,
1167+
lhs: ValueRef,
1168+
rhs: ValueRef,
1169+
binop_debug_loc: DebugLoc) -> ValueRef {
1170+
let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs);
1171+
// #1877, #10183: Ensure that input is always valid
1172+
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
1173+
let is_signed = lhs_t.is_signed();
1174+
if is_signed {
1175+
build::AShr(bcx, lhs, rhs, binop_debug_loc)
1176+
} else {
1177+
build::LShr(bcx, lhs, rhs, binop_debug_loc)
1178+
}
1179+
}
1180+
1181+
fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1182+
rhs: ValueRef,
1183+
debug_loc: DebugLoc) -> ValueRef {
1184+
let rhs_llty = val_ty(rhs);
1185+
build::And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc)
1186+
}
1187+
1188+
pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1189+
llty: Type,
1190+
mask_llty: Type,
1191+
invert: bool) -> ValueRef {
1192+
let kind = llty.kind();
1193+
match kind {
1194+
TypeKind::Integer => {
1195+
// i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
1196+
let val = llty.int_width() - 1;
1197+
if invert {
1198+
C_integral(mask_llty, !val, true)
1199+
} else {
1200+
C_integral(mask_llty, val, false)
1201+
}
1202+
},
1203+
TypeKind::Vector => {
1204+
let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert);
1205+
build::VectorSplat(bcx, mask_llty.vector_length(), mask)
1206+
},
1207+
_ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
1208+
}
1209+
}
1210+

src/librustc_trans/trans/expr.rs

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,29 +2574,6 @@ impl OverflowOpViaInputCheck {
25742574
}
25752575
}
25762576

2577-
fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2578-
llty: Type,
2579-
mask_llty: Type,
2580-
invert: bool) -> ValueRef {
2581-
let kind = llty.kind();
2582-
match kind {
2583-
TypeKind::Integer => {
2584-
// i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
2585-
let val = llty.int_width() - 1;
2586-
if invert {
2587-
C_integral(mask_llty, !val, true)
2588-
} else {
2589-
C_integral(mask_llty, val, false)
2590-
}
2591-
},
2592-
TypeKind::Vector => {
2593-
let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert);
2594-
VectorSplat(bcx, mask_llty.vector_length(), mask)
2595-
},
2596-
_ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
2597-
}
2598-
}
2599-
26002577
// Check if an integer or vector contains a nonzero element.
26012578
fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
26022579
value: ValueRef,
@@ -2616,44 +2593,6 @@ fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
26162593
}
26172594
}
26182595

2619-
// To avoid UB from LLVM, these two functions mask RHS with an
2620-
// appropriate mask unconditionally (i.e. the fallback behavior for
2621-
// all shifts). For 32- and 64-bit types, this matches the semantics
2622-
// of Java. (See related discussion on #1877 and #10183.)
2623-
2624-
fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2625-
lhs: ValueRef,
2626-
rhs: ValueRef,
2627-
binop_debug_loc: DebugLoc) -> ValueRef {
2628-
let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs);
2629-
// #1877, #10183: Ensure that input is always valid
2630-
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
2631-
Shl(bcx, lhs, rhs, binop_debug_loc)
2632-
}
2633-
2634-
fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2635-
lhs_t: Ty<'tcx>,
2636-
lhs: ValueRef,
2637-
rhs: ValueRef,
2638-
binop_debug_loc: DebugLoc) -> ValueRef {
2639-
let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs);
2640-
// #1877, #10183: Ensure that input is always valid
2641-
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
2642-
let is_signed = lhs_t.is_signed();
2643-
if is_signed {
2644-
AShr(bcx, lhs, rhs, binop_debug_loc)
2645-
} else {
2646-
LShr(bcx, lhs, rhs, binop_debug_loc)
2647-
}
2648-
}
2649-
2650-
fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2651-
rhs: ValueRef,
2652-
debug_loc: DebugLoc) -> ValueRef {
2653-
let rhs_llty = val_ty(rhs);
2654-
And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc)
2655-
}
2656-
26572596
fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan,
26582597
lhs_t: Ty<'tcx>, lhs: ValueRef,
26592598
rhs: ValueRef,

0 commit comments

Comments
 (0)