Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
cbe2f609
R
Rust
项目概览
int
/
Rust
12 个月 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
cbe2f609
编写于
10月 20, 2019
作者:
W
Wesley Wiser
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Implement pass to remove branches on uninhabited variants
上级
b497e189
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
354 addition
and
0 deletion
+354
-0
src/librustc_mir/lib.rs
src/librustc_mir/lib.rs
+1
-0
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/mod.rs
+3
-0
src/librustc_mir/transform/uninhabited_enum_branching.rs
src/librustc_mir/transform/uninhabited_enum_branching.rs
+126
-0
src/test/mir-opt/uninhabited_enum_branching.rs
src/test/mir-opt/uninhabited_enum_branching.rs
+224
-0
未找到文件。
src/librustc_mir/lib.rs
浏览文件 @
cbe2f609
...
...
@@ -26,6 +26,7 @@
#![feature(associated_type_bounds)]
#![feature(range_is_empty)]
#![feature(stmt_expr_attributes)]
#![feature(bool_to_option)]
#![recursion_limit=
"256"
]
...
...
src/librustc_mir/transform/mod.rs
浏览文件 @
cbe2f609
...
...
@@ -36,6 +36,7 @@
pub
mod
generator
;
pub
mod
inline
;
pub
mod
uniform_array_move_out
;
pub
mod
uninhabited_enum_branching
;
pub
(
crate
)
fn
provide
(
providers
:
&
mut
Providers
<
'_
>
)
{
self
::
qualify_consts
::
provide
(
providers
);
...
...
@@ -257,6 +258,8 @@ fn run_optimization_passes<'tcx>(
// Optimizations begin.
&
uninhabited_enum_branching
::
UninhabitedEnumBranching
,
&
simplify
::
SimplifyCfg
::
new
(
"after-uninhabited-enum-branching"
),
&
uniform_array_move_out
::
RestoreSubsliceArrayMoveOut
::
new
(
tcx
),
&
inline
::
Inline
,
...
...
src/librustc_mir/transform/uninhabited_enum_branching.rs
0 → 100644
浏览文件 @
cbe2f609
//! A pass that eliminates branches on uninhabited enum variants.
use
crate
::
transform
::{
MirPass
,
MirSource
};
use
rustc
::
mir
::{
BasicBlock
,
BasicBlockData
,
Body
,
Local
,
Operand
,
Rvalue
,
StatementKind
,
TerminatorKind
,
};
use
rustc
::
ty
::
layout
::{
Abi
,
TyLayout
,
Variants
};
use
rustc
::
ty
::{
Ty
,
TyCtxt
};
pub
struct
UninhabitedEnumBranching
;
fn
get_discriminant_local
(
terminator
:
&
TerminatorKind
<
'_
>
)
->
Option
<
Local
>
{
if
let
TerminatorKind
::
SwitchInt
{
discr
:
Operand
::
Move
(
p
),
..
}
=
terminator
{
p
.as_local
()
}
else
{
None
}
}
/// If the basic block terminates by switching on a discriminant, this returns the `Ty` the
/// discriminant is read from. Otherwise, returns None.
fn
get_switched_on_type
<
'tcx
>
(
block_data
:
&
BasicBlockData
<
'tcx
>
,
body
:
&
Body
<
'tcx
>
,
)
->
Option
<
Ty
<
'tcx
>>
{
let
terminator
=
block_data
.terminator
();
// Only bother checking blocks which terminate by switching on a local.
if
let
Some
(
local
)
=
get_discriminant_local
(
&
terminator
.kind
)
{
let
stmt_before_term
=
(
block_data
.statements
.len
()
>
0
)
.then_with
(||
&
block_data
.statements
[
block_data
.statements
.len
()
-
1
]
.kind
);
if
let
Some
(
StatementKind
::
Assign
(
box
(
l
,
Rvalue
::
Discriminant
(
place
))))
=
stmt_before_term
{
if
l
.as_local
()
==
Some
(
local
)
{
if
let
Some
(
r_local
)
=
place
.as_local
()
{
let
ty
=
body
.local_decls
[
r_local
]
.ty
;
if
ty
.is_enum
()
{
return
Some
(
ty
);
}
}
}
}
}
None
}
fn
variant_discriminants
<
'tcx
>
(
layout
:
&
TyLayout
<
'tcx
>
,
ty
:
Ty
<
'tcx
>
,
tcx
:
TyCtxt
<
'tcx
>
,
)
->
Vec
<
u128
>
{
match
&
layout
.details.variants
{
Variants
::
Single
{
index
}
=>
vec!
[
index
.as_u32
()
as
u128
],
Variants
::
Multiple
{
variants
,
..
}
=>
variants
.iter_enumerated
()
.filter_map
(|(
idx
,
layout
)|
{
(
layout
.abi
!=
Abi
::
Uninhabited
)
.then_with
(||
ty
.discriminant_for_variant
(
tcx
,
idx
)
.unwrap
()
.val
)
})
.collect
(),
}
}
impl
<
'tcx
>
MirPass
<
'tcx
>
for
UninhabitedEnumBranching
{
fn
run_pass
(
&
self
,
tcx
:
TyCtxt
<
'tcx
>
,
source
:
MirSource
<
'tcx
>
,
body
:
&
mut
Body
<
'tcx
>
)
{
if
source
.promoted
.is_some
()
{
return
;
}
trace!
(
"UninhabitedEnumBranching starting for {:?}"
,
source
);
let
basic_block_count
=
body
.basic_blocks
()
.len
();
for
bb
in
0
..
basic_block_count
{
let
bb
=
BasicBlock
::
from_usize
(
bb
);
trace!
(
"processing block {:?}"
,
bb
);
let
discriminant_ty
=
if
let
Some
(
ty
)
=
get_switched_on_type
(
&
body
.basic_blocks
()[
bb
],
body
)
{
ty
}
else
{
continue
;
};
let
layout
=
tcx
.layout_of
(
tcx
.param_env
(
source
.def_id
())
.and
(
discriminant_ty
));
let
allowed_variants
=
if
let
Ok
(
layout
)
=
layout
{
variant_discriminants
(
&
layout
,
discriminant_ty
,
tcx
)
}
else
{
continue
;
};
trace!
(
"allowed_variants = {:?}"
,
allowed_variants
);
if
let
TerminatorKind
::
SwitchInt
{
values
,
targets
,
..
}
=
&
mut
body
.basic_blocks_mut
()[
bb
]
.terminator_mut
()
.kind
{
let
vals
=
&*
values
;
let
zipped
=
vals
.iter
()
.zip
(
targets
.into_iter
());
let
mut
matched_values
=
Vec
::
with_capacity
(
allowed_variants
.len
());
let
mut
matched_targets
=
Vec
::
with_capacity
(
allowed_variants
.len
()
+
1
);
for
(
val
,
target
)
in
zipped
{
if
allowed_variants
.contains
(
val
)
{
matched_values
.push
(
*
val
);
matched_targets
.push
(
*
target
);
}
else
{
trace!
(
"eliminating {:?} -> {:?}"
,
val
,
target
);
}
}
// handle the "otherwise" branch
matched_targets
.push
(
targets
.pop
()
.unwrap
());
*
values
=
matched_values
.into
();
*
targets
=
matched_targets
;
}
else
{
unreachable!
()
}
}
}
}
src/test/mir-opt/uninhabited_enum_branching.rs
0 → 100644
浏览文件 @
cbe2f609
enum
Empty
{
}
// test matching an enum with uninhabited variants
enum
Test1
{
A
(
Empty
),
B
(
Empty
),
C
}
// test an enum where the discriminants don't match the variant indexes
// (the optimization should do nothing here)
enum
Test2
{
D
=
4
,
E
=
5
,
}
fn
main
()
{
match
Test1
::
C
{
Test1
::
A
(
_
)
=>
"A(Empty)"
,
Test1
::
B
(
_
)
=>
"B(Empty)"
,
Test1
::
C
=>
"C"
,
};
match
Test2
::
D
{
Test2
::
D
=>
"D"
,
Test2
::
E
=>
"E"
,
};
}
// END RUST SOURCE
//
// START rustc.main.UninhabitedEnumBranching.before.mir
// let mut _0: ();
// let _1: &str;
// let mut _2: Test1;
// let mut _3: isize;
// let mut _4: &str;
// let mut _5: &str;
// let _6: &str;
// let mut _7: Test2;
// let mut _8: isize;
// let mut _9: &str;
// bb0: {
// StorageLive(_1);
// StorageLive(_2);
// _2 = Test1::C;
// _3 = discriminant(_2);
// switchInt(move _3) -> [0isize: bb3, 1isize: bb4, 2isize: bb1, otherwise: bb2];
// }
// bb1: {
// StorageLive(_5);
// _5 = const "C";
// _1 = &(*_5);
// StorageDead(_5);
// goto -> bb5;
// }
// bb2: {
// unreachable;
// }
// bb3: {
// _1 = const "A(Empty)";
// goto -> bb5;
// }
// bb4: {
// StorageLive(_4);
// _4 = const "B(Empty)";
// _1 = &(*_4);
// StorageDead(_4);
// goto -> bb5;
// }
// bb5: {
// StorageDead(_2);
// StorageDead(_1);
// StorageLive(_6);
// StorageLive(_7);
// _7 = Test2::D;
// _8 = discriminant(_7);
// switchInt(move _8) -> [4isize: bb8, 5isize: bb6, otherwise: bb7];
// }
// bb6: {
// StorageLive(_9);
// _9 = const "E";
// _6 = &(*_9);
// StorageDead(_9);
// goto -> bb9;
// }
// bb7: {
// unreachable;
// }
// bb8: {
// _6 = const "D";
// goto -> bb9;
// }
// bb9: {
// StorageDead(_7);
// StorageDead(_6);
// _0 = ();
// return;
// }
// END rustc.main.UninhabitedEnumBranching.before.mir
// START rustc.main.UninhabitedEnumBranching.after.mir
// let mut _0: ();
// let _1: &str;
// let mut _2: Test1;
// let mut _3: isize;
// let mut _4: &str;
// let mut _5: &str;
// let _6: &str;
// let mut _7: Test2;
// let mut _8: isize;
// let mut _9: &str;
// bb0: {
// StorageLive(_1);
// StorageLive(_2);
// _2 = Test1::C;
// _3 = discriminant(_2);
// switchInt(move _3) -> [2isize: bb1, otherwise: bb2];
// }
// bb1: {
// StorageLive(_5);
// _5 = const "C";
// _1 = &(*_5);
// StorageDead(_5);
// goto -> bb5;
// }
// bb2: {
// unreachable;
// }
// bb3: {
// _1 = const "A(Empty)";
// goto -> bb5;
// }
// bb4: {
// StorageLive(_4);
// _4 = const "B(Empty)";
// _1 = &(*_4);
// StorageDead(_4);
// goto -> bb5;
// }
// bb5: {
// StorageDead(_2);
// StorageDead(_1);
// StorageLive(_6);
// StorageLive(_7);
// _7 = Test2::D;
// _8 = discriminant(_7);
// switchInt(move _8) -> [4isize: bb8, 5isize: bb6, otherwise: bb7];
// }
// bb6: {
// StorageLive(_9);
// _9 = const "E";
// _6 = &(*_9);
// StorageDead(_9);
// goto -> bb9;
// }
// bb7: {
// unreachable;
// }
// bb8: {
// _6 = const "D";
// goto -> bb9;
// }
// bb9: {
// StorageDead(_7);
// StorageDead(_6);
// _0 = ();
// return;
// }
// END rustc.main.UninhabitedEnumBranching.after.mir
// START rustc.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
// let mut _0: ();
// let _1: &str;
// let mut _2: Test1;
// let mut _3: isize;
// let mut _4: &str;
// let mut _5: &str;
// let _6: &str;
// let mut _7: Test2;
// let mut _8: isize;
// let mut _9: &str;
// bb0: {
// StorageLive(_1);
// StorageLive(_2);
// _2 = Test1::C;
// _3 = discriminant(_2);
// switchInt(move _3) -> [2isize: bb1, otherwise: bb2];
// }
// bb1: {
// StorageLive(_5);
// _5 = const "C";
// _1 = &(*_5);
// StorageDead(_5);
// StorageDead(_2);
// StorageDead(_1);
// StorageLive(_6);
// StorageLive(_7);
// _7 = Test2::D;
// _8 = discriminant(_7);
// switchInt(move _8) -> [4isize: bb5, 5isize: bb3, otherwise: bb4];
// }
// bb2: {
// unreachable;
// }
// bb3: {
// StorageLive(_9);
// _9 = const "E";
// _6 = &(*_9);
// StorageDead(_9);
// goto -> bb6;
// }
// bb4: {
// unreachable;
// }
// bb5: {
// _6 = const "D";
// goto -> bb6;
// }
// bb6: {
// StorageDead(_7);
// StorageDead(_6);
// _0 = ();
// return;
// }
// END rustc.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录