diff --git a/.gitignore b/.gitignore index 96ef6c0b94..2d45a6edf3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +*.spv diff --git a/Cargo.toml b/Cargo.toml index 826bb45b4d..d87a7772f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,5 @@ edition = "2018" crate-type = ["dylib"] [dependencies] +rspirv = "0.6" +spirv_headers = "1.4" diff --git a/libempty.rlib b/libempty.rlib deleted file mode 100644 index 81d368bb85..0000000000 --- a/libempty.rlib +++ /dev/null @@ -1 +0,0 @@ -This has been "compiled" successfully. \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index facc55fee7..5d3b663dd4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![feature(or_insert_with_key)] extern crate rustc_codegen_ssa; extern crate rustc_errors; @@ -19,18 +20,17 @@ use rustc_data_structures::sync::MetadataRef; use rustc_errors::ErrorReported; use rustc_middle::dep_graph::DepGraph; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn}; +use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_span::symbol::Symbol; use rustc_target::spec::Target; use std::any::Any; use std::path::Path; -use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility}; -use rustc_middle::mir::Rvalue; -use rustc_middle::mir::StatementKind; +mod spirv_ctx; +mod trans; pub struct NoLlvmMetadataLoader; @@ -58,7 +58,7 @@ impl CodegenBackend for TheBackend { rustc_symbol_mangling::provide(providers); // 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 }; providers.is_reachable_non_generic = |_tcx, _defid| true; @@ -89,68 +89,25 @@ impl CodegenBackend for TheBackend { dbg!(cgus.len()); + let mut translator = trans::Translator::new(tcx); + cgus.iter().for_each(|cgu| { dbg!(cgu.name()); let cgu = tcx.codegen_unit(cgu.name()); 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 { - MonoItem::Fn(instance) => { - { - 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"); - } - _ => {} - } - } - } - } - _ => {} + MonoItem::Fn(instance) => translator.trans_fn(instance), + thing => println!("Unknown MonoItem: {:?}", thing), } } }); - Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol) + let module = translator.assemble(); + + Box::new(module) } fn join_codegen( @@ -159,10 +116,11 @@ impl CodegenBackend for TheBackend { _sess: &Session, _dep_graph: &DepGraph, ) -> Result, ErrorReported> { - let crate_name = ongoing_codegen - .downcast::() - .expect("in join_codegen: ongoing_codegen is not a Symbol"); - Ok(crate_name) + Ok(ongoing_codegen) + // let crate_name = ongoing_codegen + // .downcast::() + // .expect("in join_codegen: ongoing_codegen is not a Symbol"); + // Ok(crate_name) } fn link( @@ -171,18 +129,29 @@ impl CodegenBackend for TheBackend { codegen_results: Box, outputs: &OutputFilenames, ) -> Result<(), ErrorReported> { - use rustc_session::{config::CrateType, output::out_filename}; + use rustc_session::config::{CrateType, OutputType}; use std::io::Write; - let crate_name = codegen_results - .downcast::() - .expect("in link: codegen_results is not a Symbol"); + let codegen_bytes = codegen_results + .downcast::>() + .expect("in link: codegen_results is not a Vec"); for &crate_type in sess.opts.crate_types.iter() { if crate_type != CrateType::Rlib { sess.fatal(&format!("Crate type is {:?}", crate_type)); } - let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str()); - let mut out_file = ::std::fs::File::create(output_name).unwrap(); - write!(out_file, "This has been \"compiled\" successfully.").unwrap(); + let mut output_name = outputs.path(OutputType::Exe); + output_name.set_extension("spv"); + 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::(), + ) + }; + out_file + .write_all(bytes_u8) + .expect("Unable to write output file"); } Ok(()) } @@ -194,5 +163,4 @@ pub fn __rustc_codegen_backend() -> Box { Box::new(TheBackend) } - -// https://github.com/bjorn3/rustc_codegen_cranelift/blob/1b8df386aa72bc3dacb803f7d4deb4eadd63b56f/src/base.rs \ No newline at end of file +// https://github.com/bjorn3/rustc_codegen_cranelift/blob/1b8df386aa72bc3dacb803f7d4deb4eadd63b56f/src/base.rs diff --git a/src/spirv_ctx.rs b/src/spirv_ctx.rs new file mode 100644 index 0000000000..b08d174e04 --- /dev/null +++ b/src/spirv_ctx.rs @@ -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, + type_bool: Option, + type_int: HashMap<(u32, u32), Word>, + type_float: HashMap, + type_function: HashMap<(Word, Vec), 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 { + 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) + }) + } +} diff --git a/src/trans.rs b/src/trans.rs new file mode 100644 index 0000000000..46b6d096a7 --- /dev/null +++ b/src/trans.rs @@ -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 { + 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), + } + } +} diff --git a/tests/empty.rs b/tests/empty.rs index 2f9d590ed4..251b2ca8d3 100644 --- a/tests/empty.rs +++ b/tests/empty.rs @@ -34,7 +34,5 @@ struct Jasper { } pub fn jasper() { - let _ktest = Jasper { - data: 666666 - }; + let _ktest = Jasper { data: 666666 }; }