2020-05-10 14:54:30 +00:00
/*
2022-03-26 17:29:37 +00:00
* TODO ( antoyo ) : implement equality in libgccjit based on https ://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?)
2021-08-15 12:28:46 +00:00
* TODO ( antoyo ) : support #[ inline ] attributes .
2022-03-26 17:29:37 +00:00
* TODO ( antoyo ) : support LTO ( gcc ' s equivalent to Thin LTO is enabled by - fwhopr : https ://stackoverflow.com/questions/64954525/does-gcc-have-thin-lto).
2020-05-10 14:54:30 +00:00
*
2021-08-15 12:28:46 +00:00
* TODO ( antoyo ) : remove the patches .
2020-05-10 14:54:30 +00:00
* /
2022-06-28 17:34:24 +00:00
#![ feature(
rustc_private ,
decl_macro ,
associated_type_bounds ,
never_type ,
trusted_len ,
hash_raw_entry
) ]
2020-05-10 14:54:30 +00:00
#![ allow(broken_intra_doc_links) ]
#![ recursion_limit= " 256 " ]
#![ warn(rust_2018_idioms) ]
#![ warn(unused_lifetimes) ]
extern crate rustc_ast ;
extern crate rustc_codegen_ssa ;
extern crate rustc_data_structures ;
extern crate rustc_errors ;
extern crate rustc_hir ;
extern crate rustc_metadata ;
extern crate rustc_middle ;
extern crate rustc_session ;
extern crate rustc_span ;
extern crate rustc_target ;
2022-03-26 17:29:37 +00:00
extern crate tempfile ;
2020-05-10 14:54:30 +00:00
// This prevents duplicating functions and statics that are already part of the host rustc process.
#[ allow(unused_extern_crates) ]
extern crate rustc_driver ;
mod abi ;
mod allocator ;
mod archive ;
mod asm ;
mod back ;
mod base ;
mod builder ;
mod callee ;
mod common ;
mod consts ;
mod context ;
mod coverageinfo ;
mod debuginfo ;
mod declare ;
2022-03-26 17:29:37 +00:00
mod int ;
2020-05-10 14:54:30 +00:00
mod intrinsic ;
mod mono_item ;
mod type_ ;
mod type_of ;
use std ::any ::Any ;
2022-03-26 17:29:37 +00:00
use std ::sync ::{ Arc , Mutex } ;
2020-05-10 14:54:30 +00:00
2022-03-26 17:29:37 +00:00
use gccjit ::{ Context , OptimizationLevel , CType } ;
2020-05-10 14:54:30 +00:00
use rustc_ast ::expand ::allocator ::AllocatorKind ;
use rustc_codegen_ssa ::{ CodegenResults , CompiledModule , ModuleCodegen } ;
use rustc_codegen_ssa ::base ::codegen_crate ;
use rustc_codegen_ssa ::back ::write ::{ CodegenContext , FatLTOInput , ModuleConfig , TargetMachineFactoryFn } ;
use rustc_codegen_ssa ::back ::lto ::{ LtoModuleCodegen , SerializedModule , ThinModule } ;
use rustc_codegen_ssa ::target_features ::supported_target_features ;
use rustc_codegen_ssa ::traits ::{ CodegenBackend , ExtraBackendMethods , ModuleBufferMethods , ThinBufferMethods , WriteBackendMethods } ;
use rustc_data_structures ::fx ::FxHashMap ;
2022-01-23 18:34:26 +00:00
use rustc_errors ::{ ErrorGuaranteed , Handler } ;
2021-09-30 18:22:42 +00:00
use rustc_metadata ::EncodedMetadata ;
2020-05-10 14:54:30 +00:00
use rustc_middle ::dep_graph ::{ WorkProduct , WorkProductId } ;
use rustc_middle ::ty ::TyCtxt ;
2022-03-26 17:29:37 +00:00
use rustc_middle ::ty ::query ::Providers ;
2021-09-27 13:34:06 +00:00
use rustc_session ::config ::{ Lto , OptLevel , OutputFilenames } ;
2020-05-10 14:54:30 +00:00
use rustc_session ::Session ;
use rustc_span ::Symbol ;
use rustc_span ::fatal_error ::FatalError ;
2022-03-26 17:29:37 +00:00
use tempfile ::TempDir ;
2020-05-10 14:54:30 +00:00
pub struct PrintOnPanic < F : Fn ( ) -> String > ( pub F ) ;
impl < F : Fn ( ) -> String > Drop for PrintOnPanic < F > {
fn drop ( & mut self ) {
if ::std ::thread ::panicking ( ) {
println! ( " {} " , ( self . 0 ) ( ) ) ;
}
}
}
#[ derive(Clone) ]
2022-03-26 17:29:37 +00:00
pub struct GccCodegenBackend {
supports_128bit_integers : Arc < Mutex < bool > > ,
}
2020-05-10 14:54:30 +00:00
impl CodegenBackend for GccCodegenBackend {
fn init ( & self , sess : & Session ) {
if sess . lto ( ) ! = Lto ::No {
sess . warn ( " LTO is not supported. You may get a linker error. " ) ;
}
2022-03-26 17:29:37 +00:00
let temp_dir = TempDir ::new ( ) . expect ( " cannot create temporary directory " ) ;
let temp_file = temp_dir . into_path ( ) . join ( " result.asm " ) ;
let check_context = Context ::default ( ) ;
check_context . set_print_errors_to_stderr ( false ) ;
let _int128_ty = check_context . new_c_type ( CType ::UInt128t ) ;
// NOTE: we cannot just call compile() as this would require other files than libgccjit.so.
check_context . compile_to_file ( gccjit ::OutputKind ::Assembler , temp_file . to_str ( ) . expect ( " path to str " ) ) ;
* self . supports_128bit_integers . lock ( ) . expect ( " lock " ) = check_context . get_last_error ( ) = = Ok ( None ) ;
}
fn provide ( & self , providers : & mut Providers ) {
// FIXME(antoyo) compute list of enabled features from cli flags
providers . global_backend_features = | _tcx , ( ) | vec! [ ] ;
2020-05-10 14:54:30 +00:00
}
fn codegen_crate < ' tcx > ( & self , tcx : TyCtxt < ' tcx > , metadata : EncodedMetadata , need_metadata_module : bool ) -> Box < dyn Any > {
let target_cpu = target_cpu ( tcx . sess ) ;
let res = codegen_crate ( self . clone ( ) , tcx , target_cpu . to_string ( ) , metadata , need_metadata_module ) ;
Box ::new ( res )
}
2022-01-23 18:34:26 +00:00
fn join_codegen ( & self , ongoing_codegen : Box < dyn Any > , sess : & Session , _outputs : & OutputFilenames ) -> Result < ( CodegenResults , FxHashMap < WorkProductId , WorkProduct > ) , ErrorGuaranteed > {
2020-05-10 14:54:30 +00:00
let ( codegen_results , work_products ) = ongoing_codegen
. downcast ::< rustc_codegen_ssa ::back ::write ::OngoingCodegen < GccCodegenBackend > > ( )
. expect ( " Expected GccCodegenBackend's OngoingCodegen, found Box<Any> " )
. join ( sess ) ;
Ok ( ( codegen_results , work_products ) )
}
2022-01-23 18:34:26 +00:00
fn link ( & self , sess : & Session , codegen_results : CodegenResults , outputs : & OutputFilenames ) -> Result < ( ) , ErrorGuaranteed > {
2020-05-10 14:54:30 +00:00
use rustc_codegen_ssa ::back ::link ::link_binary ;
2022-07-28 09:07:49 +00:00
link_binary (
2020-05-10 14:54:30 +00:00
sess ,
2022-07-28 09:07:49 +00:00
& crate ::archive ::ArArchiveBuilderBuilder ,
2020-05-10 14:54:30 +00:00
& codegen_results ,
outputs ,
)
}
2022-07-11 13:26:58 +00:00
fn target_features ( & self , sess : & Session , allow_unstable : bool ) -> Vec < Symbol > {
target_features ( sess , allow_unstable )
2020-05-10 14:54:30 +00:00
}
}
impl ExtraBackendMethods for GccCodegenBackend {
2022-04-30 19:20:08 +00:00
fn codegen_allocator < ' tcx > ( & self , tcx : TyCtxt < ' tcx > , module_name : & str , kind : AllocatorKind , has_alloc_error_handler : bool ) -> Self ::Module {
let mut mods = GccContext {
2020-05-10 14:54:30 +00:00
context : Context ::default ( ) ,
2022-04-30 19:20:08 +00:00
} ;
unsafe { allocator ::codegen ( tcx , & mut mods , module_name , kind , has_alloc_error_handler ) ; }
mods
2020-05-10 14:54:30 +00:00
}
fn compile_codegen_unit < ' tcx > ( & self , tcx : TyCtxt < ' tcx > , cgu_name : Symbol ) -> ( ModuleCodegen < Self ::Module > , u64 ) {
2022-03-26 17:29:37 +00:00
base ::compile_codegen_unit ( tcx , cgu_name , * self . supports_128bit_integers . lock ( ) . expect ( " lock " ) )
2020-05-10 14:54:30 +00:00
}
2021-09-24 15:02:02 +00:00
fn target_machine_factory ( & self , _sess : & Session , _opt_level : OptLevel , _features : & [ String ] ) -> TargetMachineFactoryFn < Self > {
2021-08-15 12:28:46 +00:00
// TODO(antoyo): set opt level.
2020-05-10 14:54:30 +00:00
Arc ::new ( | _ | {
Ok ( ( ) )
} )
}
fn target_cpu < ' b > ( & self , _sess : & ' b Session ) -> & ' b str {
unimplemented! ( ) ;
}
fn tune_cpu < ' b > ( & self , _sess : & ' b Session ) -> Option < & ' b str > {
None
2021-08-15 12:28:46 +00:00
// TODO(antoyo)
2020-05-10 14:54:30 +00:00
}
}
pub struct ModuleBuffer ;
impl ModuleBufferMethods for ModuleBuffer {
fn data ( & self ) -> & [ u8 ] {
unimplemented! ( ) ;
}
}
pub struct ThinBuffer ;
impl ThinBufferMethods for ThinBuffer {
fn data ( & self ) -> & [ u8 ] {
unimplemented! ( ) ;
}
}
pub struct GccContext {
context : Context < 'static > ,
}
unsafe impl Send for GccContext { }
2021-08-15 12:28:46 +00:00
// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". Try to disable it here.
2020-05-10 14:54:30 +00:00
unsafe impl Sync for GccContext { }
impl WriteBackendMethods for GccCodegenBackend {
type Module = GccContext ;
type TargetMachine = ( ) ;
type ModuleBuffer = ModuleBuffer ;
type Context = ( ) ;
type ThinData = ( ) ;
type ThinBuffer = ThinBuffer ;
fn run_fat_lto ( _cgcx : & CodegenContext < Self > , mut modules : Vec < FatLTOInput < Self > > , _cached_modules : Vec < ( SerializedModule < Self ::ModuleBuffer > , WorkProduct ) > ) -> Result < LtoModuleCodegen < Self > , FatalError > {
2021-08-15 12:28:46 +00:00
// TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
2020-05-10 14:54:30 +00:00
// NOTE: implemented elsewhere.
2022-02-06 22:04:24 +00:00
// TODO(antoyo): what is implemented elsewhere ^ ?
2020-05-10 14:54:30 +00:00
let module =
match modules . remove ( 0 ) {
FatLTOInput ::InMemory ( module ) = > module ,
FatLTOInput ::Serialized { .. } = > {
unimplemented! ( ) ;
}
} ;
2022-04-30 18:51:17 +00:00
Ok ( LtoModuleCodegen ::Fat { module , _serialized_bitcode : vec ! [ ] } )
2020-05-10 14:54:30 +00:00
}
fn run_thin_lto ( _cgcx : & CodegenContext < Self > , _modules : Vec < ( String , Self ::ThinBuffer ) > , _cached_modules : Vec < ( SerializedModule < Self ::ModuleBuffer > , WorkProduct ) > ) -> Result < ( Vec < LtoModuleCodegen < Self > > , Vec < WorkProduct > ) , FatalError > {
unimplemented! ( ) ;
}
fn print_pass_timings ( & self ) {
unimplemented! ( ) ;
}
unsafe fn optimize ( _cgcx : & CodegenContext < Self > , _diag_handler : & Handler , module : & ModuleCodegen < Self ::Module > , config : & ModuleConfig ) -> Result < ( ) , FatalError > {
module . module_llvm . context . set_optimization_level ( to_gcc_opt_level ( config . opt_level ) ) ;
Ok ( ( ) )
}
2022-04-30 18:58:42 +00:00
fn optimize_fat ( _cgcx : & CodegenContext < Self > , _module : & mut ModuleCodegen < Self ::Module > ) -> Result < ( ) , FatalError > {
2022-04-30 18:50:17 +00:00
// TODO(antoyo)
Ok ( ( ) )
}
2022-04-30 18:51:17 +00:00
unsafe fn optimize_thin ( _cgcx : & CodegenContext < Self > , _thin : ThinModule < Self > ) -> Result < ModuleCodegen < Self ::Module > , FatalError > {
2020-05-10 14:54:30 +00:00
unimplemented! ( ) ;
}
unsafe fn codegen ( cgcx : & CodegenContext < Self > , diag_handler : & Handler , module : ModuleCodegen < Self ::Module > , config : & ModuleConfig ) -> Result < CompiledModule , FatalError > {
back ::write ::codegen ( cgcx , diag_handler , module , config )
}
fn prepare_thin ( _module : ModuleCodegen < Self ::Module > ) -> ( String , Self ::ThinBuffer ) {
unimplemented! ( ) ;
}
fn serialize_module ( _module : ModuleCodegen < Self ::Module > ) -> ( String , Self ::ModuleBuffer ) {
unimplemented! ( ) ;
}
fn run_link ( cgcx : & CodegenContext < Self > , diag_handler : & Handler , modules : Vec < ModuleCodegen < Self ::Module > > ) -> Result < ModuleCodegen < Self ::Module > , FatalError > {
back ::write ::link ( cgcx , diag_handler , modules )
}
}
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
#[ no_mangle ]
pub fn __rustc_codegen_backend ( ) -> Box < dyn CodegenBackend > {
2022-03-26 17:29:37 +00:00
Box ::new ( GccCodegenBackend {
supports_128bit_integers : Arc ::new ( Mutex ::new ( false ) ) ,
} )
2020-05-10 14:54:30 +00:00
}
fn to_gcc_opt_level ( optlevel : Option < OptLevel > ) -> OptimizationLevel {
match optlevel {
None = > OptimizationLevel ::None ,
Some ( level ) = > {
match level {
OptLevel ::No = > OptimizationLevel ::None ,
OptLevel ::Less = > OptimizationLevel ::Limited ,
OptLevel ::Default = > OptimizationLevel ::Standard ,
OptLevel ::Aggressive = > OptimizationLevel ::Aggressive ,
OptLevel ::Size | OptLevel ::SizeMin = > OptimizationLevel ::Limited ,
}
} ,
}
}
fn handle_native ( name : & str ) -> & str {
if name ! = " native " {
return name ;
}
unimplemented! ( ) ;
}
pub fn target_cpu ( sess : & Session ) -> & str {
2022-04-03 16:42:39 +00:00
match sess . opts . cg . target_cpu {
Some ( ref name ) = > handle_native ( name ) ,
None = > handle_native ( sess . target . cpu . as_ref ( ) ) ,
}
2020-05-10 14:54:30 +00:00
}
2022-07-11 13:26:58 +00:00
pub fn target_features ( sess : & Session , allow_unstable : bool ) -> Vec < Symbol > {
2020-05-10 14:54:30 +00:00
supported_target_features ( sess )
. iter ( )
. filter_map (
| & ( feature , gate ) | {
2022-07-11 13:26:58 +00:00
if sess . is_nightly_build ( ) | | allow_unstable | | gate . is_none ( ) { Some ( feature ) } else { None }
2020-05-10 14:54:30 +00:00
} ,
)
. filter ( | _feature | {
2021-08-15 12:28:46 +00:00
// TODO(antoyo): implement a way to get enabled feature in libgccjit.
2022-02-06 22:04:24 +00:00
// Probably using the equivalent of __builtin_cpu_supports.
2022-04-13 21:51:39 +00:00
#[ cfg(feature= " master " ) ]
{
_feature . contains ( " sse " ) | | _feature . contains ( " avx " )
}
#[ cfg(not(feature= " master " )) ]
{
false
}
2022-02-06 22:04:24 +00:00
/*
adx , aes , avx , avx2 , avx512bf16 , avx512bitalg , avx512bw , avx512cd , avx512dq , avx512er , avx512f , avx512gfni ,
avx512ifma , avx512pf , avx512vaes , avx512vbmi , avx512vbmi2 , avx512vl , avx512vnni , avx512vp2intersect , avx512vpclmulqdq ,
avx512vpopcntdq , bmi1 , bmi2 , cmpxchg16b , ermsb , f16c , fma , fxsr , lzcnt , movbe , pclmulqdq , popcnt , rdrand , rdseed , rtm ,
sha , sse , sse2 , sse3 , sse4 . 1 , sse4 . 2 , sse4a , ssse3 , tbm , xsave , xsavec , xsaveopt , xsaves
* /
//false
2020-05-10 14:54:30 +00:00
} )
. map ( | feature | Symbol ::intern ( feature ) )
. collect ( )
}