2018-07-20 13:51:34 +02:00
use std ::borrow ::Cow ;
2018-07-14 11:59:42 +02:00
use std ::collections ::HashMap ;
use std ::fmt ;
2019-05-14 16:12:58 +02:00
use cranelift ::codegen ::{
entity ::SecondaryMap ,
ir ::{
self ,
entities ::AnyEntity ,
function ::DisplayFunctionAnnotations ,
} ,
write ::{ FuncWriter , PlainWriter } ,
ValueLabelsRanges ,
} ;
2018-07-20 13:51:34 +02:00
2018-07-30 16:57:40 +02:00
use crate ::prelude ::* ;
2018-07-14 11:59:42 +02:00
2018-12-27 10:59:01 +01:00
/// This module provides the [CommentWriter] which makes it possible
/// to add comments to the written cranelift ir.
///
/// # Example
///
/// ```clif
/// test compile
/// target x86_64
///
/// function u0:0(i64, i64, i64) system_v {
/// ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
/// ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
2019-03-01 18:55:20 +01:00
/// ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
2018-12-27 10:59:01 +01:00
///
/// ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
/// ; msg loc.idx param pass mode ssa flags ty
/// ; ret _0 = v0 ByRef NOT_SSA (u8, u8)
/// ; arg _1 = v1 ByRef NOT_SSA IsNotEmpty
/// ; arg _2.0 = v2 ByVal(types::I64) NOT_SSA &&[u16]
///
/// ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
/// ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
/// ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
/// sig0 = (i64, i64, i64) system_v
/// sig1 = (i64, i64, i64) system_v
/// fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
///
/// ebb0(v0: i64, v1: i64, v2: i64):
/// v3 = stack_addr.i64 ss0
/// v4 = stack_addr.i64 ss1
/// store v2, v4
/// v5 = stack_addr.i64 ss2
/// jump ebb1
///
/// ebb1:
/// nop
/// ; _3 = &mut _1
/// ; _4 = _2
/// v6 = load.i64 v4
/// store v6, v5
/// ;
/// ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
/// v7 = load.i64 v5
/// call fn0(v0, v3, v7)
/// jump ebb2
///
/// ebb2:
/// nop
/// ;
/// ; return
/// return
/// }
/// ```
2018-12-21 21:42:29 +01:00
#[ derive(Debug) ]
pub struct CommentWriter {
global_comments : Vec < String > ,
2018-12-27 10:59:01 +01:00
entity_comments : HashMap < AnyEntity , String > ,
inst_comments : HashMap < Inst , String > ,
2018-12-21 21:42:29 +01:00
}
impl CommentWriter {
2019-06-16 11:13:49 +02:00
pub fn new < ' tcx > ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> Self {
2018-12-21 21:42:29 +01:00
CommentWriter {
global_comments : vec ! [
format! ( " symbol {} " , tcx . symbol_name ( instance ) . as_str ( ) ) ,
format! ( " instance {:?} " , instance ) ,
2019-03-26 19:53:04 +01:00
format! ( " sig {:?} " , tcx . normalize_erasing_late_bound_regions ( ParamEnv ::reveal_all ( ) , & instance . fn_sig ( tcx ) ) ) ,
2018-12-21 21:42:29 +01:00
String ::new ( ) ,
] ,
2018-12-27 10:59:01 +01:00
entity_comments : HashMap ::new ( ) ,
2018-12-21 21:42:29 +01:00
inst_comments : HashMap ::new ( ) ,
}
}
}
2018-07-14 11:59:42 +02:00
2019-06-16 11:13:49 +02:00
impl FuncWriter for & '_ CommentWriter {
2018-11-15 10:55:40 +01:00
fn write_preamble (
& mut self ,
w : & mut dyn fmt ::Write ,
func : & Function ,
reg_info : Option < & isa ::RegInfo > ,
) -> Result < bool , fmt ::Error > {
2018-12-21 21:42:29 +01:00
for comment in & self . global_comments {
if ! comment . is_empty ( ) {
writeln! ( w , " ; {} " , comment ) ? ;
} else {
writeln! ( w , " " ) ? ;
}
}
if ! self . global_comments . is_empty ( ) {
writeln! ( w , " " ) ? ;
}
2018-12-27 10:59:01 +01:00
self . super_preamble ( w , func , reg_info )
}
fn write_entity_definition (
& mut self ,
w : & mut dyn fmt ::Write ,
_func : & Function ,
entity : AnyEntity ,
2019-05-31 10:56:55 +02:00
value : & dyn fmt ::Display ,
2018-12-27 10:59:01 +01:00
) -> fmt ::Result {
write! ( w , " {} = {} " , entity , value ) ? ;
if let Some ( comment ) = self . entity_comments . get ( & entity ) {
writeln! ( w , " ; {} " , comment . replace ( '\n' , " \n ; " ) )
} else {
writeln! ( w , " " )
}
2018-11-15 10:55:40 +01:00
}
fn write_ebb_header (
& mut self ,
w : & mut dyn fmt ::Write ,
func : & Function ,
isa : Option < & dyn isa ::TargetIsa > ,
ebb : Ebb ,
indent : usize ,
) -> fmt ::Result {
PlainWriter . write_ebb_header ( w , func , isa , ebb , indent )
}
2018-07-14 11:59:42 +02:00
fn write_instruction (
& mut self ,
w : & mut dyn fmt ::Write ,
func : & Function ,
2018-09-27 19:19:16 +02:00
aliases : & SecondaryMap < Value , Vec < Value > > ,
2018-07-14 11:59:42 +02:00
isa : Option < & dyn isa ::TargetIsa > ,
inst : Inst ,
indent : usize ,
) -> fmt ::Result {
2018-09-05 19:43:42 +02:00
PlainWriter . write_instruction ( w , func , aliases , isa , inst , indent ) ? ;
2018-12-21 21:42:29 +01:00
if let Some ( comment ) = self . inst_comments . get ( & inst ) {
2018-07-14 12:21:45 +02:00
writeln! ( w , " ; {} " , comment . replace ( '\n' , " \n ; " ) ) ? ;
}
2018-07-20 13:51:34 +02:00
Ok ( ( ) )
2018-07-14 11:59:42 +02:00
}
}
2018-07-20 13:51:34 +02:00
2018-12-28 17:07:40 +01:00
#[ cfg(debug_assertions) ]
2018-08-14 20:31:16 +02:00
impl < ' a , ' tcx : ' a , B : Backend + ' a > FunctionCx < ' a , ' tcx , B > {
2018-12-21 21:42:29 +01:00
pub fn add_global_comment < S : Into < String > > ( & mut self , comment : S ) {
self . clif_comments . global_comments . push ( comment . into ( ) ) ;
2018-08-15 16:17:59 +02:00
}
2019-02-21 15:06:09 +01:00
pub fn add_entity_comment < ' s , S : Into < Cow < ' s , str > > , E : Into < AnyEntity > > (
& mut self ,
entity : E ,
comment : S ,
) {
2018-12-27 10:59:01 +01:00
use std ::collections ::hash_map ::Entry ;
match self . clif_comments . entity_comments . entry ( entity . into ( ) ) {
Entry ::Occupied ( mut occ ) = > {
occ . get_mut ( ) . push ( '\n' ) ;
occ . get_mut ( ) . push_str ( comment . into ( ) . as_ref ( ) ) ;
}
Entry ::Vacant ( vac ) = > {
vac . insert ( comment . into ( ) . into_owned ( ) ) ;
}
}
}
2018-07-20 13:51:34 +02:00
pub fn add_comment < ' s , S : Into < Cow < ' s , str > > > ( & mut self , inst : Inst , comment : S ) {
use std ::collections ::hash_map ::Entry ;
2018-12-21 21:42:29 +01:00
match self . clif_comments . inst_comments . entry ( inst ) {
2018-07-20 13:51:34 +02:00
Entry ::Occupied ( mut occ ) = > {
occ . get_mut ( ) . push ( '\n' ) ;
occ . get_mut ( ) . push_str ( comment . into ( ) . as_ref ( ) ) ;
}
Entry ::Vacant ( vac ) = > {
vac . insert ( comment . into ( ) . into_owned ( ) ) ;
}
}
}
2019-05-14 16:12:58 +02:00
}
2019-06-16 11:13:49 +02:00
pub fn write_clif_file < ' tcx > (
tcx : TyCtxt < ' tcx > ,
2019-05-14 16:12:58 +02:00
postfix : & str ,
instance : Instance < ' tcx > ,
func : & ir ::Function ,
mut clif_comments : & CommentWriter ,
value_ranges : Option < & ValueLabelsRanges > ,
) {
use std ::io ::Write ;
let symbol_name = tcx . symbol_name ( instance ) . as_str ( ) ;
let clif_file_name = format! (
" {}/{}__{}.{}.clif " ,
concat! ( env! ( " CARGO_MANIFEST_DIR " ) , " /target/out/clif " ) ,
tcx . crate_name ( LOCAL_CRATE ) ,
symbol_name ,
postfix ,
) ;
2018-12-21 21:42:29 +01:00
2019-05-14 16:12:58 +02:00
let mut clif = String ::new ( ) ;
cranelift ::codegen ::write ::decorate_function (
& mut clif_comments ,
& mut clif ,
& func ,
& DisplayFunctionAnnotations {
isa : Some ( & * crate ::build_isa ( tcx . sess ) ) ,
value_ranges ,
} ,
)
. unwrap ( ) ;
match ::std ::fs ::File ::create ( clif_file_name ) {
Ok ( mut file ) = > {
2019-05-25 12:30:21 +02:00
let target_triple = crate ::target_triple ( tcx . sess ) ;
2019-05-14 16:12:58 +02:00
writeln! ( file , " test compile " ) . unwrap ( ) ;
writeln! ( file , " set is_pic " ) . unwrap ( ) ;
writeln! ( file , " target {} " , target_triple ) . unwrap ( ) ;
writeln! ( file , " " ) . unwrap ( ) ;
file . write ( clif . as_bytes ( ) ) . unwrap ( ) ;
}
Err ( e ) = > {
tcx . sess . warn ( & format! ( " err opening clif file: {:?} " , e ) ) ;
}
}
}
2018-12-21 21:42:29 +01:00
2019-05-14 16:12:58 +02:00
impl < ' a , ' tcx : ' a , B : Backend + ' a > fmt ::Debug for FunctionCx < ' a , ' tcx , B > {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
writeln! ( f , " {:?} " , self . instance . substs ) ? ;
writeln! ( f , " {:?} " , self . local_map ) ? ;
2018-12-21 21:42:29 +01:00
let mut clif = String ::new ( ) ;
2019-02-21 15:06:09 +01:00
::cranelift ::codegen ::write ::decorate_function (
& mut & self . clif_comments ,
& mut clif ,
& self . bcx . func ,
2019-05-14 16:12:58 +02:00
// FIXME use DisplayFunctionAnnotations::default() instead
& DisplayFunctionAnnotations {
isa : None ,
value_ranges : None ,
} ,
2019-02-21 15:06:09 +01:00
)
. unwrap ( ) ;
2019-05-14 16:12:58 +02:00
writeln! ( f , " \n {} " , clif )
2018-12-21 21:42:29 +01:00
}
2018-07-20 13:51:34 +02:00
}