diff --git a/ptx/src/ptx.lalrpop b/ptx/src/ptx.lalrpop index b051b79..52c4c2c 100644 --- a/ptx/src/ptx.lalrpop +++ b/ptx/src/ptx.lalrpop @@ -403,6 +403,8 @@ Operand: ast::Operand<'input> = { let offset = offset.unwrap_with(errors); ast::Operand::RegOffset(r, offset) }, + // TODO: start parsing whole constants sub-language: + // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#constants => { let offset = o.parse::(); let offset = offset.unwrap_with(errors); diff --git a/ptx/src/translate.rs b/ptx/src/translate.rs index 3f7ce9d..15782bf 100644 --- a/ptx/src/translate.rs +++ b/ptx/src/translate.rs @@ -1,6 +1,5 @@ use crate::ast; use rspirv::dr; -use std::collections::hash_map::Entry; use std::collections::HashMap; #[derive(PartialEq, Eq, Hash, Clone, Copy)] @@ -59,7 +58,9 @@ impl TypeWordMap { struct IdWordMap<'a>(HashMap<&'a str, spirv::Word>); impl<'a> IdWordMap<'a> { - fn new() -> Self { IdWordMap(HashMap::new()) } + fn new() -> Self { + IdWordMap(HashMap::new()) + } } impl<'a> IdWordMap<'a> { @@ -128,7 +129,7 @@ fn emit_function<'a>( builder.begin_block(Some(id))?; } ast::Statement::Variable(var) => panic!(), - ast::Statement::Instruction(_,_) => panic!(), + ast::Statement::Instruction(_, _) => panic!(), } } builder.ret()?; @@ -136,22 +137,218 @@ fn emit_function<'a>( Ok(()) } +// TODO: support scopes +fn normalize_identifiers<'a>(func: Vec>) -> Vec { + let mut result = Vec::with_capacity(func.len()); + let mut id: u32 = 0; + let mut known_ids = HashMap::new(); + let mut get_or_add = |key| { + *known_ids.entry(key).or_insert_with(|| { + id += 1; + id + }) + }; + for s in func { + if let Some(s) = Statement::from_ast(s, &mut get_or_add) { + result.push(s); + } + } + result +} + +fn ssa_legalize(func: Vec) -> Vec { + vec![] +} + enum Statement { - Label, - Instruction(Instruction), - Phi(Vec) + Label(u32), + Instruction(Option, Instruction), + Phi(Vec), +} + +impl Statement { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(s: ast::Statement<'a>, f: &mut F) -> Option { + match s { + ast::Statement::Label(name) => Some(Statement::Label(f(name))), + ast::Statement::Instruction(p, i) => Some(Statement::Instruction( + p.map(|p| PredAt::from_ast(p, f)), + Instruction::from_ast(i, f), + )), + ast::Statement::Variable(_) => None, + } + } +} + +struct PredAt { + pub not: bool, + pub label: u32, +} + +impl PredAt { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(p: ast::PredAt<'a>, f: &mut F) -> Self { + PredAt { + not: p.not, + label: f(p.label), + } + } } enum Instruction { - Ld, - Mov, - Mul, - Add, - Setp, - Not, - Bra, - Cvt, - Shl, - At, - Ret, -} \ No newline at end of file + Ld(ast::LdData, Arg2), + Mov(ast::MovData, Arg2Mov), + Mul(ast::MulData, Arg3), + Add(ast::AddData, Arg3), + Setp(ast::SetpData, Arg4), + SetpBool(ast::SetpBoolData, Arg5), + Not(ast::NotData, Arg2), + Bra(ast::BraData, Arg1), + Cvt(ast::CvtData, Arg2), + Shl(ast::ShlData, Arg3), + St(ast::StData, Arg2), + At(ast::AtData, Arg1), + Ret(ast::RetData), +} + +impl Instruction { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(i: ast::Instruction<'a>, f: &mut F) -> Self { + match i { + ast::Instruction::Ld(d, a) => Instruction::Ld(d, Arg2::from_ast(a, f)), + ast::Instruction::Mov(d, a) => Instruction::Mov(d, Arg2Mov::from_ast(a, f)), + ast::Instruction::Mul(d, a) => Instruction::Mul(d, Arg3::from_ast(a, f)), + ast::Instruction::Add(d, a) => Instruction::Add(d, Arg3::from_ast(a, f)), + ast::Instruction::Setp(d, a) => Instruction::Setp(d, Arg4::from_ast(a, f)), + ast::Instruction::SetpBool(d, a) => Instruction::SetpBool(d, Arg5::from_ast(a, f)), + ast::Instruction::Not(d, a) => Instruction::Not(d, Arg2::from_ast(a, f)), + ast::Instruction::Bra(d, a) => Instruction::Bra(d, Arg1::from_ast(a, f)), + ast::Instruction::Cvt(d, a) => Instruction::Cvt(d, Arg2::from_ast(a, f)), + ast::Instruction::Shl(d, a) => Instruction::Shl(d, Arg3::from_ast(a, f)), + ast::Instruction::St(d, a) => Instruction::St(d, Arg2::from_ast(a, f)), + ast::Instruction::At(d, a) => Instruction::At(d, Arg1::from_ast(a, f)), + ast::Instruction::Ret(d) => Instruction::Ret(d), + } + } +} + +pub struct Arg1 { + pub dst: u32, +} + +impl Arg1 { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(a: ast::Arg1<'a>, f: &mut F) -> Self { + Arg1 { dst: f(a.dst) } + } +} + +pub struct Arg2 { + pub dst: u32, + pub src: Operand, +} + +impl Arg2 { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(a: ast::Arg2<'a>, f: &mut F) -> Self { + Arg2 { + dst: f(a.dst), + src: Operand::from_ast(a.src, f), + } + } +} + +pub struct Arg2Mov { + pub dst: u32, + pub src: MovOperand, +} + +impl Arg2Mov { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(a: ast::Arg2Mov<'a>, f: &mut F) -> Self { + Arg2Mov { + dst: f(a.dst), + src: MovOperand::from_ast(a.src, f), + } + } +} + +pub struct Arg3 { + pub dst: u32, + pub src1: Operand, + pub src2: Operand, +} + +impl Arg3 { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(a: ast::Arg3<'a>, f: &mut F) -> Self { + Arg3 { + dst: f(a.dst), + src1: Operand::from_ast(a.src1, f), + src2: Operand::from_ast(a.src2, f), + } + } +} + +pub struct Arg4 { + pub dst1: u32, + pub dst2: Option, + pub src1: Operand, + pub src2: Operand, +} + +impl Arg4 { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(a: ast::Arg4<'a>, f: &mut F) -> Self { + Arg4 { + dst1: f(a.dst1), + dst2: a.dst2.map(|i| f(i)), + src1: Operand::from_ast(a.src1, f), + src2: Operand::from_ast(a.src2, f), + } + } +} + +pub struct Arg5 { + pub dst1: u32, + pub dst2: Option, + pub src1: Operand, + pub src2: Operand, + pub src3: Operand, +} + +impl Arg5 { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(a: ast::Arg5<'a>, f: &mut F) -> Self { + Arg5 { + dst1: f(a.dst1), + dst2: a.dst2.map(|i| f(i)), + src1: Operand::from_ast(a.src1, f), + src2: Operand::from_ast(a.src2, f), + src3: Operand::from_ast(a.src3, f), + } + } +} + +pub enum Operand { + Reg(u32), + RegOffset(u32, i32), + Imm(i128), +} + +impl Operand { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(a: ast::Operand<'a>, f: &mut F) -> Self { + match a { + ast::Operand::Reg(i) => Operand::Reg(f(i)), + ast::Operand::RegOffset(i, o) => Operand::RegOffset(f(i), o), + ast::Operand::Imm(v) => Operand::Imm(v), + } + } +} + +pub enum MovOperand { + Op(Operand), + Vec(String, String), +} + +impl MovOperand { + fn from_ast<'a, F: FnMut(&'a str) -> u32>(a: ast::MovOperand<'a>, f: &mut F) -> Self { + match a { + ast::MovOperand::Op(o) => MovOperand::Op(Operand::from_ast(o, f)), + ast::MovOperand::Vec(var, idx) => { + MovOperand::Vec(var.to_owned(), idx.to_string()) + } + } + } +}