Description
As suggested, this issue is about the Rust single source cross compilation story. I've had some success with this while I was working on mir-hsa
and the AMDGPU Stuff. In my case, the HSA API is used, which accepts GPU native ELF files directly, and therefore enables me to not have to write a new codegen backend. I have done this with the following changes to Rust:
- Plugin provided
rustc-intrinsic
s, which run post monomorphization to have access to only concrete types and usage. They are limited to inserting MIR statements just before the originalTerminatorKind::Call
. This is useful because all Rust functions have a unique type. Thus a call the intrinsic like this one (note the upvar stuff is nonfunctional, however. I need to put more thought into that part) will “return” theDefId
(rather, equivalent info) of the function passed in. After expansion, trans rewrites the terminator to be a direct goto. This is the plugin that expands thekernel_info_for
intrinsic mentioned/linked earlier.
This expansion originally occurred during trans, like when traditional LLVM intrinsics are handled. However, I think it could be made to happen before collection and partitioning. Either way, this implementation as is allows crate authors to use plugin intrinsics and not force downstream crates to also load that plugin (downstream crates can't be able to call the intrinsics generically).
Here is the trait for the plugin registry:
pub trait MirPluginIntrinsicTrans {
fn trans_simple_intrinsic<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
name: &str,
source_info: SourceInfo,
sig: &FnSig<'tcx>,
parent_mir: &mir::Mir<'tcx>,
parent_param_substs: &'tcx Substs<'tcx>,
args: &Vec<Operand<'tcx>>,
return_place: Place<'tcx>,
extra_stmts: &mut Vec<StatementKind<'tcx>>)
where 'tcx: 'a;
}
The extra statements needed to store the return values are put into extra_stmts
, which are translated just after the function returns. The other parameters are so one has the needed things to monomorphize types, and for debugging info.
My impl had Rust just trusting that the "return" value provided by the plugin matched the type specified by the intrinsic declaration. This is probably not what we want long term.
-
A codegen/”debugging” flag to always save/keep Rust’s cstore metadata in outputs. Combined with
-Z always-encode-mir
, we now have every function’s MIR available at runtime. My original impl made this hard coded ‘cause I’m lazy, so I’ll need to fix this before issuing a PR. -
An extra codegen/”debugging” flag to force
librustc_mir::monomorphize
to translate everything, without relying on upstream definitions and a linker. I made this inaccessible to everyone except specializedrustc
drivers, ie can’t userustc -Z retrans-all-deps ..
, to prevent misuse. -
Make
librustc_metadata::schema
public, so one can useCrateRoot
and friends. Here is how the metadata was loaded (finding every dylib, including dylibs not actually mapped into the current process, is done elsewhere). -
Make Rust accept a mono item collector root override. This is used by a special
rustc
driver at compiled program runtime to rerun trans for specific functions.
Issues (as implemented, so mostly issues related to my runtime impl):
- This method is limited to Rust code only.
- It also doesn’t allow performing codegen at compile-time (ie generating for the cross when you’re compiling for the host; the cross must be “compiled” at runtime).
- Globals referenced will not be shared. Or, globals are defined in the output. Host/GPU ABI differences.
- Closure upvars are ignored (IIRC, they didn’t work at all when I tried with my prototype, but I decided to ignore this while I got other things working so..). The runtime (eg my
mir-hsa::runtime
crate) will need to know about the upvars of a closure so that they can get mapped on to the GPU. - New
Send
like trait:NumaSend
. This is needed so that types can do appropriate serialization of inner memory regions when they are sent to other memories. Doesn’t seem like there is a whole lotta thought into this area, yet.
Has anyone else worked on any single source prototype? I see this topic on discuss.rust-lang.org, but nothing recent.
RFC of sorts, so please criticize. I'm going to submit patches for the proposed changes above, and I would like to at least get something functionally equivalent accepted.
@eddyb
Edit log:
- Fix missing link