Skip to content

Commit

Permalink
Leave FIXME for wasm layout difference.
Browse files Browse the repository at this point in the history
There is a distinction between running this on wasm and i686, even though they should be
identical. This technically is not _incorrect_, it's just an unexpected difference, which is
worth investigating, but not for correctness.
  • Loading branch information
JulianKnodt committed Feb 7, 2023
1 parent 610e1a1 commit 15f4eec
Show file tree
Hide file tree
Showing 11 changed files with 297 additions and 315 deletions.
42 changes: 27 additions & 15 deletions compiler/rustc_mir_transform/src/large_enums.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::rustc_middle::ty::util::IntTypeExt;
use crate::MirPass;
use rustc_data_structures::stable_map::FxHashMap;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, AdtDef, Const, ParamEnv, Ty, TyCtxt};
Expand All @@ -19,14 +19,21 @@ use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants};
/// Instead of emitting moves of the large variant,
/// Perform a memcpy instead.
/// Based off of [this HackMD](https://hackmd.io/@ft4bxUsFT5CEUBmRKYHr7w/rJM8BBPzD).
///
/// In summary, what this does is at runtime determine which enum variant is active,
/// and instead of copying all the bytes of the largest possible variant,
/// copy only the bytes for the currently active variant.
pub struct EnumSizeOpt {
pub(crate) discrepancy: u64,
}

impl<'tcx> MirPass<'tcx> for EnumSizeOpt {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let sess = tcx.sess;
if (!sess.opts.debugging_opts.unsound_mir_opts) || sess.mir_opt_level() < 3 {
// FIXME(julianknodt): one thing noticed while testing this mir-opt is that there is a
// different layout of large enums on wasm. It's not clear what is causing this layout
// difference, as it should be identical to i686 (32 bit).
if (!sess.opts.unstable_opts.unsound_mir_opts) || sess.mir_opt_level() < 3 {
return;
}
self.optim(tcx, body);
Expand Down Expand Up @@ -56,8 +63,8 @@ impl EnumSizeOpt {
Variants::Multiple { variants, .. } if variants.len() <= 1 => return None,
Variants::Multiple { variants, .. } => variants,
};
let min = variants.iter().map(|v| v.size()).min().unwrap();
let max = variants.iter().map(|v| v.size()).max().unwrap();
let min = variants.iter().map(|v| v.size).min().unwrap();
let max = variants.iter().map(|v| v.size).max().unwrap();
if max.bytes() - min.bytes() < self.discrepancy {
return None;
}
Expand Down Expand Up @@ -92,7 +99,7 @@ impl EnumSizeOpt {
for (var_idx, layout) in variants.iter_enumerated() {
let curr_idx =
target_bytes * adt_def.discriminant_for_variant(tcx, var_idx).val as usize;
let sz = layout.size();
let sz = layout.size;
match ptr_sized_int {
rustc_target::abi::Integer::I32 => {
encode_store!(curr_idx, data_layout.endian, sz.bytes() as u32);
Expand All @@ -115,8 +122,11 @@ impl EnumSizeOpt {
let mut alloc_cache = FxHashMap::default();
let body_did = body.source.def_id();
let param_env = tcx.param_env(body_did);
let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
for bb in bbs {

let blocks = body.basic_blocks.as_mut();
let local_decls = &mut body.local_decls;

for bb in blocks {
bb.expand_statements(|st| {
if let StatementKind::Assign(box (
lhs,
Expand Down Expand Up @@ -175,7 +185,7 @@ impl EnumSizeOpt {
kind: StatementKind::Assign(box (
discr_cast_place,
Rvalue::Cast(
CastKind::Misc,
CastKind::IntToInt,
Operand::Copy(discr_place),
tcx.types.usize,
),
Expand Down Expand Up @@ -217,7 +227,7 @@ impl EnumSizeOpt {
source_info,
kind: StatementKind::Assign(box (
dst_cast_place,
Rvalue::Cast(CastKind::Misc, Operand::Copy(dst), dst_cast_ty),
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty),
)),
};

Expand All @@ -240,17 +250,19 @@ impl EnumSizeOpt {
source_info,
kind: StatementKind::Assign(box (
src_cast_place,
Rvalue::Cast(CastKind::Misc, Operand::Copy(src), src_cast_ty),
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty),
)),
};

let copy_bytes = Statement {
source_info,
kind: StatementKind::CopyNonOverlapping(box CopyNonOverlapping {
src: Operand::Copy(src_cast_place),
dst: Operand::Copy(dst_cast_place),
count: Operand::Copy(size_place),
}),
kind: StatementKind::Intrinsic(
box NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
src: Operand::Copy(src_cast_place),
dst: Operand::Copy(dst_cast_place),
count: Operand::Copy(size_place),
}),
),
};

let store_dead = Statement {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#![allow(rustc::potential_query_instability)]
#![feature(box_patterns)]
#![feature(drain_filter)]
#![feature(box_syntax)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(never_type)]
Expand Down
84 changes: 40 additions & 44 deletions tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,50 @@
+ // MIR for `cand` after EnumSizeOpt

fn cand() -> () {
let mut _0: (); // return place in scope 0 at $DIR/enum_opt.rs:50:15: 50:15
let mut _1: Candidate; // in scope 0 at $DIR/enum_opt.rs:51:7: 51:12
let mut _2: Candidate; // in scope 0 at $DIR/enum_opt.rs:52:7: 52:34
let mut _3: [u64; 1024]; // in scope 0 at $DIR/enum_opt.rs:52:24: 52:33
+ let mut _4: [usize; 2]; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _5: isize; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _6: usize; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _7: usize; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _8: *mut Candidate; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _9: *mut u8; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _10: *const Candidate; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _11: *const u8; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
let mut _0: (); // return place in scope 0 at $DIR/enum_opt.rs:+0:15: +0:15
let mut _1: Candidate; // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
let mut _2: Candidate; // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:34
let mut _3: [u64; 1024]; // in scope 0 at $DIR/enum_opt.rs:+2:24: +2:33
+ let mut _4: [usize; 2]; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _5: isize; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _6: usize; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _7: usize; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _8: *mut Candidate; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _9: *mut u8; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _10: *const Candidate; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _11: *const u8; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
scope 1 {
debug a => _1; // in scope 1 at $DIR/enum_opt.rs:51:7: 51:12
debug a => _1; // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
}

bb0: {
StorageLive(_1); // scope 0 at $DIR/enum_opt.rs:51:7: 51:12
Deinit(_1); // scope 0 at $DIR/enum_opt.rs:51:15: 51:34
((_1 as Small).0: u8) = const 1_u8; // scope 0 at $DIR/enum_opt.rs:51:15: 51:34
discriminant(_1) = 0; // scope 0 at $DIR/enum_opt.rs:51:15: 51:34
StorageLive(_2); // scope 1 at $DIR/enum_opt.rs:52:7: 52:34
StorageLive(_3); // scope 1 at $DIR/enum_opt.rs:52:24: 52:33
_3 = [const 1_u64; 1024]; // scope 1 at $DIR/enum_opt.rs:52:24: 52:33
Deinit(_2); // scope 1 at $DIR/enum_opt.rs:52:7: 52:34
((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:52:7: 52:34
discriminant(_2) = 1; // scope 1 at $DIR/enum_opt.rs:52:7: 52:34
StorageDead(_3); // scope 1 at $DIR/enum_opt.rs:52:33: 52:34
- _1 = move _2; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ StorageLive(_4); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _4 = const [2_usize, 8196_usize]; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _5 = discriminant(_2); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _6 = _5 as usize (Misc); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _7 = _4[_6]; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _8 = &raw mut _1; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _9 = _8 as *mut u8 (Misc); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _10 = &raw const _2; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _11 = _10 as *const u8 (Misc); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ copy_nonoverlapping(src=_11, dst=_9, count=_7); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ StorageDead(_4); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
StorageDead(_2); // scope 1 at $DIR/enum_opt.rs:52:33: 52:34
_0 = const (); // scope 0 at $DIR/enum_opt.rs:50:15: 53:2
StorageDead(_1); // scope 0 at $DIR/enum_opt.rs:53:1: 53:2
return; // scope 0 at $DIR/enum_opt.rs:53:2: 53:2
}

bb1 (cleanup): {
resume; // scope 0 at $DIR/enum_opt.rs:50:1: 53:2
StorageLive(_1); // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
Deinit(_1); // scope 0 at $DIR/enum_opt.rs:+1:15: +1:34
((_1 as Small).0: u8) = const 1_u8; // scope 0 at $DIR/enum_opt.rs:+1:15: +1:34
discriminant(_1) = 0; // scope 0 at $DIR/enum_opt.rs:+1:15: +1:34
StorageLive(_2); // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
StorageLive(_3); // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
_3 = [const 1_u64; 1024]; // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
Deinit(_2); // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
discriminant(_2) = 1; // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
StorageDead(_3); // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
- _1 = move _2; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ StorageLive(_4); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _4 = const [2_usize, 8196_usize]; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _5 = discriminant(_2); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _6 = _5 as usize (IntToInt); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _7 = _4[_6]; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _8 = &raw mut _1; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _9 = _8 as *mut u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _10 = &raw const _2; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _11 = _10 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ copy_nonoverlapping(dst = _9, src = _11, count = _7); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ StorageDead(_4); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
StorageDead(_2); // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
_0 = const (); // scope 0 at $DIR/enum_opt.rs:+0:15: +3:2
StorageDead(_1); // scope 0 at $DIR/enum_opt.rs:+3:1: +3:2
return; // scope 0 at $DIR/enum_opt.rs:+3:2: +3:2
}
}

84 changes: 40 additions & 44 deletions tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,50 @@
+ // MIR for `cand` after EnumSizeOpt

fn cand() -> () {
let mut _0: (); // return place in scope 0 at $DIR/enum_opt.rs:50:15: 50:15
let mut _1: Candidate; // in scope 0 at $DIR/enum_opt.rs:51:7: 51:12
let mut _2: Candidate; // in scope 0 at $DIR/enum_opt.rs:52:7: 52:34
let mut _3: [u64; 1024]; // in scope 0 at $DIR/enum_opt.rs:52:24: 52:33
+ let mut _4: [usize; 2]; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _5: isize; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _6: usize; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _7: usize; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _8: *mut Candidate; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _9: *mut u8; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _10: *const Candidate; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
+ let mut _11: *const u8; // in scope 0 at $DIR/enum_opt.rs:52:3: 52:34
let mut _0: (); // return place in scope 0 at $DIR/enum_opt.rs:+0:15: +0:15
let mut _1: Candidate; // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
let mut _2: Candidate; // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:34
let mut _3: [u64; 1024]; // in scope 0 at $DIR/enum_opt.rs:+2:24: +2:33
+ let mut _4: [usize; 2]; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _5: isize; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _6: usize; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _7: usize; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _8: *mut Candidate; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _9: *mut u8; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _10: *const Candidate; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
+ let mut _11: *const u8; // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
scope 1 {
debug a => _1; // in scope 1 at $DIR/enum_opt.rs:51:7: 51:12
debug a => _1; // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
}

bb0: {
StorageLive(_1); // scope 0 at $DIR/enum_opt.rs:51:7: 51:12
Deinit(_1); // scope 0 at $DIR/enum_opt.rs:51:15: 51:34
((_1 as Small).0: u8) = const 1_u8; // scope 0 at $DIR/enum_opt.rs:51:15: 51:34
discriminant(_1) = 0; // scope 0 at $DIR/enum_opt.rs:51:15: 51:34
StorageLive(_2); // scope 1 at $DIR/enum_opt.rs:52:7: 52:34
StorageLive(_3); // scope 1 at $DIR/enum_opt.rs:52:24: 52:33
_3 = [const 1_u64; 1024]; // scope 1 at $DIR/enum_opt.rs:52:24: 52:33
Deinit(_2); // scope 1 at $DIR/enum_opt.rs:52:7: 52:34
((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:52:7: 52:34
discriminant(_2) = 1; // scope 1 at $DIR/enum_opt.rs:52:7: 52:34
StorageDead(_3); // scope 1 at $DIR/enum_opt.rs:52:33: 52:34
- _1 = move _2; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ StorageLive(_4); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _4 = const [2_usize, 8200_usize]; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _5 = discriminant(_2); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _6 = _5 as usize (Misc); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _7 = _4[_6]; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _8 = &raw mut _1; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _9 = _8 as *mut u8 (Misc); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _10 = &raw const _2; // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ _11 = _10 as *const u8 (Misc); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ copy_nonoverlapping(src=_11, dst=_9, count=_7); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
+ StorageDead(_4); // scope 1 at $DIR/enum_opt.rs:52:3: 52:34
StorageDead(_2); // scope 1 at $DIR/enum_opt.rs:52:33: 52:34
_0 = const (); // scope 0 at $DIR/enum_opt.rs:50:15: 53:2
StorageDead(_1); // scope 0 at $DIR/enum_opt.rs:53:1: 53:2
return; // scope 0 at $DIR/enum_opt.rs:53:2: 53:2
}

bb1 (cleanup): {
resume; // scope 0 at $DIR/enum_opt.rs:50:1: 53:2
StorageLive(_1); // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
Deinit(_1); // scope 0 at $DIR/enum_opt.rs:+1:15: +1:34
((_1 as Small).0: u8) = const 1_u8; // scope 0 at $DIR/enum_opt.rs:+1:15: +1:34
discriminant(_1) = 0; // scope 0 at $DIR/enum_opt.rs:+1:15: +1:34
StorageLive(_2); // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
StorageLive(_3); // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
_3 = [const 1_u64; 1024]; // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
Deinit(_2); // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
discriminant(_2) = 1; // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
StorageDead(_3); // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
- _1 = move _2; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ StorageLive(_4); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _4 = const [2_usize, 8200_usize]; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _5 = discriminant(_2); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _6 = _5 as usize (IntToInt); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _7 = _4[_6]; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _8 = &raw mut _1; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _9 = _8 as *mut u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _10 = &raw const _2; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ _11 = _10 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ copy_nonoverlapping(dst = _9, src = _11, count = _7); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+ StorageDead(_4); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
StorageDead(_2); // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
_0 = const (); // scope 0 at $DIR/enum_opt.rs:+0:15: +3:2
StorageDead(_1); // scope 0 at $DIR/enum_opt.rs:+3:1: +3:2
return; // scope 0 at $DIR/enum_opt.rs:+3:2: +3:2
}
}

Loading

0 comments on commit 15f4eec

Please sign in to comment.