Start emitting spirv modules

This commit is contained in:
khyperia 2020-08-10 16:41:57 +02:00
parent cf71e44bb6
commit 9ab212f93c
7 changed files with 210 additions and 73 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target /target
Cargo.lock Cargo.lock
*.spv

View File

@ -10,3 +10,5 @@ edition = "2018"
crate-type = ["dylib"] crate-type = ["dylib"]
[dependencies] [dependencies]
rspirv = "0.6"
spirv_headers = "1.4"

View File

@ -1 +0,0 @@
This has been "compiled" successfully.

View File

@ -1,4 +1,5 @@
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(or_insert_with_key)]
extern crate rustc_codegen_ssa; extern crate rustc_codegen_ssa;
extern crate rustc_errors; extern crate rustc_errors;
@ -19,18 +20,17 @@ use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported; use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::DepGraph; use rustc_middle::dep_graph::DepGraph;
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames; use rustc_session::config::OutputFilenames;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::Target; use rustc_target::spec::Target;
use std::any::Any; use std::any::Any;
use std::path::Path; use std::path::Path;
use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility}; mod spirv_ctx;
use rustc_middle::mir::Rvalue; mod trans;
use rustc_middle::mir::StatementKind;
pub struct NoLlvmMetadataLoader; pub struct NoLlvmMetadataLoader;
@ -58,7 +58,7 @@ impl CodegenBackend for TheBackend {
rustc_symbol_mangling::provide(providers); rustc_symbol_mangling::provide(providers);
// jb-todo: target_features_whitelist is old name for supported_target_features // jb-todo: target_features_whitelist is old name for supported_target_features
providers.target_features_whitelist = |tcx, _cnum| { providers.supported_target_features = |_tcx, _cnum| {
Default::default() // Just a dummy Default::default() // Just a dummy
}; };
providers.is_reachable_non_generic = |_tcx, _defid| true; providers.is_reachable_non_generic = |_tcx, _defid| true;
@ -89,68 +89,25 @@ impl CodegenBackend for TheBackend {
dbg!(cgus.len()); dbg!(cgus.len());
let mut translator = trans::Translator::new(tcx);
cgus.iter().for_each(|cgu| { cgus.iter().for_each(|cgu| {
dbg!(cgu.name()); dbg!(cgu.name());
let cgu = tcx.codegen_unit(cgu.name()); let cgu = tcx.codegen_unit(cgu.name());
let mono_items = cgu.items_in_deterministic_order(tcx); let mono_items = cgu.items_in_deterministic_order(tcx);
for (mono_item, (linkage, visibility)) in mono_items { for (mono_item, (_linkage, _visibility)) in mono_items {
match mono_item { match mono_item {
MonoItem::Fn(instance) => { MonoItem::Fn(instance) => translator.trans_fn(instance),
{ thing => println!("Unknown MonoItem: {:?}", thing),
let mut mir = ::std::io::Cursor::new(Vec::new());
crate::rustc_mir::util::write_mir_pretty(
tcx,
Some(instance.def_id()),
&mut mir,
)
.unwrap();
let s = String::from_utf8(mir.into_inner()).unwrap();
println!("{}", s);
}
let mir = tcx.instance_mir(instance.def);
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
for stmt in &bb_data.statements {
match &stmt.kind {
StatementKind::Assign(to_place_and_rval) => {
let place = to_place_and_rval.0; // jb-todo: iterate though place.projection & build OpAccessChain from it? see trans_place in cranelift
dbg!(&place);
for elem in place.projection {
match elem {
_ => {}
}
}
dbg!(&to_place_and_rval.1);
match &to_place_and_rval.1 {
Rvalue::Use(operand) => {
//let val = trans_operand(fx, operand);
//lval.write_cvalue(fx, val);
dbg!(operand);
}
_ => {}
}
//let lval = trans_place(fx, to_place_and_rval.0);
//dbg!(lval);
//println!("Assign");
}
_ => {}
}
}
}
}
_ => {}
} }
} }
}); });
Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol) let module = translator.assemble();
Box::new(module)
} }
fn join_codegen( fn join_codegen(
@ -159,10 +116,11 @@ impl CodegenBackend for TheBackend {
_sess: &Session, _sess: &Session,
_dep_graph: &DepGraph, _dep_graph: &DepGraph,
) -> Result<Box<dyn Any>, ErrorReported> { ) -> Result<Box<dyn Any>, ErrorReported> {
let crate_name = ongoing_codegen Ok(ongoing_codegen)
.downcast::<Symbol>() // let crate_name = ongoing_codegen
.expect("in join_codegen: ongoing_codegen is not a Symbol"); // .downcast::<Symbol>()
Ok(crate_name) // .expect("in join_codegen: ongoing_codegen is not a Symbol");
// Ok(crate_name)
} }
fn link( fn link(
@ -171,18 +129,29 @@ impl CodegenBackend for TheBackend {
codegen_results: Box<dyn Any>, codegen_results: Box<dyn Any>,
outputs: &OutputFilenames, outputs: &OutputFilenames,
) -> Result<(), ErrorReported> { ) -> Result<(), ErrorReported> {
use rustc_session::{config::CrateType, output::out_filename}; use rustc_session::config::{CrateType, OutputType};
use std::io::Write; use std::io::Write;
let crate_name = codegen_results let codegen_bytes = codegen_results
.downcast::<Symbol>() .downcast::<Vec<u32>>()
.expect("in link: codegen_results is not a Symbol"); .expect("in link: codegen_results is not a Vec<u32>");
for &crate_type in sess.opts.crate_types.iter() { for &crate_type in sess.opts.crate_types.iter() {
if crate_type != CrateType::Rlib { if crate_type != CrateType::Rlib {
sess.fatal(&format!("Crate type is {:?}", crate_type)); sess.fatal(&format!("Crate type is {:?}", crate_type));
} }
let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str()); let mut output_name = outputs.path(OutputType::Exe);
let mut out_file = ::std::fs::File::create(output_name).unwrap(); output_name.set_extension("spv");
write!(out_file, "This has been \"compiled\" successfully.").unwrap(); let mut out_file =
::std::fs::File::create(output_name).expect("Unable to create output file");
// Note: endianness doesn't matter, readers deduce endianness from magic header.
let bytes_u8: &[u8] = unsafe {
std::slice::from_raw_parts(
codegen_bytes.as_ptr() as *const u8,
codegen_bytes.len() * std::mem::size_of::<u32>(),
)
};
out_file
.write_all(bytes_u8)
.expect("Unable to write output file");
} }
Ok(()) Ok(())
} }
@ -194,5 +163,4 @@ pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
Box::new(TheBackend) Box::new(TheBackend)
} }
// https://github.com/bjorn3/rustc_codegen_cranelift/blob/1b8df386aa72bc3dacb803f7d4deb4eadd63b56f/src/base.rs
// https://github.com/bjorn3/rustc_codegen_cranelift/blob/1b8df386aa72bc3dacb803f7d4deb4eadd63b56f/src/base.rs

75
src/spirv_ctx.rs Normal file
View File

@ -0,0 +1,75 @@
use rspirv::dr::Builder;
use spirv_headers::{AddressingModel, MemoryModel, Word};
use std::collections::HashMap;
macro_rules! impl_cache {
($name:ident) => {
pub fn $name(&mut self) -> Word {
match self.cache.$name {
Some(value) => value,
None => {
let value = self.builder.$name();
self.cache.$name = Some(value);
value
}
}
}
};
}
pub struct SpirvContext {
pub builder: Builder,
cache: Cache,
}
#[derive(Default)]
struct Cache {
type_void: Option<Word>,
type_bool: Option<Word>,
type_int: HashMap<(u32, u32), Word>,
type_float: HashMap<u32, Word>,
type_function: HashMap<(Word, Vec<Word>), Word>,
}
impl SpirvContext {
pub fn new() -> Self {
let mut builder = Builder::new();
builder.memory_model(AddressingModel::Logical, MemoryModel::GLSL450);
SpirvContext {
builder,
cache: Default::default(),
}
}
impl_cache! {type_void}
impl_cache! {type_bool}
pub fn type_int(&mut self, width: u32, signedness: u32) -> Word {
let builder = &mut self.builder;
*self
.cache
.type_int
.entry((width, signedness))
.or_insert_with(|| builder.type_int(width, signedness))
}
pub fn type_float(&mut self, width: u32) -> Word {
let builder = &mut self.builder;
*self
.cache
.type_float
.entry(width)
.or_insert_with(|| builder.type_float(width))
}
pub fn type_function(&mut self, return_type: Word, parameter_types: Vec<Word>) -> Word {
let builder = &mut self.builder;
*self
.cache
.type_function
.entry((return_type, parameter_types))
.or_insert_with_key(|(return_type, parameter_types)| {
builder.type_function(*return_type, parameter_types)
})
}
}

94
src/trans.rs Normal file
View File

@ -0,0 +1,94 @@
use crate::spirv_ctx::SpirvContext;
use rspirv::binary::Assemble;
use rustc_middle::mir::{Rvalue, Statement, StatementKind};
use rustc_middle::ty::TyCtxt;
use spirv_headers::FunctionControl;
pub struct Translator<'tcx> {
spirv: SpirvContext,
tcx: TyCtxt<'tcx>,
}
impl<'tcx> Translator<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
let spirv = SpirvContext::new();
Self { spirv, tcx }
}
pub fn assemble(self) -> Vec<u32> {
self.spirv.builder.module().assemble()
}
pub fn trans_fn(&mut self, instance: rustc_middle::ty::Instance<'tcx>) {
{
let mut mir = ::std::io::Cursor::new(Vec::new());
crate::rustc_mir::util::write_mir_pretty(self.tcx, Some(instance.def_id()), &mut mir)
.unwrap();
let s = String::from_utf8(mir.into_inner()).unwrap();
println!("{}", s);
}
let void = self.spirv.type_void();
let void_function = self.spirv.type_function(void, vec![void]);
let function_id = None;
let control = FunctionControl::NONE;
let _ = self
.spirv
.builder
.begin_function(void, function_id, control, void_function)
.unwrap();
let mir = self.tcx.instance_mir(instance.def);
for (_bb, bb_data) in mir.basic_blocks().iter_enumerated() {
self.spirv.builder.begin_block(None).unwrap();
for stmt in &bb_data.statements {
self.trans_stmt(stmt);
}
}
self.spirv.builder.end_function().unwrap();
}
fn trans_stmt(&self, stmt: &Statement) {
match &stmt.kind {
StatementKind::Assign(place_and_rval) => {
// can't destructure this since it's a Box<(place, rvalue)>
let place = place_and_rval.0;
let rvalue = &place_and_rval.1;
dbg!(&place);
for elem in place.projection {
match elem {
thing => println!("Unknown projection: {:?}", thing),
}
}
dbg!(&rvalue);
match &rvalue {
Rvalue::Use(operand) => {
//let val = trans_operand(fx, operand);
//lval.write_cvalue(fx, val);
dbg!(operand);
}
thing => println!("Unknown place: {:?}", thing),
}
//let lval = trans_place(fx, to_place_and_rval.0);
//dbg!(lval);
//println!("Assign");
}
thing => println!("Unknown statement: {:?}", thing),
}
}
fn trans_expr(&self, expr: Rvalue<'tcx>) {
match &expr {
Rvalue::Use(operand) => {
//let val = trans_operand(fx, operand);
//lval.write_cvalue(fx, val);
dbg!(operand);
}
thing => println!("Unknown place: {:?}", thing),
}
}
}

View File

@ -34,7 +34,5 @@ struct Jasper {
} }
pub fn jasper() { pub fn jasper() {
let _ktest = Jasper { let _ktest = Jasper { data: 666666 };
data: 666666
};
} }