-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Add a MIR pass to lower 128-bit operators to lang item calls #46093
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
//! Replaces 128-bit operators with lang item calls | ||
|
||
use rustc::hir::def_id::DefId; | ||
use rustc::middle::lang_items::LangItem; | ||
use rustc::mir::*; | ||
use rustc::ty::{Slice, Ty, TyCtxt, TypeVariants}; | ||
use rustc_data_structures::indexed_vec::{Idx}; | ||
use transform::{MirPass, MirSource}; | ||
use syntax; | ||
|
||
pub struct Lower128Bit; | ||
|
||
impl MirPass for Lower128Bit { | ||
fn run_pass<'a, 'tcx>(&self, | ||
tcx: TyCtxt<'a, 'tcx, 'tcx>, | ||
_src: MirSource, | ||
mir: &mut Mir<'tcx>) { | ||
if !tcx.sess.opts.debugging_opts.lower_128bit_ops { | ||
return | ||
} | ||
|
||
self.lower_128bit_ops(tcx, mir); | ||
} | ||
} | ||
|
||
impl Lower128Bit { | ||
fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) { | ||
let mut new_blocks = Vec::new(); | ||
let cur_len = mir.basic_blocks().len(); | ||
|
||
let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut(); | ||
for block in basic_blocks.iter_mut() { | ||
for i in (0..block.statements.len()).rev() { | ||
let call_did = | ||
if let Some(call_did) = lower_to(&block.statements[i], local_decls, tcx) { | ||
call_did | ||
} else { | ||
continue; | ||
}; | ||
|
||
let after_call = BasicBlockData { | ||
statements: block.statements.drain((i+1)..).collect(), | ||
is_cleanup: block.is_cleanup, | ||
terminator: block.terminator.take(), | ||
}; | ||
|
||
let bin_statement = block.statements.pop().unwrap(); | ||
let (source_info, lvalue, lhs, rhs) = match bin_statement { | ||
Statement { | ||
source_info, | ||
kind: StatementKind::Assign( | ||
lvalue, | ||
Rvalue::BinaryOp(_, lhs, rhs)) | ||
} => (source_info, lvalue, lhs, rhs), | ||
Statement { | ||
source_info, | ||
kind: StatementKind::Assign( | ||
lvalue, | ||
Rvalue::CheckedBinaryOp(_, lhs, rhs)) | ||
} => (source_info, lvalue, lhs, rhs), | ||
_ => bug!("Statement doesn't match pattern any more?"), | ||
}; | ||
|
||
let bb = BasicBlock::new(cur_len + new_blocks.len()); | ||
new_blocks.push(after_call); | ||
|
||
block.terminator = | ||
Some(Terminator { | ||
source_info, | ||
kind: TerminatorKind::Call { | ||
func: Operand::function_handle(tcx, call_did, | ||
Slice::empty(), source_info.span), | ||
args: vec![lhs, rhs], | ||
destination: Some((lvalue, bb)), | ||
cleanup: None, | ||
}, | ||
}); | ||
} | ||
} | ||
|
||
basic_blocks.extend(new_blocks); | ||
} | ||
} | ||
|
||
fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>) | ||
-> Option<DefId> | ||
where D: HasLocalDecls<'tcx> | ||
{ | ||
match statement.kind { | ||
StatementKind::Assign(_, Rvalue::BinaryOp(bin_op, ref lhs, _)) => { | ||
let ty = lhs.ty(local_decls, tcx); | ||
if let Some(is_signed) = sign_of_128bit(&ty) { | ||
if let Some(item) = item_for_op(bin_op, is_signed) { | ||
return Some(tcx.require_lang_item(item)) | ||
} | ||
} | ||
}, | ||
StatementKind::Assign(_, Rvalue::CheckedBinaryOp(bin_op, ref lhs, _)) => { | ||
let ty = lhs.ty(local_decls, tcx); | ||
if let Some(is_signed) = sign_of_128bit(&ty) { | ||
if let Some(item) = item_for_checked_op(bin_op, is_signed) { | ||
return Some(tcx.require_lang_item(item)) | ||
} | ||
} | ||
}, | ||
_ => {}, | ||
} | ||
None | ||
} | ||
|
||
fn sign_of_128bit(ty: &Ty) -> Option<bool> { | ||
match ty.sty { | ||
TypeVariants::TyInt(syntax::ast::IntTy::I128) => Some(true), | ||
TypeVariants::TyUint(syntax::ast::UintTy::U128) => Some(false), | ||
_ => None, | ||
} | ||
} | ||
|
||
fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<LangItem> { | ||
let i = match (bin_op, is_signed) { | ||
(BinOp::Add, _) => LangItem::I128AddFnLangItem, | ||
(BinOp::Sub, _) => LangItem::I128SubFnLangItem, | ||
(BinOp::Mul, _) => LangItem::I128MulFnLangItem, | ||
(BinOp::Div, true) => LangItem::I128DivFnLangItem, | ||
(BinOp::Div, false) => LangItem::U128DivFnLangItem, | ||
(BinOp::Rem, true) => LangItem::I128RemFnLangItem, | ||
(BinOp::Rem, false) => LangItem::U128RemFnLangItem, | ||
(BinOp::Shl, _) => LangItem::I128ShlFnLangItem, | ||
(BinOp::Shr, true) => LangItem::I128ShrFnLangItem, | ||
(BinOp::Shr, false) => LangItem::U128ShrFnLangItem, | ||
_ => return None, | ||
}; | ||
Some(i) | ||
} | ||
|
||
fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<LangItem> { | ||
let i = match (bin_op, is_signed) { | ||
(BinOp::Add, true) => LangItem::I128AddoFnLangItem, | ||
(BinOp::Add, false) => LangItem::U128AddoFnLangItem, | ||
(BinOp::Sub, true) => LangItem::I128SuboFnLangItem, | ||
(BinOp::Sub, false) => LangItem::U128SuboFnLangItem, | ||
(BinOp::Mul, true) => LangItem::I128MuloFnLangItem, | ||
(BinOp::Mul, false) => LangItem::U128MuloFnLangItem, | ||
(BinOp::Shl, _) => LangItem::I128ShloFnLangItem, | ||
(BinOp::Shr, true) => LangItem::I128ShroFnLangItem, | ||
(BinOp::Shr, false) => LangItem::U128ShroFnLangItem, | ||
_ => return None, | ||
}; | ||
Some(i) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// compile-flags: -Z lower_128bit_ops -C debug_assertions=yes | ||
|
||
#![feature(i128_type)] | ||
#![feature(lang_items)] | ||
|
||
#[lang="i128_div"] | ||
fn i128_div(_x: i128, _y: i128) -> i128 { 3 } | ||
#[lang="u128_div"] | ||
fn u128_div(_x: i128, _y: i128) -> i128 { 4 } | ||
#[lang="i128_rem"] | ||
fn i128_rem(_x: i128, _y: i128) -> i128 { 5 } | ||
#[lang="u128_rem"] | ||
fn u128_rem(_x: i128, _y: i128) -> i128 { 6 } | ||
|
||
#[lang="i128_addo"] | ||
fn i128_addo(_x: i128, _y: i128) -> (i128, bool) { (0, false) } | ||
#[lang="u128_addo"] | ||
fn u128_addo(_x: i128, _y: i128) -> (i128, bool) { (1, false) } | ||
#[lang="i128_subo"] | ||
fn i128_subo(_x: i128, _y: i128) -> (i128, bool) { (2, false) } | ||
#[lang="u128_subo"] | ||
fn u128_subo(_x: i128, _y: i128) -> (i128, bool) { (3, false) } | ||
#[lang="i128_mulo"] | ||
fn i128_mulo(_x: i128, _y: i128) -> (i128, bool) { (4, false) } | ||
#[lang="u128_mulo"] | ||
fn u128_mulo(_x: i128, _y: i128) -> (i128, bool) { (5, false) } | ||
#[lang="i128_shlo"] | ||
fn i128_shlo(_x: i128, _y: u32) -> (i128, bool) { (6, false) } | ||
#[lang="i128_shro"] | ||
fn i128_shro(_x: i128, _y: u32) -> (i128, bool) { (7, false) } | ||
#[lang="u128_shro"] | ||
fn u128_shro(_x: i128, _y: u32) -> (i128, bool) { (8, false) } | ||
|
||
|
||
fn test_signed(mut x: i128) -> i128 { | ||
x += 1; | ||
x -= 2; | ||
x *= 3; | ||
x /= 4; | ||
x %= 5; | ||
x <<= 6; | ||
x >>= 7; | ||
x | ||
} | ||
|
||
fn test_unsigned(mut x: u128) -> u128 { | ||
x += 1; | ||
x -= 2; | ||
x *= 3; | ||
x /= 4; | ||
x %= 5; | ||
x <<= 6; | ||
x >>= 7; | ||
x | ||
} | ||
|
||
fn main() { | ||
test_signed(-200); | ||
test_unsigned(200); | ||
} | ||
|
||
// END RUST SOURCE | ||
|
||
// START rustc.test_signed.Lower128Bit.after.mir | ||
// _2 = const i128_addo(_1, const 1i128) -> bb10; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test should include the statements dealing with the tuple projections (i.e. the branch on |
||
// ... | ||
// _3 = const i128_subo(_1, const 2i128) -> bb11; | ||
// ... | ||
// _4 = const i128_mulo(_1, const 3i128) -> bb12; | ||
// ... | ||
// _1 = const i128_div(_1, const 4i128) -> bb13; | ||
// ... | ||
// _1 = const i128_rem(_1, const 5i128) -> bb15; | ||
// ... | ||
// _14 = const i128_shro(_1, const 7i32) -> bb16; | ||
// ... | ||
// _13 = const i128_shlo(_1, const 6i32) -> bb14; | ||
// END rustc.test_signed.Lower128Bit.after.mir | ||
|
||
// START rustc.test_unsigned.Lower128Bit.after.mir | ||
// _2 = const u128_addo(_1, const 1u128) -> bb8; | ||
// ... | ||
// _3 = const u128_subo(_1, const 2u128) -> bb9; | ||
// ... | ||
// _4 = const u128_mulo(_1, const 3u128) -> bb10; | ||
// ... | ||
// _1 = const u128_div(_1, const 4u128) -> bb11; | ||
// ... | ||
// _1 = const u128_rem(_1, const 5u128) -> bb13; | ||
// ... | ||
// _8 = const u128_shro(_1, const 7i32) -> bb14; | ||
// ... | ||
// _7 = const i128_shlo(_1, const 6i32) -> bb12; | ||
// END rustc.test_unsigned.Lower128Bit.after.mir |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since lang-items aren’t yet type-checked, could you add an assertion of some sort that checks whether the function really has the expected type?
#9307 is a long standing issue regarding that, and I would rather have an assertion in an easy to track location rather than right before trans.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, the next update generates an error like