global_asm! start

This commit is contained in:
Jasper Bekkers 2021-02-04 18:36:44 +01:00
parent 8a68551a06
commit c0213eb229
No known key found for this signature in database
GPG Key ID: 2F16E81D61CAEF01
4 changed files with 159 additions and 24 deletions

View File

@ -29,7 +29,8 @@ use-compiled-tools = ["spirv-tools/use-compiled-tools"]
[dependencies] [dependencies]
bimap = "0.6" bimap = "0.6"
indexmap = "1.6.0" indexmap = "1.6.0"
rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "7111e6c5a8bb43563d280825fa65623032ee052d" } #rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "7111e6c5a8bb43563d280825fa65623032ee052d" }
rspirv = { path = "c:/users/jasper/embark/rspirv/rspirv" }
rustc-demangle = "0.1.18" rustc-demangle = "0.1.18"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"

View File

@ -2,7 +2,7 @@ mod builder_methods;
mod ext_inst; mod ext_inst;
mod intrinsics; mod intrinsics;
pub mod libm_intrinsics; pub mod libm_intrinsics;
mod spirv_asm; pub mod spirv_asm;
pub use ext_inst::ExtInst; pub use ext_inst::ExtInst;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;

View File

@ -98,7 +98,7 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
tokens.push(vec![]); tokens.push(vec![]);
} }
let mut chars = line.chars(); let mut chars = line.chars();
while let Some(token) = self.lex_word(&mut chars) { while let Some(token) = InlineAsmCx::Local(self).lex_word(&mut chars) {
tokens.last_mut().unwrap().push(token); tokens.last_mut().unwrap().push(token);
} }
} }
@ -132,25 +132,35 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
} }
let mut id_map = HashMap::new(); let mut id_map = HashMap::new();
let mut id_to_type_map = HashMap::new(); let global_id_map = self.cx.global_asm_id_map.borrow();
for (k, v) in global_id_map.iter() {
id_map.insert(k.as_str(), *v);
}
let mut id_to_type_map = self.cx.global_asm_id_to_type_map.borrow().clone();
for operand in operands { for operand in operands {
if let InlineAsmOperandRef::In { reg: _, value } = operand { if let InlineAsmOperandRef::In { reg: _, value } = operand {
let value = value.immediate(); let value = value.immediate();
id_to_type_map.insert(value.def(self), value.ty); id_to_type_map.insert(value.def(self), value.ty);
} }
} }
for line in tokens { for line in tokens {
self.codegen_asm(&mut id_map, &mut id_to_type_map, line.into_iter()); InlineAsmCx::Local(self).codegen_asm(
&mut id_map,
&mut id_to_type_map,
line.into_iter(),
);
} }
} }
} }
enum TypeofKind { pub enum TypeofKind {
Plain, Plain,
Dereference, Dereference,
} }
enum Token<'a, 'cx, 'tcx> { pub enum Token<'a, 'cx, 'tcx> {
Word(&'a str), Word(&'a str),
String(String), String(String),
Placeholder(&'a InlineAsmOperandRef<'tcx, Builder<'cx, 'tcx>>, Span), Placeholder(&'a InlineAsmOperandRef<'tcx, Builder<'cx, 'tcx>>, Span),
@ -166,8 +176,56 @@ enum OutRegister<'a> {
Place(PlaceRef<'a, SpirvValue>), Place(PlaceRef<'a, SpirvValue>),
} }
impl<'cx, 'tcx> Builder<'cx, 'tcx> { pub enum InlineAsmCx<'a, 'cx, 'tcx> {
fn lex_word<'a>(&self, line: &mut std::str::Chars<'a>) -> Option<Token<'a, 'cx, 'tcx>> { Global(&'cx CodegenCx<'tcx>, Span),
Local(&'a mut Builder<'cx, 'tcx>),
}
impl<'cx, 'tcx> std::ops::Deref for InlineAsmCx<'_, 'cx, 'tcx> {
type Target = &'cx CodegenCx<'tcx>;
fn deref(&self) -> &Self::Target {
match self {
Self::Global(cx, _) | Self::Local(Builder { cx, .. }) => cx,
}
}
}
impl InlineAsmCx<'_, '_, '_> {
fn span(&self) -> Span {
match self {
&Self::Global(_, span) => span,
Self::Local(bx) => bx.span(),
}
}
fn err(&self, msg: &str) {
self.tcx.sess.span_err(self.span(), msg)
}
fn emit(&self) -> std::cell::RefMut<'_, rspirv::dr::Builder> {
match self {
Self::Global(cx, _) => cx.emit_global(),
Self::Local(bx) => bx.emit(),
}
}
fn emit_append(&self, inst: dr::Instruction){
match self {
Self::Global(cx, _) => cx.emit_global().insert_types_global_values(dr::InsertPoint::End, inst),
Self::Local(bx) => bx.emit().insert_into_block(dr::InsertPoint::End, inst).unwrap(),
}
}
fn emit_global(&self, inst: dr::Instruction){
match self {
Self::Global(cx, _) => cx.emit_global().insert_types_global_values(dr::InsertPoint::End, inst),
Self::Local(bx) => bx.emit_global().insert_types_global_values(dr::InsertPoint::End, inst),
}
}
}
impl<'cx, 'tcx> InlineAsmCx<'_, 'cx, 'tcx> {
pub fn lex_word<'a>(&self, line: &mut std::str::Chars<'a>) -> Option<Token<'a, 'cx, 'tcx>> {
loop { loop {
let start = line.as_str(); let start = line.as_str();
match line.next()? { match line.next()? {
@ -228,6 +286,8 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
fn insert_inst(&mut self, id_map: &mut HashMap<&str, Word>, inst: dr::Instruction) { fn insert_inst(&mut self, id_map: &mut HashMap<&str, Word>, inst: dr::Instruction) {
// Types declared must be registered in our type system. // Types declared must be registered in our type system.
println!("{:?}", &inst);
let new_result_id = match inst.class.opcode { let new_result_id = match inst.class.opcode {
Op::TypeVoid => SpirvType::Void.def(self.span(), self), Op::TypeVoid => SpirvType::Void.def(self.span(), self),
Op::TypeBool => SpirvType::Bool.def(self.span(), self), Op::TypeBool => SpirvType::Bool.def(self.span(), self),
@ -255,15 +315,34 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
Op::TypeArray => { Op::TypeArray => {
self.err("OpTypeArray in asm! is not supported yet"); self.err("OpTypeArray in asm! is not supported yet");
return; return;
} },
Op::TypeRuntimeArray => SpirvType::RuntimeArray {
element: inst.operands[0].unwrap_id_ref()
}.def(self.span(), self),
Op::TypePointer => SpirvType::Pointer {
storage_class: inst.operands[0].unwrap_storage_class(),
pointee: inst.operands[1].unwrap_id_ref(),
}.def(self.span(), self),
Op::TypeImage => SpirvType::Image {
sampled_type: inst.operands[0].unwrap_id_ref(),
dim: inst.operands[1].unwrap_dim(),
depth: inst.operands[2].unwrap_literal_int32(),
arrayed: inst.operands[3].unwrap_literal_int32(),
multisampled: inst.operands[4].unwrap_literal_int32(),
sampled: inst.operands[5].unwrap_literal_int32(),
image_format: inst.operands[6].unwrap_image_format(),
access_qualifier: None,
}.def(self.span(), self),
Op::TypeSampledImage => SpirvType::SampledImage { Op::TypeSampledImage => SpirvType::SampledImage {
image_type: inst.operands[0].unwrap_id_ref(), image_type: inst.operands[0].unwrap_id_ref(),
} }
.def(self.span(), self), .def(self.span(), self),
Op::Variable => {
self.emit_global(inst);
return;
},
_ => { _ => {
self.emit() self.emit_append(inst);
.insert_into_block(dr::InsertPoint::End, inst)
.unwrap();
return; return;
} }
}; };
@ -274,7 +353,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
} }
} }
fn codegen_asm<'a>( pub fn codegen_asm<'a>(
&mut self, &mut self,
id_map: &mut HashMap<&'a str, Word>, id_map: &mut HashMap<&'a str, Word>,
id_to_type_map: &mut HashMap<Word, Word>, id_to_type_map: &mut HashMap<Word, Word>,
@ -358,13 +437,12 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
} }
self.insert_inst(id_map, instruction); self.insert_inst(id_map, instruction);
if let Some(OutRegister::Place(place)) = out_register { if let Some(OutRegister::Place(place)) = out_register {
let place = match self {
Self::Global(..) => unreachable!(),
Self::Local(bx) => place.llval.def(bx),
};
self.emit() self.emit()
.store( .store(place, result_id.unwrap(), None, std::iter::empty())
place.llval.def(self),
result_id.unwrap(),
None,
std::iter::empty(),
)
.unwrap(); .unwrap();
} }
} }
@ -755,7 +833,10 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
Token::Placeholder(hole, span) => match hole { Token::Placeholder(hole, span) => match hole {
InlineAsmOperandRef::In { reg, value } => { InlineAsmOperandRef::In { reg, value } => {
self.check_reg(span, reg); self.check_reg(span, reg);
Some(value.immediate().def(self)) match self {
Self::Global(..) => unreachable!(),
Self::Local(bx) => Some(value.immediate().def(bx)),
}
} }
InlineAsmOperandRef::Out { InlineAsmOperandRef::Out {
reg, reg,
@ -775,7 +856,10 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
out_place: _, out_place: _,
} => { } => {
self.check_reg(span, reg); self.check_reg(span, reg);
Some(in_value.immediate().def(self)) match self {
Self::Global(..) => unreachable!(),
Self::Local(bx) => Some(in_value.immediate().def(bx)),
}
} }
InlineAsmOperandRef::Const { string: _ } => { InlineAsmOperandRef::Const { string: _ } => {
self.tcx self.tcx
@ -890,6 +974,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
_ => return Err("expected number literal in OpConstant".to_string()), _ => return Err("expected number literal in OpConstant".to_string()),
}) })
} }
println!("{} {}", ty, word);
match parse(self.lookup_type(ty), word) { match parse(self.lookup_type(ty), word) {
Ok(op) => inst.operands.push(op), Ok(op) => inst.operands.push(op),
Err(err) => self.err(&err), Err(err) => self.err(&err),

View File

@ -69,6 +69,9 @@ pub struct CodegenCx<'tcx> {
/// Some runtimes (e.g. intel-compute-runtime) disallow atomics on i8 and i16, even though it's allowed by the spec. /// Some runtimes (e.g. intel-compute-runtime) disallow atomics on i8 and i16, even though it's allowed by the spec.
/// This enables/disables them. /// This enables/disables them.
pub i8_i16_atomics_allowed: bool, pub i8_i16_atomics_allowed: bool,
pub global_asm_id_map: RefCell<HashMap<String, Word>>,
pub global_asm_id_to_type_map: RefCell<HashMap<Word, Word>>,
} }
impl<'tcx> CodegenCx<'tcx> { impl<'tcx> CodegenCx<'tcx> {
@ -121,6 +124,8 @@ impl<'tcx> CodegenCx<'tcx> {
panic_fn_id: Default::default(), panic_fn_id: Default::default(),
panic_bounds_check_fn_id: Default::default(), panic_bounds_check_fn_id: Default::default(),
i8_i16_atomics_allowed: false, i8_i16_atomics_allowed: false,
global_asm_id_map: Default::default(),
global_asm_id_to_type_map: Default::default(),
} }
} }
@ -402,8 +407,52 @@ impl<'tcx> CoverageInfoMethods for CodegenCx<'tcx> {
} }
} }
use crate::builder::spirv_asm::InlineAsmCx;
impl<'tcx> AsmMethods for CodegenCx<'tcx> { impl<'tcx> AsmMethods for CodegenCx<'tcx> {
fn codegen_global_asm(&self, _ga: &GlobalAsm) { fn codegen_global_asm(&self, ga: &GlobalAsm) {
todo!() use rustc_span::DUMMY_SP;
// vec of lines, and each line is vec of tokens
let mut tokens = vec![vec![]];
let asm = ga.asm.as_str().to_string();
let lines = asm.split('\n').map(|line| {
let l = line.len();
if l > 0 && line.as_bytes()[l - 1] == b'\r' {
&line[0..l - 1]
} else {
line
}
});
for (index, line) in lines.enumerate() {
if index != 0 {
// There was a newline, add a new line.
tokens.push(vec![]);
}
let mut chars = line.chars();
// passing around DUMMY_SP in here now, because it's unclear how to create a Span from a Symbol
while let Some(token) = InlineAsmCx::Global(self, DUMMY_SP).lex_word(&mut chars) {
tokens.last_mut().unwrap().push(token);
}
}
let mut id_map = HashMap::new();
for line in tokens {
// passing around DUMMY_SP in here now, because it's unclear how to create a Span from a Symbol
InlineAsmCx::Global(self, DUMMY_SP).codegen_asm(
&mut id_map,
&mut self.global_asm_id_to_type_map.borrow_mut(),
line.into_iter(),
);
}
for (k, v) in id_map {
self.global_asm_id_map.borrow_mut().insert(k.to_owned(), v);
}
} }
} }