Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
7279af86
R
Rust
项目概览
int
/
Rust
11 个月 前同步成功
通知
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,发现更多精彩内容 >>
提交
7279af86
编写于
6月 20, 2016
作者:
E
Eduard Burtescu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
trans: generalize immediate temporaries to all MIR locals.
上级
bec32eb4
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
422 addition
and
307 deletion
+422
-307
src/librustc/mir/repr.rs
src/librustc/mir/repr.rs
+35
-0
src/librustc/ty/sty.rs
src/librustc/ty/sty.rs
+7
-0
src/librustc_trans/mir/analyze.rs
src/librustc_trans/mir/analyze.rs
+81
-60
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/block.rs
+87
-54
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/constant.rs
+28
-39
src/librustc_trans/mir/lvalue.rs
src/librustc_trans/mir/lvalue.rs
+44
-57
src/librustc_trans/mir/mod.rs
src/librustc_trans/mir/mod.rs
+95
-58
src/librustc_trans/mir/operand.rs
src/librustc_trans/mir/operand.rs
+11
-10
src/librustc_trans/mir/statement.rs
src/librustc_trans/mir/statement.rs
+25
-28
src/test/codegen/loads.rs
src/test/codegen/loads.rs
+3
-0
src/test/codegen/naked-functions.rs
src/test/codegen/naked-functions.rs
+3
-1
src/test/compile-fail/issue-26548.rs
src/test/compile-fail/issue-26548.rs
+3
-0
未找到文件。
src/librustc/mir/repr.rs
浏览文件 @
7279af86
...
...
@@ -144,6 +144,40 @@ pub fn predecessors(&self) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> {
pub
fn
predecessors_for
(
&
self
,
bb
:
BasicBlock
)
->
Ref
<
Vec
<
BasicBlock
>>
{
Ref
::
map
(
self
.predecessors
(),
|
p
|
&
p
[
bb
])
}
/// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
/// to their index in the whole list of locals. This is useful if you
/// want to treat all locals the same instead of repeating yourself.
pub
fn
local_index
(
&
self
,
lvalue
:
&
Lvalue
<
'tcx
>
)
->
Option
<
Local
>
{
let
idx
=
match
*
lvalue
{
Lvalue
::
Arg
(
arg
)
=>
arg
.index
(),
Lvalue
::
Var
(
var
)
=>
{
self
.arg_decls
.len
()
+
var
.index
()
}
Lvalue
::
Temp
(
temp
)
=>
{
self
.arg_decls
.len
()
+
self
.var_decls
.len
()
+
temp
.index
()
}
Lvalue
::
ReturnPointer
=>
{
self
.arg_decls
.len
()
+
self
.var_decls
.len
()
+
self
.temp_decls
.len
()
}
Lvalue
::
Static
(
_
)
|
Lvalue
::
Projection
(
_
)
=>
return
None
};
Some
(
Local
::
new
(
idx
))
}
/// Counts the number of locals, such that that local_index
/// will always return an index smaller than this count.
pub
fn
count_locals
(
&
self
)
->
usize
{
self
.arg_decls
.len
()
+
self
.var_decls
.len
()
+
self
.temp_decls
.len
()
+
1
}
}
impl
<
'tcx
>
Index
<
BasicBlock
>
for
Mir
<
'tcx
>
{
...
...
@@ -663,6 +697,7 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
newtype_index!
(
Var
,
"var"
);
newtype_index!
(
Temp
,
"tmp"
);
newtype_index!
(
Arg
,
"arg"
);
newtype_index!
(
Local
,
"local"
);
/// A path to a value; something that can be evaluated without
/// changing or disturbing program state.
...
...
src/librustc/ty/sty.rs
浏览文件 @
7279af86
...
...
@@ -492,6 +492,13 @@ pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> {
ty
::
FnDiverging
=>
def
}
}
pub
fn
maybe_converging
(
self
)
->
Option
<
Ty
<
'tcx
>>
{
match
self
{
ty
::
FnConverging
(
t
)
=>
Some
(
t
),
ty
::
FnDiverging
=>
None
}
}
}
pub
type
PolyFnOutput
<
'tcx
>
=
Binder
<
FnOutput
<
'tcx
>>
;
...
...
src/librustc_trans/mir/analyze.rs
浏览文件 @
7279af86
...
...
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! An analysis to determine which
temporarie
s require allocas and
//! An analysis to determine which
local
s require allocas and
//! which do not.
use
rustc_data_structures
::
bitvec
::
BitVector
;
...
...
@@ -21,16 +21,20 @@
use
glue
;
use
super
::
rvalue
;
pub
fn
lvalue_
temps
<
'bcx
,
'tcx
>
(
bcx
:
Block
<
'bcx
,
'tcx
>
,
mir
:
&
mir
::
Mir
<
'tcx
>
)
->
BitVector
{
pub
fn
lvalue_
locals
<
'bcx
,
'tcx
>
(
bcx
:
Block
<
'bcx
,
'tcx
>
,
mir
:
&
mir
::
Mir
<
'tcx
>
)
->
BitVector
{
let
bcx
=
bcx
.build
();
let
mut
analyzer
=
TempAnalyzer
::
new
(
mir
,
&
bcx
,
mir
.temp_decls
.len
()
);
let
mut
analyzer
=
LocalAnalyzer
::
new
(
mir
,
&
bcx
);
analyzer
.visit_mir
(
mir
);
for
(
index
,
temp_decl
)
in
mir
.temp_decls
.iter
()
.enumerate
()
{
let
ty
=
bcx
.monomorphize
(
&
temp_decl
.ty
);
debug!
(
"temp {:?} has type {:?}"
,
index
,
ty
);
let
local_types
=
mir
.arg_decls
.iter
()
.map
(|
a
|
a
.ty
)
.chain
(
mir
.var_decls
.iter
()
.map
(|
v
|
v
.ty
))
.chain
(
mir
.temp_decls
.iter
()
.map
(|
t
|
t
.ty
))
.chain
(
mir
.return_ty
.maybe_converging
());
for
(
index
,
ty
)
in
local_types
.enumerate
()
{
let
ty
=
bcx
.monomorphize
(
&
ty
);
debug!
(
"local {} has type {:?}"
,
index
,
ty
);
if
ty
.is_scalar
()
||
ty
.is_unique
()
||
ty
.is_region_ptr
()
||
...
...
@@ -50,66 +54,87 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
// (e.g. structs) into an alloca unconditionally, just so
// that we don't have to deal with having two pathways
// (gep vs extractvalue etc).
analyzer
.mark_as_lvalue
(
index
);
analyzer
.mark_as_lvalue
(
mir
::
Local
::
new
(
index
)
);
}
}
analyzer
.lvalue_
temp
s
analyzer
.lvalue_
local
s
}
struct
Temp
Analyzer
<
'mir
,
'bcx
:
'mir
,
'tcx
:
'bcx
>
{
struct
Local
Analyzer
<
'mir
,
'bcx
:
'mir
,
'tcx
:
'bcx
>
{
mir
:
&
'mir
mir
::
Mir
<
'tcx
>
,
bcx
:
&
'mir
BlockAndBuilder
<
'bcx
,
'tcx
>
,
lvalue_
temp
s
:
BitVector
,
lvalue_
local
s
:
BitVector
,
seen_assigned
:
BitVector
}
impl
<
'mir
,
'bcx
,
'tcx
>
Temp
Analyzer
<
'mir
,
'bcx
,
'tcx
>
{
impl
<
'mir
,
'bcx
,
'tcx
>
Local
Analyzer
<
'mir
,
'bcx
,
'tcx
>
{
fn
new
(
mir
:
&
'mir
mir
::
Mir
<
'tcx
>
,
bcx
:
&
'mir
BlockAndBuilder
<
'bcx
,
'tcx
>
,
temp_count
:
usize
)
->
TempAnalyzer
<
'mir
,
'bcx
,
'tcx
>
{
TempAnalyzer
{
bcx
:
&
'mir
BlockAndBuilder
<
'bcx
,
'tcx
>
)
->
LocalAnalyzer
<
'mir
,
'bcx
,
'tcx
>
{
let
local_count
=
mir
.count_locals
();
LocalAnalyzer
{
mir
:
mir
,
bcx
:
bcx
,
lvalue_
temps
:
BitVector
::
new
(
temp
_count
),
seen_assigned
:
BitVector
::
new
(
temp
_count
)
lvalue_
locals
:
BitVector
::
new
(
local
_count
),
seen_assigned
:
BitVector
::
new
(
local
_count
)
}
}
fn
mark_as_lvalue
(
&
mut
self
,
temp
:
usize
)
{
debug!
(
"marking
temp {} as lvalue"
,
temp
);
self
.lvalue_
temps
.insert
(
temp
);
fn
mark_as_lvalue
(
&
mut
self
,
local
:
mir
::
Local
)
{
debug!
(
"marking
{:?} as lvalue"
,
local
);
self
.lvalue_
locals
.insert
(
local
.index
()
);
}
fn
mark_assigned
(
&
mut
self
,
temp
:
usize
)
{
if
!
self
.seen_assigned
.insert
(
temp
)
{
self
.mark_as_lvalue
(
temp
);
fn
mark_assigned
(
&
mut
self
,
local
:
mir
::
Local
)
{
if
!
self
.seen_assigned
.insert
(
local
.index
()
)
{
self
.mark_as_lvalue
(
local
);
}
}
}
impl
<
'mir
,
'bcx
,
'tcx
>
Visitor
<
'tcx
>
for
Temp
Analyzer
<
'mir
,
'bcx
,
'tcx
>
{
impl
<
'mir
,
'bcx
,
'tcx
>
Visitor
<
'tcx
>
for
Local
Analyzer
<
'mir
,
'bcx
,
'tcx
>
{
fn
visit_assign
(
&
mut
self
,
block
:
mir
::
BasicBlock
,
lvalue
:
&
mir
::
Lvalue
<
'tcx
>
,
rvalue
:
&
mir
::
Rvalue
<
'tcx
>
)
{
debug!
(
"visit_assign(block={:?}, lvalue={:?}, rvalue={:?})"
,
block
,
lvalue
,
rvalue
);
match
*
lvalue
{
mir
::
Lvalue
::
Temp
(
temp
)
=>
{
self
.mark_assigned
(
temp
.index
());
if
!
rvalue
::
rvalue_creates_operand
(
self
.mir
,
self
.bcx
,
rvalue
)
{
self
.mark_as_lvalue
(
temp
.index
());
}
}
_
=>
{
self
.visit_lvalue
(
lvalue
,
LvalueContext
::
Store
);
if
let
Some
(
index
)
=
self
.mir
.local_index
(
lvalue
)
{
self
.mark_assigned
(
index
);
if
!
rvalue
::
rvalue_creates_operand
(
self
.mir
,
self
.bcx
,
rvalue
)
{
self
.mark_as_lvalue
(
index
);
}
}
else
{
self
.visit_lvalue
(
lvalue
,
LvalueContext
::
Store
);
}
self
.visit_rvalue
(
rvalue
);
}
fn
visit_terminator_kind
(
&
mut
self
,
block
:
mir
::
BasicBlock
,
kind
:
&
mir
::
TerminatorKind
<
'tcx
>
)
{
match
*
kind
{
mir
::
TerminatorKind
::
Call
{
func
:
mir
::
Operand
::
Constant
(
mir
::
Constant
{
literal
:
mir
::
Literal
::
Item
{
def_id
,
..
},
..
}),
ref
args
,
..
}
if
Some
(
def_id
)
==
self
.bcx
.tcx
()
.lang_items
.box_free_fn
()
=>
{
// box_free(x) shares with `drop x` the property that it
// is not guaranteed to be statically dominated by the
// definition of x, so x must always be in an alloca.
if
let
mir
::
Operand
::
Consume
(
ref
lvalue
)
=
args
[
0
]
{
self
.visit_lvalue
(
lvalue
,
LvalueContext
::
Drop
);
}
}
_
=>
{}
}
self
.super_terminator_kind
(
block
,
kind
);
}
fn
visit_lvalue
(
&
mut
self
,
lvalue
:
&
mir
::
Lvalue
<
'tcx
>
,
context
:
LvalueContext
)
{
...
...
@@ -117,9 +142,9 @@ fn visit_lvalue(&mut self,
// Allow uses of projections of immediate pair fields.
if
let
mir
::
Lvalue
::
Projection
(
ref
proj
)
=
*
lvalue
{
if
let
mir
::
Lvalue
::
Temp
(
temp
)
=
proj
.base
{
let
ty
=
self
.mir.
temp_decls
[
temp
]
.ty
;
let
ty
=
self
.bcx
.monomorphize
(
&
ty
);
if
self
.mir
.local_index
(
&
proj
.base
)
.is_some
()
{
let
ty
=
self
.mir
.
lvalue_ty
(
self
.bcx
.tcx
(),
&
proj
.base
)
;
let
ty
=
self
.bcx
.monomorphize
(
&
ty
.to_ty
(
self
.bcx
.tcx
())
);
if
common
::
type_is_imm_pair
(
self
.bcx
.ccx
(),
ty
)
{
if
let
mir
::
ProjectionElem
::
Field
(
..
)
=
proj
.elem
{
if
let
LvalueContext
::
Consume
=
context
{
...
...
@@ -130,34 +155,30 @@ fn visit_lvalue(&mut self,
}
}
match
*
lvalue
{
mir
::
Lvalue
::
Temp
(
temp
)
=>
{
match
context
{
LvalueContext
::
Call
=>
{
self
.mark_assigned
(
temp
.index
());
}
LvalueContext
::
Consume
=>
{
}
LvalueContext
::
Store
|
LvalueContext
::
Inspect
|
LvalueContext
::
Borrow
{
..
}
|
LvalueContext
::
Slice
{
..
}
|
LvalueContext
::
Projection
=>
{
self
.mark_as_lvalue
(
temp
.index
());
}
LvalueContext
::
Drop
=>
{
let
ty
=
self
.mir.temp_decls
[
index
as
usize
]
.ty
;
let
ty
=
self
.bcx
.monomorphize
(
&
ty
);
if
let
Some
(
index
)
=
self
.mir
.local_index
(
lvalue
)
{
match
context
{
LvalueContext
::
Call
=>
{
self
.mark_assigned
(
index
);
}
LvalueContext
::
Consume
=>
{
}
LvalueContext
::
Store
|
LvalueContext
::
Inspect
|
LvalueContext
::
Borrow
{
..
}
|
LvalueContext
::
Slice
{
..
}
|
LvalueContext
::
Projection
=>
{
self
.mark_as_lvalue
(
index
);
}
LvalueContext
::
Drop
=>
{
let
ty
=
self
.mir
.lvalue_ty
(
self
.bcx
.tcx
(),
lvalue
);
let
ty
=
self
.bcx
.monomorphize
(
&
ty
.to_ty
(
self
.bcx
.tcx
()));
// Only need the lvalue if we're actually dropping it.
if
glue
::
type_needs_drop
(
self
.bcx
.tcx
(),
ty
)
{
self
.mark_as_lvalue
(
index
as
usize
);
}
// Only need the lvalue if we're actually dropping it.
if
glue
::
type_needs_drop
(
self
.bcx
.tcx
(),
ty
)
{
self
.mark_as_lvalue
(
index
);
}
}
}
_
=>
{
}
}
// A deref projection only reads the pointer, never needs the lvalue.
...
...
src/librustc_trans/mir/block.rs
浏览文件 @
7279af86
...
...
@@ -32,7 +32,7 @@
use
rustc_data_structures
::
fnv
::
FnvHashMap
;
use
syntax
::
parse
::
token
;
use
super
::{
MirContext
,
Temp
Ref
};
use
super
::{
MirContext
,
Local
Ref
};
use
super
::
analyze
::
CleanupKind
;
use
super
::
constant
::
Const
;
use
super
::
lvalue
::{
LvalueRef
,
load_fat_ptr
};
...
...
@@ -186,9 +186,43 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
}
mir
::
TerminatorKind
::
Return
=>
{
bcx
.with_block
(|
bcx
|
{
self
.fcx
.build_return_block
(
bcx
,
debug_loc
);
})
let
ret
=
bcx
.fcx
()
.fn_ty.ret
;
if
ret
.is_ignore
()
||
ret
.is_indirect
()
{
bcx
.ret_void
();
return
;
}
let
llval
=
if
let
Some
(
cast_ty
)
=
ret
.cast
{
let
index
=
mir
.local_index
(
&
mir
::
Lvalue
::
ReturnPointer
)
.unwrap
();
let
op
=
match
self
.locals
[
index
]
{
LocalRef
::
Operand
(
Some
(
op
))
=>
op
,
LocalRef
::
Operand
(
None
)
=>
bug!
(
"use of return before def"
),
LocalRef
::
Lvalue
(
tr_lvalue
)
=>
{
OperandRef
{
val
:
Ref
(
tr_lvalue
.llval
),
ty
:
tr_lvalue
.ty
.to_ty
(
bcx
.tcx
())
}
}
};
let
llslot
=
match
op
.val
{
Immediate
(
_
)
|
Pair
(
..
)
=>
{
let
llscratch
=
build
::
AllocaFcx
(
bcx
.fcx
(),
ret
.original_ty
,
"ret"
);
self
.store_operand
(
&
bcx
,
llscratch
,
op
);
llscratch
}
Ref
(
llval
)
=>
llval
};
let
load
=
bcx
.load
(
bcx
.pointercast
(
llslot
,
cast_ty
.ptr_to
()));
let
llalign
=
llalign_of_min
(
bcx
.ccx
(),
ret
.ty
);
unsafe
{
llvm
::
LLVMSetAlignment
(
load
,
llalign
);
}
load
}
else
{
let
op
=
self
.trans_consume
(
&
bcx
,
&
mir
::
Lvalue
::
ReturnPointer
);
op
.pack_if_pair
(
&
bcx
)
.immediate
()
};
bcx
.ret
(
llval
);
}
mir
::
TerminatorKind
::
Unreachable
=>
{
...
...
@@ -537,7 +571,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
fn
trans_argument
(
&
mut
self
,
bcx
:
&
BlockAndBuilder
<
'bcx
,
'tcx
>
,
mut
op
:
OperandRef
<
'tcx
>
,
op
:
OperandRef
<
'tcx
>
,
llargs
:
&
mut
Vec
<
ValueRef
>
,
fn_ty
:
&
FnType
,
next_idx
:
&
mut
usize
,
...
...
@@ -565,8 +599,6 @@ fn trans_argument(&mut self,
self
.trans_argument
(
bcx
,
imm_op
(
meta
),
llargs
,
fn_ty
,
next_idx
,
callee
);
return
;
}
op
=
op
.pack_if_pair
(
bcx
);
}
let
arg
=
&
fn_ty
.args
[
*
next_idx
];
...
...
@@ -583,14 +615,16 @@ fn trans_argument(&mut self,
// Force by-ref if we have to load through a cast pointer.
let
(
mut
llval
,
by_ref
)
=
match
op
.val
{
Immediate
(
llval
)
if
arg
.is_indirect
()
||
arg
.cast
.is_some
()
=>
{
let
llscratch
=
build
::
AllocaFcx
(
bcx
.fcx
(),
arg
.original_ty
,
"arg"
);
bcx
.store
(
llval
,
llscratch
);
(
llscratch
,
true
)
Immediate
(
_
)
|
Pair
(
..
)
=>
{
if
arg
.is_indirect
()
||
arg
.cast
.is_some
()
{
let
llscratch
=
build
::
AllocaFcx
(
bcx
.fcx
(),
arg
.original_ty
,
"arg"
);
self
.store_operand
(
bcx
,
llscratch
,
op
);
(
llscratch
,
true
)
}
else
{
(
op
.pack_if_pair
(
bcx
)
.immediate
(),
false
)
}
}
Immediate
(
llval
)
=>
(
llval
,
false
),
Ref
(
llval
)
=>
(
llval
,
true
),
Pair
(
..
)
=>
bug!
(
"pairs handled above"
)
Ref
(
llval
)
=>
(
llval
,
true
)
};
if
by_ref
&&
!
arg
.is_indirect
()
{
...
...
@@ -776,40 +810,39 @@ fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
if
fn_ret_ty
.is_ignore
()
{
return
ReturnDest
::
Nothing
;
}
let
dest
=
match
*
dest
{
mir
::
Lvalue
::
Temp
(
idx
)
=>
{
let
ret_ty
=
self
.lvalue_ty
(
dest
);
match
self
.temps
[
idx
]
{
TempRef
::
Lvalue
(
dest
)
=>
dest
,
TempRef
::
Operand
(
None
)
=>
{
// Handle temporary lvalues, specifically Operand ones, as
// they don't have allocas
return
if
fn_ret_ty
.is_indirect
()
{
// Odd, but possible, case, we have an operand temporary,
// but the calling convention has an indirect return.
let
tmp
=
bcx
.with_block
(|
bcx
|
{
base
::
alloc_ty
(
bcx
,
ret_ty
,
"tmp_ret"
)
});
llargs
.push
(
tmp
);
ReturnDest
::
IndirectOperand
(
tmp
,
idx
)
}
else
if
is_intrinsic
{
// Currently, intrinsics always need a location to store
// the result. so we create a temporary alloca for the
// result
let
tmp
=
bcx
.with_block
(|
bcx
|
{
base
::
alloc_ty
(
bcx
,
ret_ty
,
"tmp_ret"
)
});
ReturnDest
::
IndirectOperand
(
tmp
,
idx
)
}
else
{
ReturnDest
::
DirectOperand
(
idx
)
};
}
TempRef
::
Operand
(
Some
(
_
))
=>
{
bug!
(
"lvalue temp already assigned to"
);
}
let
dest
=
if
let
Some
(
index
)
=
self
.mir
.local_index
(
dest
)
{
let
ret_ty
=
self
.lvalue_ty
(
dest
);
match
self
.locals
[
index
]
{
LocalRef
::
Lvalue
(
dest
)
=>
dest
,
LocalRef
::
Operand
(
None
)
=>
{
// Handle temporary lvalues, specifically Operand ones, as
// they don't have allocas
return
if
fn_ret_ty
.is_indirect
()
{
// Odd, but possible, case, we have an operand temporary,
// but the calling convention has an indirect return.
let
tmp
=
bcx
.with_block
(|
bcx
|
{
base
::
alloc_ty
(
bcx
,
ret_ty
,
"tmp_ret"
)
});
llargs
.push
(
tmp
);
ReturnDest
::
IndirectOperand
(
tmp
,
index
)
}
else
if
is_intrinsic
{
// Currently, intrinsics always need a location to store
// the result. so we create a temporary alloca for the
// result
let
tmp
=
bcx
.with_block
(|
bcx
|
{
base
::
alloc_ty
(
bcx
,
ret_ty
,
"tmp_ret"
)
});
ReturnDest
::
IndirectOperand
(
tmp
,
index
)
}
else
{
ReturnDest
::
DirectOperand
(
index
)
};
}
LocalRef
::
Operand
(
Some
(
_
))
=>
{
bug!
(
"lvalue local already assigned to"
);
}
}
_
=>
self
.trans_lvalue
(
bcx
,
dest
)
}
else
{
self
.trans_lvalue
(
bcx
,
dest
)
};
if
fn_ret_ty
.is_indirect
()
{
llargs
.push
(
dest
.llval
);
...
...
@@ -853,11 +886,11 @@ fn store_return(&mut self,
match
dest
{
Nothing
=>
(),
Store
(
dst
)
=>
ret_ty
.store
(
bcx
,
op
.immediate
(),
dst
),
IndirectOperand
(
tmp
,
i
d
x
)
=>
{
IndirectOperand
(
tmp
,
i
nde
x
)
=>
{
let
op
=
self
.trans_load
(
bcx
,
tmp
,
op
.ty
);
self
.
temps
[
idx
]
=
Temp
Ref
::
Operand
(
Some
(
op
));
self
.
locals
[
index
]
=
Local
Ref
::
Operand
(
Some
(
op
));
}
DirectOperand
(
i
d
x
)
=>
{
DirectOperand
(
i
nde
x
)
=>
{
// If there is a cast, we have to store and reload.
let
op
=
if
ret_ty
.cast
.is_some
()
{
let
tmp
=
bcx
.with_block
(|
bcx
|
{
...
...
@@ -868,7 +901,7 @@ fn store_return(&mut self,
}
else
{
op
.unpack_if_pair
(
bcx
)
};
self
.
temps
[
idx
]
=
Temp
Ref
::
Operand
(
Some
(
op
));
self
.
locals
[
index
]
=
Local
Ref
::
Operand
(
Some
(
op
));
}
}
}
...
...
@@ -879,8 +912,8 @@ enum ReturnDest {
Nothing
,
// Store the return value to the pointer
Store
(
ValueRef
),
// Stores an indirect return value to an operand
temporary
lvalue
IndirectOperand
(
ValueRef
,
mir
::
Temp
),
// Stores a direct return value to an operand
temporary
lvalue
DirectOperand
(
mir
::
Temp
)
// Stores an indirect return value to an operand
local
lvalue
IndirectOperand
(
ValueRef
,
mir
::
Local
),
// Stores a direct return value to an operand
local
lvalue
DirectOperand
(
mir
::
Local
)
}
src/librustc_trans/mir/constant.rs
浏览文件 @
7279af86
...
...
@@ -203,17 +203,8 @@ struct MirConstContext<'a, 'tcx: 'a> {
/// Type parameters for const fn and associated constants.
substs
:
&
'tcx
Substs
<
'tcx
>
,
/// Arguments passed to a const fn.
args
:
IndexVec
<
mir
::
Arg
,
Const
<
'tcx
>>
,
/// Variable values - specifically, argument bindings of a const fn.
vars
:
IndexVec
<
mir
::
Var
,
Option
<
Const
<
'tcx
>>>
,
/// Temp values.
temps
:
IndexVec
<
mir
::
Temp
,
Option
<
Const
<
'tcx
>>>
,
/// Value assigned to Return, which is the resulting constant.
return_value
:
Option
<
Const
<
'tcx
>>
/// Values of locals in a constant or const fn.
locals
:
IndexVec
<
mir
::
Local
,
Option
<
Const
<
'tcx
>>>
}
...
...
@@ -223,15 +214,17 @@ fn new(ccx: &'a CrateContext<'a, 'tcx>,
substs
:
&
'tcx
Substs
<
'tcx
>
,
args
:
IndexVec
<
mir
::
Arg
,
Const
<
'tcx
>>
)
->
MirConstContext
<
'a
,
'tcx
>
{
MirConstContext
{
let
mut
context
=
MirConstContext
{
ccx
:
ccx
,
mir
:
mir
,
substs
:
substs
,
args
:
args
,
vars
:
IndexVec
::
from_elem
(
None
,
&
mir
.var_decls
),
temps
:
IndexVec
::
from_elem
(
None
,
&
mir
.temp_decls
),
return_value
:
None
locals
:
(
0
..
mir
.count_locals
())
.map
(|
_
|
None
)
.collect
(),
};
for
(
i
,
arg
)
in
args
.into_iter
()
.enumerate
()
{
let
index
=
mir
.local_index
(
&
mir
::
Lvalue
::
Arg
(
mir
::
Arg
::
new
(
i
)))
.unwrap
();
context
.locals
[
index
]
=
Some
(
arg
);
}
context
}
fn
trans_def
(
ccx
:
&
'a
CrateContext
<
'a
,
'tcx
>
,
...
...
@@ -302,9 +295,10 @@ fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalFailure> {
mir
::
TerminatorKind
::
Goto
{
target
}
=>
target
,
mir
::
TerminatorKind
::
Return
=>
{
failure
?
;
return
Ok
(
self
.return_value
.unwrap_or_else
(||
{
let
index
=
self
.mir
.local_index
(
&
mir
::
Lvalue
::
ReturnPointer
)
.unwrap
();
return
Ok
(
self
.locals
[
index
]
.unwrap_or_else
(||
{
span_bug!
(
span
,
"no returned value in constant"
);
}))
}))
;
}
mir
::
TerminatorKind
::
Assert
{
ref
cond
,
expected
,
ref
msg
,
target
,
..
}
=>
{
...
...
@@ -366,30 +360,28 @@ fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalFailure> {
}
fn
store
(
&
mut
self
,
dest
:
&
mir
::
Lvalue
<
'tcx
>
,
value
:
Const
<
'tcx
>
,
span
:
Span
)
{
let
dest
=
match
*
dest
{
mir
::
Lvalue
::
Var
(
var
)
=>
&
mut
self
.vars
[
var
],
mir
::
Lvalue
::
Temp
(
temp
)
=>
&
mut
self
.temps
[
temp
],
mir
::
Lvalue
::
ReturnPointer
=>
&
mut
self
.return_value
,
_
=>
span_bug!
(
span
,
"assignment to {:?} in constant"
,
dest
)
};
*
dest
=
Some
(
value
);
if
let
Some
(
index
)
=
self
.mir
.local_index
(
dest
)
{
self
.locals
[
index
]
=
Some
(
value
);
}
else
{
span_bug!
(
span
,
"assignment to {:?} in constant"
,
dest
);
}
}
fn
const_lvalue
(
&
self
,
lvalue
:
&
mir
::
Lvalue
<
'tcx
>
,
span
:
Span
)
->
Result
<
ConstLvalue
<
'tcx
>
,
ConstEvalFailure
>
{
let
tcx
=
self
.ccx
.tcx
();
if
let
Some
(
index
)
=
self
.mir
.local_index
(
lvalue
)
{
return
Ok
(
self
.locals
[
index
]
.unwrap_or_else
(||
{
span_bug!
(
span
,
"{:?} not initialized"
,
lvalue
)
})
.as_lvalue
());
}
let
lvalue
=
match
*
lvalue
{
mir
::
Lvalue
::
Var
(
var
)
=>
{
self
.vars
[
var
]
.unwrap_or_else
(||
{
span_bug!
(
span
,
"{:?} not initialized"
,
var
)
})
.as_lvalue
()
}
mir
::
Lvalue
::
Temp
(
temp
)
=>
{
self
.temps
[
temp
]
.unwrap_or_else
(||
{
span_bug!
(
span
,
"{:?} not initialized"
,
temp
)
})
.as_lvalue
()
}
mir
::
Lvalue
::
Arg
(
arg
)
=>
self
.args
[
arg
]
.as_lvalue
(),
mir
::
Lvalue
::
Var
(
_
)
|
mir
::
Lvalue
::
Temp
(
_
)
|
mir
::
Lvalue
::
Arg
(
_
)
|
mir
::
Lvalue
::
ReturnPointer
=>
bug!
(),
// handled above
mir
::
Lvalue
::
Static
(
def_id
)
=>
{
ConstLvalue
{
base
:
Base
::
Static
(
consts
::
get_static
(
self
.ccx
,
def_id
)
.val
),
...
...
@@ -397,9 +389,6 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
ty
:
self
.mir
.lvalue_ty
(
tcx
,
lvalue
)
.to_ty
(
tcx
)
}
}
mir
::
Lvalue
::
ReturnPointer
=>
{
span_bug!
(
span
,
"accessing Lvalue::ReturnPointer in constant"
)
}
mir
::
Lvalue
::
Projection
(
ref
projection
)
=>
{
let
tr_base
=
self
.const_lvalue
(
&
projection
.base
,
span
)
?
;
let
projected_ty
=
LvalueTy
::
Ty
{
ty
:
tr_base
.ty
}
...
...
src/librustc_trans/mir/lvalue.rs
浏览文件 @
7279af86
...
...
@@ -26,7 +26,7 @@
use
std
::
ptr
;
use
super
::{
MirContext
,
Temp
Ref
};
use
super
::{
MirContext
,
Local
Ref
};
use
super
::
operand
::
OperandValue
;
#[derive(Copy,
Clone,
Debug)]
...
...
@@ -88,40 +88,30 @@ pub fn trans_lvalue(&mut self,
->
LvalueRef
<
'tcx
>
{
debug!
(
"trans_lvalue(lvalue={:?})"
,
lvalue
);
let
fcx
=
bcx
.fcx
();
let
ccx
=
bcx
.ccx
();
let
tcx
=
bcx
.tcx
();
if
let
Some
(
index
)
=
self
.mir
.local_index
(
lvalue
)
{
match
self
.locals
[
index
]
{
LocalRef
::
Lvalue
(
lvalue
)
=>
{
return
lvalue
;
}
LocalRef
::
Operand
(
..
)
=>
{
bug!
(
"using operand local {:?} as lvalue"
,
lvalue
);
}
}
}
let
result
=
match
*
lvalue
{
mir
::
Lvalue
::
Var
(
var
)
=>
self
.vars
[
var
],
mir
::
Lvalue
::
Temp
(
temp
)
=>
match
self
.temps
[
temp
]
{
TempRef
::
Lvalue
(
lvalue
)
=>
lvalue
,
TempRef
::
Operand
(
..
)
=>
bug!
(
"using operand temp {:?} as lvalue"
,
lvalue
),
},
mir
::
Lvalue
::
Arg
(
arg
)
=>
self
.args
[
arg
],
mir
::
Lvalue
::
Var
(
_
)
|
mir
::
Lvalue
::
Temp
(
_
)
|
mir
::
Lvalue
::
Arg
(
_
)
|
mir
::
Lvalue
::
ReturnPointer
=>
bug!
(),
// handled above
mir
::
Lvalue
::
Static
(
def_id
)
=>
{
let
const_ty
=
self
.lvalue_ty
(
lvalue
);
LvalueRef
::
new_sized
(
consts
::
get_static
(
ccx
,
def_id
)
.val
,
LvalueTy
::
from_ty
(
const_ty
))
},
mir
::
Lvalue
::
ReturnPointer
=>
{
let
llval
=
if
!
fcx
.fn_ty.ret
.is_ignore
()
{
bcx
.with_block
(|
bcx
|
{
fcx
.get_ret_slot
(
bcx
,
""
)
})
}
else
{
// This is a void return; that is, there’s no place to store the value and
// there cannot really be one (or storing into it doesn’t make sense, anyway).
// Ergo, we return an undef ValueRef, so we do not have to special-case every
// place using lvalues, and could use it the same way you use a regular
// ReturnPointer LValue (i.e. store into it, load from it etc).
C_undef
(
fcx
.fn_ty.ret.original_ty
.ptr_to
())
};
let
fn_return_ty
=
bcx
.monomorphize
(
&
self
.mir.return_ty
);
let
return_ty
=
fn_return_ty
.unwrap
();
LvalueRef
::
new_sized
(
llval
,
LvalueTy
::
from_ty
(
return_ty
))
},
mir
::
Lvalue
::
Projection
(
box
mir
::
Projection
{
ref
base
,
elem
:
mir
::
ProjectionElem
::
Deref
...
...
@@ -240,44 +230,41 @@ pub fn trans_lvalue(&mut self,
}
// Perform an action using the given Lvalue.
// If the Lvalue is an empty
Temp
Ref::Operand, then a temporary stack slot
// If the Lvalue is an empty
Local
Ref::Operand, then a temporary stack slot
// is created first, then used as an operand to update the Lvalue.
pub
fn
with_lvalue_ref
<
F
,
U
>
(
&
mut
self
,
bcx
:
&
BlockAndBuilder
<
'bcx
,
'tcx
>
,
lvalue
:
&
mir
::
Lvalue
<
'tcx
>
,
f
:
F
)
->
U
where
F
:
FnOnce
(
&
mut
Self
,
LvalueRef
<
'tcx
>
)
->
U
{
match
*
lvalue
{
mir
::
Lvalue
::
Temp
(
temp
)
=>
{
match
self
.temps
[
temp
]
{
TempRef
::
Lvalue
(
lvalue
)
=>
f
(
self
,
lvalue
),
TempRef
::
Operand
(
None
)
=>
{
let
lvalue_ty
=
self
.lvalue_ty
(
lvalue
);
let
lvalue
=
LvalueRef
::
alloca
(
bcx
,
lvalue_ty
,
"lvalue_temp"
);
let
ret
=
f
(
self
,
lvalue
);
let
op
=
self
.trans_load
(
bcx
,
lvalue
.llval
,
lvalue_ty
);
self
.temps
[
temp
]
=
TempRef
::
Operand
(
Some
(
op
));
ret
}
TempRef
::
Operand
(
Some
(
_
))
=>
{
// See comments in TempRef::new_operand as to why
// we always have Some in a ZST TempRef::Operand.
let
ty
=
self
.lvalue_ty
(
lvalue
);
if
common
::
type_is_zero_size
(
bcx
.ccx
(),
ty
)
{
// Pass an undef pointer as no stores can actually occur.
let
llptr
=
C_undef
(
type_of
(
bcx
.ccx
(),
ty
)
.ptr_to
());
f
(
self
,
LvalueRef
::
new_sized
(
llptr
,
LvalueTy
::
from_ty
(
ty
)))
}
else
{
bug!
(
"Lvalue temp already set"
);
}
if
let
Some
(
index
)
=
self
.mir
.local_index
(
lvalue
)
{
match
self
.locals
[
index
]
{
LocalRef
::
Lvalue
(
lvalue
)
=>
f
(
self
,
lvalue
),
LocalRef
::
Operand
(
None
)
=>
{
let
lvalue_ty
=
self
.lvalue_ty
(
lvalue
);
let
lvalue
=
LvalueRef
::
alloca
(
bcx
,
lvalue_ty
,
"lvalue_temp"
);
let
ret
=
f
(
self
,
lvalue
);
let
op
=
self
.trans_load
(
bcx
,
lvalue
.llval
,
lvalue_ty
);
self
.locals
[
index
]
=
LocalRef
::
Operand
(
Some
(
op
));
ret
}
LocalRef
::
Operand
(
Some
(
_
))
=>
{
// See comments in LocalRef::new_operand as to why
// we always have Some in a ZST LocalRef::Operand.
let
ty
=
self
.lvalue_ty
(
lvalue
);
if
common
::
type_is_zero_size
(
bcx
.ccx
(),
ty
)
{
// Pass an undef pointer as no stores can actually occur.
let
llptr
=
C_undef
(
type_of
(
bcx
.ccx
(),
ty
)
.ptr_to
());
f
(
self
,
LvalueRef
::
new_sized
(
llptr
,
LvalueTy
::
from_ty
(
ty
)))
}
else
{
bug!
(
"Lvalue local already set"
);
}
}
}
_
=>
{
let
lvalue
=
self
.trans_lvalue
(
bcx
,
lvalue
);
f
(
self
,
lvalue
)
}
}
else
{
let
lvalue
=
self
.trans_lvalue
(
bcx
,
lvalue
);
f
(
self
,
lvalue
)
}
}
...
...
src/librustc_trans/mir/mod.rs
浏览文件 @
7279af86
...
...
@@ -84,16 +84,13 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
/// Cached unreachable block
unreachable_block
:
Option
<
Block
<
'bcx
,
'tcx
>>
,
/// An LLVM alloca for each MIR `VarDecl`
vars
:
IndexVec
<
mir
::
Var
,
LvalueRef
<
'tcx
>>
,
/// The location where each MIR `TempDecl` is stored. This is
/// The location where each MIR arg/var/tmp/ret is stored. This is
/// usually an `LvalueRef` representing an alloca, but not always:
/// sometimes we can skip the alloca and just store the value
/// directly using an `OperandRef`, which makes for tighter LLVM
/// IR. The conditions for using an `OperandRef` are as follows:
///
/// - the type of the
temporary
must be judged "immediate" by `type_is_immediate`
/// - the type of the
local
must be judged "immediate" by `type_is_immediate`
/// - the operand must never be referenced indirectly
/// - we should not take its address using the `&` operator
/// - nor should it appear in an lvalue path like `tmp.a`
...
...
@@ -102,12 +99,7 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
///
/// Avoiding allocs can also be important for certain intrinsics,
/// notably `expect`.
temps
:
IndexVec
<
mir
::
Temp
,
TempRef
<
'tcx
>>
,
/// The arguments to the function; as args are lvalues, these are
/// always indirect, though we try to avoid creating an alloca
/// when we can (and just reuse the pointer the caller provided).
args
:
IndexVec
<
mir
::
Arg
,
LvalueRef
<
'tcx
>>
,
locals
:
IndexVec
<
mir
::
Local
,
LocalRef
<
'tcx
>>
,
/// Debug information for MIR scopes.
scopes
:
IndexVec
<
mir
::
VisibilityScope
,
DIScope
>
...
...
@@ -119,14 +111,14 @@ pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc {
}
}
enum
Temp
Ref
<
'tcx
>
{
enum
Local
Ref
<
'tcx
>
{
Lvalue
(
LvalueRef
<
'tcx
>
),
Operand
(
Option
<
OperandRef
<
'tcx
>>
),
}
impl
<
'tcx
>
Temp
Ref
<
'tcx
>
{
impl
<
'tcx
>
Local
Ref
<
'tcx
>
{
fn
new_operand
<
'bcx
>
(
ccx
:
&
CrateContext
<
'bcx
,
'tcx
>
,
ty
:
ty
::
Ty
<
'tcx
>
)
->
Temp
Ref
<
'tcx
>
{
ty
:
ty
::
Ty
<
'tcx
>
)
->
Local
Ref
<
'tcx
>
{
if
common
::
type_is_zero_size
(
ccx
,
ty
)
{
// Zero-size temporaries aren't always initialized, which
// doesn't matter because they don't contain data, but
...
...
@@ -142,9 +134,9 @@ fn new_operand<'bcx>(ccx: &CrateContext<'bcx, 'tcx>,
val
:
val
,
ty
:
ty
};
Temp
Ref
::
Operand
(
Some
(
op
))
Local
Ref
::
Operand
(
Some
(
op
))
}
else
{
Temp
Ref
::
Operand
(
None
)
Local
Ref
::
Operand
(
None
)
}
}
}
...
...
@@ -157,8 +149,8 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
// Analyze the temps to determine which must be lvalues
// FIXME
let
(
lvalue_
temp
s
,
cleanup_kinds
)
=
bcx
.with_block
(|
bcx
|
{
(
analyze
::
lvalue_
temp
s
(
bcx
,
&
mir
),
let
(
lvalue_
local
s
,
cleanup_kinds
)
=
bcx
.with_block
(|
bcx
|
{
(
analyze
::
lvalue_
local
s
(
bcx
,
&
mir
),
analyze
::
cleanup_kinds
(
bcx
,
&
mir
))
});
...
...
@@ -166,37 +158,49 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
let
scopes
=
debuginfo
::
create_mir_scopes
(
fcx
);
// Allocate variable and temp allocas
let
args
=
arg_value_refs
(
&
bcx
,
&
mir
,
&
scopes
);
let
vars
=
mir
.var_decls
.iter
()
.map
(|
decl
|
(
bcx
.monomorphize
(
&
decl
.ty
),
decl
))
.map
(|(
mty
,
decl
)|
{
let
lvalue
=
LvalueRef
::
alloca
(
&
bcx
,
mty
,
&
decl
.name
.as_str
());
let
scope
=
scopes
[
decl
.source_info.scope
];
if
!
scope
.is_null
()
&&
bcx
.sess
()
.opts.debuginfo
==
FullDebugInfo
{
bcx
.with_block
(|
bcx
|
{
declare_local
(
bcx
,
decl
.name
,
mty
,
scope
,
VariableAccess
::
DirectVariable
{
alloca
:
lvalue
.llval
},
VariableKind
::
LocalVariable
,
decl
.source_info.span
);
});
}
let
locals
=
{
let
args
=
arg_local_refs
(
&
bcx
,
&
mir
,
&
scopes
,
&
lvalue_locals
);
let
vars
=
mir
.var_decls
.iter
()
.enumerate
()
.map
(|(
i
,
decl
)|
{
let
ty
=
bcx
.monomorphize
(
&
decl
.ty
);
let
scope
=
scopes
[
decl
.source_info.scope
];
let
dbg
=
!
scope
.is_null
()
&&
bcx
.sess
()
.opts.debuginfo
==
FullDebugInfo
;
let
local
=
mir
.local_index
(
&
mir
::
Lvalue
::
Var
(
mir
::
Var
::
new
(
i
)))
.unwrap
();
if
!
lvalue_locals
.contains
(
local
.index
())
&&
!
dbg
{
return
LocalRef
::
new_operand
(
bcx
.ccx
(),
ty
);
}
lvalue
})
.collect
();
let
temps
=
mir
.temp_decls
.iter
()
.map
(|
decl
|
bcx
.monomorphize
(
&
decl
.ty
))
.enumerate
()
.map
(|(
i
,
mty
)|
if
lvalue_temps
.contains
(
i
)
{
TempRef
::
Lvalue
(
LvalueRef
::
alloca
(
&
bcx
,
mty
,
&
format!
(
"temp{:?}"
,
i
)))
}
else
{
// If this is an immediate temp, we do not create an
// alloca in advance. Instead we wait until we see the
// definition and update the operand there.
TempRef
::
new_operand
(
bcx
.ccx
(),
mty
)
})
.collect
();
let
lvalue
=
LvalueRef
::
alloca
(
&
bcx
,
ty
,
&
decl
.name
.as_str
());
if
dbg
{
bcx
.with_block
(|
bcx
|
{
declare_local
(
bcx
,
decl
.name
,
ty
,
scope
,
VariableAccess
::
DirectVariable
{
alloca
:
lvalue
.llval
},
VariableKind
::
LocalVariable
,
decl
.source_info.span
);
});
}
LocalRef
::
Lvalue
(
lvalue
)
});
let
locals
=
mir
.temp_decls
.iter
()
.enumerate
()
.map
(|(
i
,
decl
)|
{
(
mir
::
Lvalue
::
Temp
(
mir
::
Temp
::
new
(
i
)),
decl
.ty
)
})
.chain
(
mir
.return_ty
.maybe_converging
()
.map
(|
ty
|
(
mir
::
Lvalue
::
ReturnPointer
,
ty
)));
args
.into_iter
()
.chain
(
vars
)
.chain
(
locals
.map
(|(
lvalue
,
ty
)|
{
let
ty
=
bcx
.monomorphize
(
&
ty
);
let
local
=
mir
.local_index
(
&
lvalue
)
.unwrap
();
if
lvalue
==
mir
::
Lvalue
::
ReturnPointer
&&
fcx
.fn_ty.ret
.is_indirect
()
{
let
llretptr
=
llvm
::
get_param
(
fcx
.llfn
,
0
);
LocalRef
::
Lvalue
(
LvalueRef
::
new_sized
(
llretptr
,
LvalueTy
::
from_ty
(
ty
)))
}
else
if
lvalue_locals
.contains
(
local
.index
())
{
LocalRef
::
Lvalue
(
LvalueRef
::
alloca
(
&
bcx
,
ty
,
&
format!
(
"{:?}"
,
lvalue
)))
}
else
{
// If this is an immediate local, we do not create an
// alloca in advance. Instead we wait until we see the
// definition and update the operand there.
LocalRef
::
new_operand
(
bcx
.ccx
(),
ty
)
}
}))
.collect
()
};
// Allocate a `Block` for every basic block
let
block_bcxs
:
IndexVec
<
mir
::
BasicBlock
,
Block
<
'blk
,
'tcx
>>
=
...
...
@@ -225,9 +229,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
unreachable_block
:
None
,
cleanup_kinds
:
cleanup_kinds
,
landing_pads
:
IndexVec
::
from_elem
(
None
,
mir
.basic_blocks
()),
vars
:
vars
,
temps
:
temps
,
args
:
args
,
locals
:
locals
,
scopes
:
scopes
};
...
...
@@ -266,10 +268,11 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
/// Produce, for each argument, a `ValueRef` pointing at the
/// argument's value. As arguments are lvalues, these are always
/// indirect.
fn
arg_
value
_refs
<
'bcx
,
'tcx
>
(
bcx
:
&
BlockAndBuilder
<
'bcx
,
'tcx
>
,
fn
arg_
local
_refs
<
'bcx
,
'tcx
>
(
bcx
:
&
BlockAndBuilder
<
'bcx
,
'tcx
>
,
mir
:
&
mir
::
Mir
<
'tcx
>
,
scopes
:
&
IndexVec
<
mir
::
VisibilityScope
,
DIScope
>
)
->
IndexVec
<
mir
::
Arg
,
LvalueRef
<
'tcx
>>
{
scopes
:
&
IndexVec
<
mir
::
VisibilityScope
,
DIScope
>
,
lvalue_locals
:
&
BitVector
)
->
Vec
<
LocalRef
<
'tcx
>>
{
let
fcx
=
bcx
.fcx
();
let
tcx
=
bcx
.tcx
();
let
mut
idx
=
0
;
...
...
@@ -285,6 +288,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
mir
.arg_decls
.iter
()
.enumerate
()
.map
(|(
arg_index
,
arg_decl
)|
{
let
arg_ty
=
bcx
.monomorphize
(
&
arg_decl
.ty
);
let
local
=
mir
.local_index
(
&
mir
::
Lvalue
::
Arg
(
mir
::
Arg
::
new
(
arg_index
)))
.unwrap
();
if
arg_decl
.spread
{
// This argument (e.g. the last argument in the "rust-call" ABI)
// is a tuple that was spread at the ABI level and now we have
...
...
@@ -305,8 +309,8 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
let
arg
=
&
fcx
.fn_ty.args
[
idx
];
idx
+=
1
;
if
common
::
type_is_fat_ptr
(
tcx
,
tupled_arg_ty
)
{
// We pass fat pointers as two words, but inside the tuple
// they are the two sub-fields of a single aggregate field.
// We pass fat pointers as two words, but inside the tuple
// they are the two sub-fields of a single aggregate field.
let
meta
=
&
fcx
.fn_ty.args
[
idx
];
idx
+=
1
;
arg
.store_fn_arg
(
bcx
,
&
mut
llarg_idx
,
get_dataptr
(
bcx
,
dst
));
...
...
@@ -335,7 +339,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
bcx
.fcx
()
.span
.unwrap_or
(
DUMMY_SP
));
}));
}
return
L
valueRef
::
new_sized
(
lltemp
,
LvalueTy
::
from_ty
(
arg_ty
));
return
L
ocalRef
::
Lvalue
(
LvalueRef
::
new_sized
(
lltemp
,
LvalueTy
::
from_ty
(
arg_ty
)
));
}
let
arg
=
&
fcx
.fn_ty.args
[
idx
];
...
...
@@ -345,9 +349,42 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
// already put it in a temporary alloca and gave it up, unless
// we emit extra-debug-info, which requires local allocas :(.
// FIXME: lifetimes
if
arg
.pad
.is_some
()
{
llarg_idx
+=
1
;
}
let
llarg
=
llvm
::
get_param
(
fcx
.llfn
,
llarg_idx
as
c_uint
);
llarg_idx
+=
1
;
llarg
}
else
if
!
lvalue_locals
.contains
(
local
.index
())
&&
!
arg
.is_indirect
()
&&
arg
.cast
.is_none
()
&&
arg_scope
.is_none
()
{
if
arg
.is_ignore
()
{
return
LocalRef
::
new_operand
(
bcx
.ccx
(),
arg_ty
);
}
// We don't have to cast or keep the argument in the alloca.
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
// of putting everything in allocas just so we can use llvm.dbg.declare.
if
arg
.pad
.is_some
()
{
llarg_idx
+=
1
;
}
let
llarg
=
llvm
::
get_param
(
fcx
.llfn
,
llarg_idx
as
c_uint
);
llarg_idx
+=
1
;
let
val
=
if
common
::
type_is_fat_ptr
(
tcx
,
arg_ty
)
{
let
meta
=
&
fcx
.fn_ty.args
[
idx
];
idx
+=
1
;
assert_eq!
((
meta
.cast
,
meta
.pad
),
(
None
,
None
));
let
llmeta
=
llvm
::
get_param
(
fcx
.llfn
,
llarg_idx
as
c_uint
);
llarg_idx
+=
1
;
OperandValue
::
Pair
(
llarg
,
llmeta
)
}
else
{
OperandValue
::
Immediate
(
llarg
)
};
let
operand
=
OperandRef
{
val
:
val
,
ty
:
arg_ty
};
return
LocalRef
::
Operand
(
Some
(
operand
.unpack_if_pair
(
bcx
)));
}
else
{
let
lltemp
=
bcx
.with_block
(|
bcx
|
{
base
::
alloc_ty
(
bcx
,
arg_ty
,
&
format!
(
"arg{}"
,
arg_index
))
...
...
@@ -441,7 +478,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
bcx
.fcx
()
.span
.unwrap_or
(
DUMMY_SP
));
}
}));
L
valueRef
::
new_sized
(
llval
,
LvalueTy
::
from_ty
(
arg_ty
))
L
ocalRef
::
Lvalue
(
LvalueRef
::
new_sized
(
llval
,
LvalueTy
::
from_ty
(
arg_ty
)
))
})
.collect
()
}
...
...
src/librustc_trans/mir/operand.rs
浏览文件 @
7279af86
...
...
@@ -21,7 +21,7 @@
use
std
::
fmt
;
use
super
::{
MirContext
,
Temp
Ref
};
use
super
::{
MirContext
,
Local
Ref
};
/// The representation of a Rust value. The enum variant is in fact
/// uniquely determined by the value's type, but is kept as a
...
...
@@ -112,6 +112,8 @@ pub fn unpack_if_pair(mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>)
if
let
OperandValue
::
Immediate
(
llval
)
=
self
.val
{
// Deconstruct the immediate aggregate.
if
common
::
type_is_imm_pair
(
bcx
.ccx
(),
self
.ty
)
{
debug!
(
"Operand::unpack_if_pair: unpacking {:?}"
,
self
);
let
mut
a
=
bcx
.extract_value
(
llval
,
0
);
let
mut
b
=
bcx
.extract_value
(
llval
,
1
);
...
...
@@ -171,17 +173,17 @@ pub fn trans_consume(&mut self,
{
debug!
(
"trans_consume(lvalue={:?})"
,
lvalue
);
// watch out for
temporarie
s that do not have an
// watch out for
local
s that do not have an
// alloca; they are handled somewhat differently
if
let
&
mir
::
Lvalue
::
Temp
(
index
)
=
lvalue
{
match
self
.
temp
s
[
index
]
{
Temp
Ref
::
Operand
(
Some
(
o
))
=>
{
if
let
Some
(
index
)
=
self
.mir
.local_index
(
lvalue
)
{
match
self
.
local
s
[
index
]
{
Local
Ref
::
Operand
(
Some
(
o
))
=>
{
return
o
;
}
Temp
Ref
::
Operand
(
None
)
=>
{
Local
Ref
::
Operand
(
None
)
=>
{
bug!
(
"use of {:?} before def"
,
lvalue
);
}
Temp
Ref
::
Lvalue
(
..
)
=>
{
Local
Ref
::
Lvalue
(
..
)
=>
{
// use path below
}
}
...
...
@@ -189,9 +191,8 @@ pub fn trans_consume(&mut self,
// Moves out of pair fields are trivial.
if
let
&
mir
::
Lvalue
::
Projection
(
ref
proj
)
=
lvalue
{
if
let
mir
::
Lvalue
::
Temp
(
index
)
=
proj
.base
{
let
temp_ref
=
&
self
.temps
[
index
];
if
let
&
TempRef
::
Operand
(
Some
(
o
))
=
temp_ref
{
if
let
Some
(
index
)
=
self
.mir
.local_index
(
&
proj
.base
)
{
if
let
LocalRef
::
Operand
(
Some
(
o
))
=
self
.locals
[
index
]
{
match
(
o
.val
,
&
proj
.elem
)
{
(
OperandValue
::
Pair
(
a
,
b
),
&
mir
::
ProjectionElem
::
Field
(
ref
f
,
ty
))
=>
{
...
...
src/librustc_trans/mir/statement.rs
浏览文件 @
7279af86
...
...
@@ -13,7 +13,7 @@
use
common
::{
self
,
BlockAndBuilder
};
use
super
::
MirContext
;
use
super
::
Temp
Ref
;
use
super
::
Local
Ref
;
impl
<
'bcx
,
'tcx
>
MirContext
<
'bcx
,
'tcx
>
{
pub
fn
trans_statement
(
&
mut
self
,
...
...
@@ -27,37 +27,34 @@ pub fn trans_statement(&mut self,
debug_loc
.apply
(
bcx
.fcx
());
match
statement
.kind
{
mir
::
StatementKind
::
Assign
(
ref
lvalue
,
ref
rvalue
)
=>
{
match
*
lvalue
{
mir
::
Lvalue
::
Temp
(
index
)
=>
{
match
self
.temps
[
index
]
{
TempRef
::
Lvalue
(
tr_dest
)
=>
{
self
.trans_rvalue
(
bcx
,
tr_dest
,
rvalue
,
debug_loc
)
}
TempRef
::
Operand
(
None
)
=>
{
let
(
bcx
,
operand
)
=
self
.trans_rvalue_operand
(
bcx
,
rvalue
,
debug_loc
);
self
.temps
[
index
]
=
TempRef
::
Operand
(
Some
(
operand
));
bcx
}
TempRef
::
Operand
(
Some
(
_
))
=>
{
let
ty
=
self
.lvalue_ty
(
lvalue
);
if
let
Some
(
index
)
=
self
.mir
.local_index
(
lvalue
)
{
match
self
.locals
[
index
]
{
LocalRef
::
Lvalue
(
tr_dest
)
=>
{
self
.trans_rvalue
(
bcx
,
tr_dest
,
rvalue
,
debug_loc
)
}
LocalRef
::
Operand
(
None
)
=>
{
let
(
bcx
,
operand
)
=
self
.trans_rvalue_operand
(
bcx
,
rvalue
,
debug_loc
);
self
.locals
[
index
]
=
LocalRef
::
Operand
(
Some
(
operand
));
bcx
}
LocalRef
::
Operand
(
Some
(
_
))
=>
{
let
ty
=
self
.lvalue_ty
(
lvalue
);
if
!
common
::
type_is_zero_size
(
bcx
.ccx
(),
ty
)
{
span_bug!
(
statement
.source_info.span
,
"operand {:?} already assigned"
,
rvalue
);
}
else
{
// If the type is zero-sized, it's already been set here,
// but we still need to make sure we translate the operand
self
.trans_rvalue_operand
(
bcx
,
rvalue
,
debug_loc
)
.0
}
if
!
common
::
type_is_zero_size
(
bcx
.ccx
(),
ty
)
{
span_bug!
(
statement
.source_info.span
,
"operand {:?} already assigned"
,
rvalue
);
}
else
{
// If the type is zero-sized, it's already been set here,
// but we still need to make sure we translate the operand
self
.trans_rvalue_operand
(
bcx
,
rvalue
,
debug_loc
)
.0
}
}
}
_
=>
{
let
tr_dest
=
self
.trans_lvalue
(
&
bcx
,
lvalue
);
self
.trans_rvalue
(
bcx
,
tr_dest
,
rvalue
,
debug_loc
)
}
}
else
{
let
tr_dest
=
self
.trans_lvalue
(
&
bcx
,
lvalue
);
self
.trans_rvalue
(
bcx
,
tr_dest
,
rvalue
,
debug_loc
)
}
}
}
...
...
src/test/codegen/loads.rs
浏览文件 @
7279af86
...
...
@@ -11,6 +11,7 @@
// compile-flags: -C no-prepopulate-passes
#![crate_type
=
"lib"
]
#![feature(rustc_attrs)]
pub
struct
Bytes
{
a
:
u8
,
...
...
@@ -21,6 +22,7 @@ pub struct Bytes {
// CHECK-LABEL: @borrow
#[no_mangle]
#[rustc_no_mir]
// FIXME #27840 MIR has different codegen.
pub
fn
borrow
(
x
:
&
i32
)
->
&
i32
{
// CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull
x
...
...
@@ -28,6 +30,7 @@ pub fn borrow(x: &i32) -> &i32 {
// CHECK-LABEL: @_box
#[no_mangle]
#[rustc_no_mir]
// FIXME #27840 MIR has different codegen.
pub
fn
_
box
(
x
:
Box
<
i32
>
)
->
i32
{
// CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull
*
x
...
...
src/test/codegen/naked-functions.rs
浏览文件 @
7279af86
...
...
@@ -13,7 +13,7 @@
// compile-flags: -C no-prepopulate-passes
#![crate_type
=
"lib"
]
#![feature(naked_functions)]
#![feature(naked_functions
,
rustc_attrs
)]
// CHECK: Function Attrs: naked uwtable
// CHECK-NEXT: define internal void @naked_empty()
...
...
@@ -26,6 +26,7 @@ fn naked_empty() {
// CHECK: Function Attrs: naked uwtable
#[no_mangle]
#[naked]
#[rustc_no_mir]
// FIXME #27840 MIR has different codegen.
// CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}})
fn
naked_with_args
(
a
:
isize
)
{
// CHECK: %a = alloca i{{[0-9]+}}
...
...
@@ -45,6 +46,7 @@ fn naked_with_return() -> isize {
// CHECK-NEXT: define internal i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
#[no_mangle]
#[naked]
#[rustc_no_mir]
// FIXME #27840 MIR has different codegen.
fn
naked_with_args_and_return
(
a
:
isize
)
->
isize
{
// CHECK: %a = alloca i{{[0-9]+}}
// CHECK: ret i{{[0-9]+}} %{{[0-9]+}}
...
...
src/test/compile-fail/issue-26548.rs
浏览文件 @
7279af86
...
...
@@ -10,10 +10,13 @@
// error-pattern: overflow representing the type `S`
#![feature(rustc_attrs)]
trait
Mirror
{
type
It
:
?
Sized
;
}
impl
<
T
:
?
Sized
>
Mirror
for
T
{
type
It
=
Self
;
}
struct
S
(
Option
<<
S
as
Mirror
>
::
It
>
);
#[rustc_no_mir]
// FIXME #27840 MIR tries to represent `std::option::Option<S>` first.
fn
main
()
{
let
_
s
=
S
(
None
);
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录