From e644edab7a0f73c8cac68a671e7580da8c0bd3a4 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Fri, 29 May 2026 19:02:03 -0400 Subject: [PATCH] kraid: Break v9 instruction encoding out into traits This is modeled, again, after what we're doing in NAK. The new traits also allow us to query instruction info from the ISA XML. Part-of: --- src/panfrost/compiler/kraid/encode_v9.rs | 781 +++++++++++++++-------- 1 file changed, 516 insertions(+), 265 deletions(-) diff --git a/src/panfrost/compiler/kraid/encode_v9.rs b/src/panfrost/compiler/kraid/encode_v9.rs index 24f0139a207..24875c62f63 100644 --- a/src/panfrost/compiler/kraid/encode_v9.rs +++ b/src/panfrost/compiler/kraid/encode_v9.rs @@ -13,6 +13,56 @@ use crate::swizzle::*; use paste::paste; use rustc_hash::FxHashMap; +type EncodedInstr = [u32; 2]; +const INSTR_SIZE: i64 = size_of::() as i64; + +trait V9Instr { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo>; + fn encode(&self, encoder: V9Encoder<'_>) -> EncodedInstr; +} + +struct V9Encoder<'a> { + ip: i64, + instr: &'a Instr, + arch: u8, + labels: &'a FxHashMap, +} + +impl V9Encoder<'_> { + fn encode( + &self, + isa_instr: impl TryEncode, + ) -> [u32; 2] { + let fau_page_index = instr_fau_page(&self.instr).unwrap_or(0); + let flow = encode_flow(self.instr.flow, self.arch) + .try_encode(self.arch) + .expect("Failed to encode flow"); + + let mut bits = isa_instr + .try_encode(self.arch) + .expect("Failed to encode instruction"); + + let mut b = BitMutView::new(&mut bits); + b.set_field(57..59, fau_page_index); + b.set_field(59..63, flow); + + bits + } + + fn get_msg_slot_idx(&self) -> Option { + self.instr.flow.get_msg_slot_idx().map(|idx| match idx { + 0 => MessageSlotIndexM::Slot0, + 1 => MessageSlotIndexM::Slot1, + 2 => MessageSlotIndexM::Slot2, + _ => panic!("Invalid message slot index"), + }) + } + + fn get_pc_rel_offset(&self, label: &Label) -> i64 { + self.labels.get(label).unwrap() - (self.ip + INSTR_SIZE) + } +} + fn encode_src_ref(src: &SrcRef, last_use: bool) -> u8 { match src { SrcRef::FAU(fau) => match fau.page { @@ -299,6 +349,371 @@ impl From for AccessStoreM { } } +impl V9Instr for OpBranch { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + Branch::get_info((), arch) + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + e.encode(Branch { + not: self.not.into(), + src0: op_encode_src(self, &self.cond), + combine: match self.combine_op { + BranchCombineOp::None => BranchCombineM::And, + BranchCombineOp::H0 => BranchCombineM::H0, + BranchCombineOp::H1 => BranchCombineM::H1, + BranchCombineOp::And => BranchCombineM::Lowbits, + BranchCombineOp::LowBits => BranchCombineM::None, + }, + conservative: false.into(), + offset: e.get_pc_rel_offset(&self.label), + }) + } +} + +impl V9Instr for OpFAdd { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + if let SrcRef::Imm32(_) = &self.srcs[1].src_ref { + let variant = match self.dst_type { + DataType::F32 => FaddImmVariant::F32, + DataType::V2F16 => FaddImmVariant::V2f16, + _ => return None, + }; + FaddImm::get_info(variant, arch) + } else { + let variant = match self.dst_type { + DataType::F32 => FaddVariant::F32, + DataType::V2F16 => FaddVariant::V2f16, + _ => return None, + }; + Fadd::get_info(variant, arch) + } + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + if let SrcRef::Imm32(imm) = &self.srcs[1].src_ref { + e.encode(FaddImm { + variant: match self.dst_type { + DataType::F32 => FaddImmVariant::F32, + DataType::V2F16 => FaddImmVariant::V2f16, + t => panic!("FADD_IMM.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + src0: op_encode_src(self, &self.srcs[0]), + imm1w: *imm, + }) + } else { + e.encode(Fadd { + variant: match self.dst_type { + DataType::F32 => FaddVariant::F32, + DataType::V2F16 => FaddVariant::V2f16, + t => panic!("FADD.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + src0: op_encode_src(self, &self.srcs[0]), + src1: op_encode_src(self, &self.srcs[1]), + clamp: ClampM::None, + round: Round::None, + sticky: false.into(), + }) + } + } +} + +impl V9Instr for OpFCmp { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + let variant = match self.src_type { + DataType::F32 => FcmpVariant::F32, + DataType::V2F16 => FcmpVariant::V2f16, + _ => return None, + }; + Fcmp::get_info(variant, arch) + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + e.encode(Fcmp { + variant: match self.src_type { + DataType::F32 => FcmpVariant::F32, + DataType::V2F16 => FcmpVariant::V2f16, + t => panic!("FCMP.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + src0: op_encode_src(self, &self.srcs[0]), + src1: op_encode_src(self, &self.srcs[1]), + cmpf: match self.cmp_op { + CmpOp::Eq => CmpfM::Eq, + CmpOp::Gt => CmpfM::Gt, + CmpOp::Ge => CmpfM::Ge, + CmpOp::Ne => CmpfM::Ne, + CmpOp::Lt => CmpfM::Lt, + CmpOp::Le => CmpfM::Le, + CmpOp::GtLt => CmpfM::Gtlt, + CmpOp::Total => CmpfM::Total, + }, + result_type: CmpResultTypeM::M1, + }) + } +} + +impl V9Instr for OpIAdd { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + if let SrcRef::Imm32(_) = &self.srcs[1].src_ref { + let variant = match self.dst_type { + DataType::I32 => IaddImmVariant::I32, + DataType::V2I16 => IaddImmVariant::V2i16, + DataType::V4I8 => IaddImmVariant::V4i8, + _ => return None, + }; + IaddImm::get_info(variant, arch) + } else { + let variant = match self.dst_type { + DataType::S32 => IaddVariant::S32, + DataType::S64 => IaddVariant::S64, + DataType::U32 => IaddVariant::U32, + DataType::U64 => IaddVariant::U64, + DataType::V2S16 => IaddVariant::V2s16, + DataType::V2U16 => IaddVariant::V2u16, + DataType::V4S8 => IaddVariant::V4s8, + DataType::V4U8 => IaddVariant::V4u8, + _ => return None, + }; + Iadd::get_info(variant, arch) + } + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + if let SrcRef::Imm32(imm) = &self.srcs[1].src_ref { + e.encode(IaddImm { + variant: match self.dst_type { + DataType::I32 => IaddImmVariant::I32, + DataType::V2I16 => IaddImmVariant::V2i16, + DataType::V4I8 => IaddImmVariant::V4i8, + t => panic!("IADD_IMM.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + src0: op_encode_src(self, &self.srcs[0]), + imm1w: *imm, + }) + } else { + e.encode(Iadd { + variant: match self.dst_type { + DataType::S32 => IaddVariant::S32, + DataType::S64 => IaddVariant::S64, + DataType::U32 => IaddVariant::U32, + DataType::U64 => IaddVariant::U64, + DataType::V2S16 => IaddVariant::V2s16, + DataType::V2U16 => IaddVariant::V2u16, + DataType::V4S8 => IaddVariant::V4s8, + DataType::V4U8 => IaddVariant::V4u8, + t => panic!("IADD.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + src0: op_encode_src(self, &self.srcs[0]), + src1: op_encode_src(self, &self.srcs[1]), + saturate: self.saturate.into(), + }) + } + } +} + +impl V9Instr for OpICmp { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + let variant = match self.src_type { + DataType::S32 => IcmpVariant::S32, + DataType::U32 => IcmpVariant::U32, + DataType::V2S16 => IcmpVariant::V2s16, + DataType::V2U16 => IcmpVariant::V2u16, + _ => return None, + }; + Icmp::get_info(variant, arch) + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + e.encode(Icmp { + variant: match self.src_type { + DataType::S32 => IcmpVariant::S32, + DataType::U32 => IcmpVariant::U32, + DataType::V2S16 => IcmpVariant::V2s16, + DataType::V2U16 => IcmpVariant::V2u16, + t => panic!("FCMP.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + src0: op_encode_src(self, &self.srcs[0]), + src1: op_encode_src(self, &self.srcs[1]), + cmpf: match self.cmp_op { + CmpOp::Eq => CmpfM::Eq, + CmpOp::Gt => CmpfM::Gt, + CmpOp::Ge => CmpfM::Ge, + CmpOp::Ne => CmpfM::Ne, + CmpOp::Lt => CmpfM::Lt, + CmpOp::Le => CmpfM::Le, + cmp_op => panic!("Unsupported comparison: {cmp_op}"), + }, + result_type: CmpResultTypeM::M1, + }) + } +} + +impl V9Instr for OpLdPka { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + let variant = match self.dst_type { + DataType::I8 => LdPkaVariant::I8, + DataType::I16 => LdPkaVariant::I16, + DataType::I24 => LdPkaVariant::I24, + DataType::I32 => LdPkaVariant::I32, + DataType::I48 => LdPkaVariant::I48, + DataType::I64 => LdPkaVariant::I64, + DataType::I96 => LdPkaVariant::I96, + DataType::I128 => LdPkaVariant::I128, + _ => return None, + }; + LdPka::get_info(variant, arch) + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + e.encode(LdPka { + variant: match self.dst_type { + DataType::I8 => LdPkaVariant::I8, + DataType::I16 => LdPkaVariant::I16, + DataType::I24 => LdPkaVariant::I24, + DataType::I32 => LdPkaVariant::I32, + DataType::I48 => LdPkaVariant::I48, + DataType::I64 => LdPkaVariant::I64, + DataType::I96 => LdPkaVariant::I96, + DataType::I128 => LdPkaVariant::I128, + t => panic!("LD_PKA.{t} not supported"), + }, + access: self.access.into(), + extend: SignExtendOrNoneM::None, + message_slot_index: e.get_msg_slot_idx().unwrap(), + sr_dst: op_encode_sr_write(self, &self.dst), + src0: op_encode_src(self, &self.offset), + src1: op_encode_src(self, &self.handle), + }) + } +} + +impl V9Instr for OpLeaPka { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + LeaPka::get_info((), arch) + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + e.encode(LeaPka { + message_slot_index: e.get_msg_slot_idx().unwrap(), + sr_dst: op_encode_sr_write(self, &self.dst), + src0: op_encode_src(self, &self.offset), + src1: op_encode_src(self, &self.handle), + }) + } +} + +impl V9Instr for OpLoad { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + let variant = match self.dst_type { + DataType::I8 => LoadVariant::I8, + DataType::I16 => LoadVariant::I16, + DataType::I24 => LoadVariant::I24, + DataType::I32 => LoadVariant::I32, + DataType::I48 => LoadVariant::I48, + DataType::I64 => LoadVariant::I64, + DataType::I96 => LoadVariant::I96, + DataType::I128 => LoadVariant::I128, + _ => return None, + }; + Load::get_info(variant, arch) + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + e.encode(Load { + variant: match self.dst_type { + DataType::I8 => LoadVariant::I8, + DataType::I16 => LoadVariant::I16, + DataType::I24 => LoadVariant::I24, + DataType::I32 => LoadVariant::I32, + DataType::I48 => LoadVariant::I48, + DataType::I64 => LoadVariant::I64, + DataType::I96 => LoadVariant::I96, + DataType::I128 => LoadVariant::I128, + t => panic!("LOAD.{t} not supported"), + }, + access: self.access.into(), + extend: SignExtendOrNoneM::None, + message_slot_index: e.get_msg_slot_idx().unwrap(), + sr_dst: op_encode_sr_write(self, &self.dst), + src0: op_encode_src(self, &self.addr), + offset: self.offset, + }) + } +} + +impl V9Instr for OpMov { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + if let SrcRef::Imm32(_) = &self.src.src_ref { + let variant = match self.dst_type { + DataType::I16 => MovImmVariant::V2i16, + DataType::I32 => MovImmVariant::I32, + _ => return None, + }; + MovImm::get_info(variant, arch) + } else { + let variant = match self.dst_type { + DataType::I32 => MovVariant::I32, + _ => return None, + }; + Mov::get_info(variant, arch) + } + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + if let SrcRef::Imm32(imm) = &self.src.src_ref { + e.encode(MovImm { + variant: match self.dst_type { + DataType::I16 => MovImmVariant::V2i16, + DataType::I32 => MovImmVariant::I32, + t => panic!("MOV_IMM.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + imm1w: *imm, + }) + } else { + e.encode(Mov { + variant: match self.dst_type { + DataType::I32 => MovVariant::I32, + t => panic!("MOV.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + src0: op_encode_src(self, &self.src), + }) + } + } +} + +impl V9Instr for OpNop { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + Nop::get_info((), arch) + } + + fn encode(&self, e: V9Encoder) -> EncodedInstr { + e.encode(Nop {}) + } +} + +macro_rules! shift_lop_info { + ($op:expr, $Instr:ident, $arch:expr) => { + paste! {{ + let variant = match $op.dst_type { + DataType::I32 => [<$Instr Variant>]::I32, + DataType::I64 => [<$Instr Variant>]::I64, + DataType::V2I16 => [<$Instr Variant>]::V2i16, + DataType::V4I8 => [<$Instr Variant>]::V4i8, + _ => return None, + }; + $Instr::get_info(variant, $arch) + }} + }; +} + macro_rules! shift_lop_as { ($op:expr, $Instr:ident) => { paste! { @@ -320,268 +735,72 @@ macro_rules! shift_lop_as { }; } -struct InstrEnc { - arch: u8, - fau_page_index: u8, - flow: FlowControlM, -} +impl V9Instr for OpShiftLop { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + use LogicOp::*; + use ShiftOp::*; + match (self.shift_op, self.logic_op) { + (LShift, And) => shift_lop_info!(self, LshiftAnd, arch), + (LShift, Or) => shift_lop_info!(self, LshiftOr, arch), + (LShift, Xor) => shift_lop_info!(self, LshiftXor, arch), + (RShift, And) => shift_lop_info!(self, RshiftAnd, arch), + (RShift, Or) => shift_lop_info!(self, RshiftOr, arch), + (RShift, Xor) => shift_lop_info!(self, RshiftXor, arch), + (ARShift, _) => shift_lop_info!(self, Arshift, arch), + _ => None, + } + } -impl InstrEnc { - fn encode( - self, - instr: impl TryEncode, - ) -> [u32; 2] { - let mut bits = instr - .try_encode(self.arch) - .expect("Failed to encode instruction"); - let flow = self - .flow - .try_encode(self.arch) - .expect("Failed to encode flow"); - - let mut b = BitMutView::new(&mut bits); - b.set_field(57..59, self.fau_page_index); - b.set_field(59..63, flow); - - bits + fn encode(&self, e: V9Encoder) -> EncodedInstr { + use LogicOp::*; + use ShiftOp::*; + match (self.shift_op, self.logic_op) { + (LShift, And) => e.encode(shift_lop_as!(self, LshiftAnd)), + (LShift, Or) => e.encode(shift_lop_as!(self, LshiftOr)), + (LShift, Xor) => e.encode(shift_lop_as!(self, LshiftXor)), + (RShift, And) => e.encode(shift_lop_as!(self, RshiftAnd)), + (RShift, Or) => e.encode(shift_lop_as!(self, RshiftOr)), + (RShift, Xor) => e.encode(shift_lop_as!(self, RshiftXor)), + (ARShift, _) => { + assert!(self.shift.is_zero()); + e.encode(Arshift { + variant: match self.dst_type { + DataType::I32 => ArshiftVariant::I32, + DataType::I64 => ArshiftVariant::I64, + DataType::V2I16 => ArshiftVariant::V2i16, + DataType::V4I8 => ArshiftVariant::V4i8, + t => panic!("SHIFT_LOP.{t} not supported"), + }, + dst: op_encode_dst(self, &self.dst), + not_result: self.not_result.into(), + src0: op_encode_src(self, &self.src0), + src1: op_encode_src(self, &self.shift), + }) + } + _ => todo!("Implement [lr]rot"), + } } } -fn encode_instr( - ip: i64, - instr: &Instr, - arch: u8, - labels: &FxHashMap, -) -> [u32; 2] { - let msg_slot_idx = instr.flow.get_msg_slot_idx().map(|idx| match idx { - 0 => MessageSlotIndexM::Slot0, - 1 => MessageSlotIndexM::Slot1, - 2 => MessageSlotIndexM::Slot2, - _ => panic!("Invalid message slot"), - }); +impl V9Instr for OpStore { + fn get_info(&self, arch: u8) -> Option<&'static InstructionInfo> { + let variant = match self.src_type { + DataType::I8 => StoreVariant::I8, + DataType::I16 => StoreVariant::I16, + DataType::I24 => StoreVariant::I24, + DataType::I32 => StoreVariant::I32, + DataType::I48 => StoreVariant::I48, + DataType::I64 => StoreVariant::I64, + DataType::I96 => StoreVariant::I96, + DataType::I128 => StoreVariant::I128, + _ => return None, + }; + Store::get_info(variant, arch) + } - let enc = InstrEnc { - arch, - fau_page_index: instr_fau_page(instr).unwrap_or(0), - flow: encode_flow(instr.flow, arch), - }; - - match &instr.op { - Op::Branch(op) => enc.encode(Branch { - not: op.not.into(), - src0: op_encode_src(op, &op.cond), - combine: match op.combine_op { - BranchCombineOp::None => BranchCombineM::And, - BranchCombineOp::H0 => BranchCombineM::H0, - BranchCombineOp::H1 => BranchCombineM::H1, - BranchCombineOp::And => BranchCombineM::Lowbits, - BranchCombineOp::LowBits => BranchCombineM::None, - }, - conservative: false.into(), - offset: labels.get(&op.label).unwrap() - (ip + INSTR_SIZE), - }), - Op::FAdd(op) => { - if let SrcRef::Imm32(imm) = &op.srcs[1].src_ref { - enc.encode(FaddImm { - variant: match op.dst_type { - DataType::F32 => FaddImmVariant::F32, - DataType::V2F16 => FaddImmVariant::V2f16, - t => panic!("FADD_IMM.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - src0: op_encode_src(op, &op.srcs[0]), - imm1w: *imm, - }) - } else { - enc.encode(Fadd { - variant: match op.dst_type { - DataType::F32 => FaddVariant::F32, - DataType::V2F16 => FaddVariant::V2f16, - t => panic!("FADD.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - src0: op_encode_src(op, &op.srcs[0]), - src1: op_encode_src(op, &op.srcs[1]), - clamp: ClampM::None, - round: Round::None, - sticky: false.into(), - }) - } - } - Op::FCmp(op) => enc.encode(Fcmp { - variant: match op.src_type { - DataType::F32 => FcmpVariant::F32, - DataType::V2F16 => FcmpVariant::V2f16, - t => panic!("FCMP.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - src0: op_encode_src(op, &op.srcs[0]), - src1: op_encode_src(op, &op.srcs[1]), - cmpf: match op.cmp_op { - CmpOp::Eq => CmpfM::Eq, - CmpOp::Gt => CmpfM::Gt, - CmpOp::Ge => CmpfM::Ge, - CmpOp::Ne => CmpfM::Ne, - CmpOp::Lt => CmpfM::Lt, - CmpOp::Le => CmpfM::Le, - CmpOp::GtLt => CmpfM::Gtlt, - CmpOp::Total => CmpfM::Total, - }, - result_type: CmpResultTypeM::M1, - }), - Op::IAdd(op) => { - if let SrcRef::Imm32(imm) = &op.srcs[1].src_ref { - enc.encode(IaddImm { - variant: match op.dst_type { - DataType::I32 => IaddImmVariant::I32, - DataType::V2I16 => IaddImmVariant::V2i16, - DataType::V4I8 => IaddImmVariant::V4i8, - t => panic!("IADD_IMM.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - src0: op_encode_src(op, &op.srcs[0]), - imm1w: *imm, - }) - } else { - enc.encode(Iadd { - variant: match op.dst_type { - DataType::S32 => IaddVariant::S32, - DataType::S64 => IaddVariant::S64, - DataType::U32 => IaddVariant::U32, - DataType::U64 => IaddVariant::U64, - DataType::V2S16 => IaddVariant::V2s16, - DataType::V2U16 => IaddVariant::V2u16, - DataType::V4S8 => IaddVariant::V4s8, - DataType::V4U8 => IaddVariant::V4u8, - t => panic!("IADD.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - src0: op_encode_src(op, &op.srcs[0]), - src1: op_encode_src(op, &op.srcs[1]), - saturate: op.saturate.into(), - }) - } - } - Op::ICmp(op) => enc.encode(Icmp { - variant: match op.src_type { - DataType::S32 => IcmpVariant::S32, - DataType::U32 => IcmpVariant::U32, - DataType::V2S16 => IcmpVariant::V2s16, - DataType::V2U16 => IcmpVariant::V2u16, - t => panic!("FCMP.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - src0: op_encode_src(op, &op.srcs[0]), - src1: op_encode_src(op, &op.srcs[1]), - cmpf: match op.cmp_op { - CmpOp::Eq => CmpfM::Eq, - CmpOp::Gt => CmpfM::Gt, - CmpOp::Ge => CmpfM::Ge, - CmpOp::Ne => CmpfM::Ne, - CmpOp::Lt => CmpfM::Lt, - CmpOp::Le => CmpfM::Le, - cmp_op => panic!("Unsupported comparison: {cmp_op}"), - }, - result_type: CmpResultTypeM::M1, - }), - Op::LdPka(op) => enc.encode(LdPka { - variant: match op.dst_type { - DataType::I8 => LdPkaVariant::I8, - DataType::I16 => LdPkaVariant::I16, - DataType::I24 => LdPkaVariant::I24, - DataType::I32 => LdPkaVariant::I32, - DataType::I48 => LdPkaVariant::I48, - DataType::I64 => LdPkaVariant::I64, - DataType::I96 => LdPkaVariant::I96, - DataType::I128 => LdPkaVariant::I128, - t => panic!("LD_PKA.{t} not supported"), - }, - access: op.access.into(), - extend: SignExtendOrNoneM::None, - message_slot_index: msg_slot_idx.unwrap(), - sr_dst: op_encode_sr_write(op, &op.dst), - src0: op_encode_src(op, &op.offset), - src1: op_encode_src(op, &op.handle), - }), - Op::LeaPka(op) => enc.encode(LeaPka { - message_slot_index: msg_slot_idx.unwrap(), - sr_dst: op_encode_sr_write(op, &op.dst), - src0: op_encode_src(op, &op.offset), - src1: op_encode_src(op, &op.handle), - }), - Op::Load(op) => enc.encode(Load { - variant: match op.dst_type { - DataType::I8 => LoadVariant::I8, - DataType::I16 => LoadVariant::I16, - DataType::I24 => LoadVariant::I24, - DataType::I32 => LoadVariant::I32, - DataType::I48 => LoadVariant::I48, - DataType::I64 => LoadVariant::I64, - DataType::I96 => LoadVariant::I96, - DataType::I128 => LoadVariant::I128, - t => panic!("LOAD.{t} not supported"), - }, - access: op.access.into(), - extend: SignExtendOrNoneM::None, - message_slot_index: msg_slot_idx.unwrap(), - sr_dst: op_encode_sr_write(op, &op.dst), - src0: op_encode_src(op, &op.addr), - offset: op.offset, - }), - Op::Mov(op) => { - if let SrcRef::Imm32(imm) = &op.src.src_ref { - enc.encode(MovImm { - variant: match op.dst_type { - DataType::I16 => MovImmVariant::V2i16, - DataType::I32 => MovImmVariant::I32, - t => panic!("MOV_IMM.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - imm1w: *imm, - }) - } else { - enc.encode(Mov { - variant: match op.dst_type { - DataType::I32 => MovVariant::I32, - t => panic!("MOV.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - src0: op_encode_src(op, &op.src), - }) - } - } - Op::Nop(_) => enc.encode(Nop {}), - Op::ShiftLop(op) => { - use LogicOp::*; - use ShiftOp::*; - match (op.shift_op, op.logic_op) { - (LShift, And) => enc.encode(shift_lop_as!(op, LshiftAnd)), - (LShift, Or) => enc.encode(shift_lop_as!(op, LshiftOr)), - (LShift, Xor) => enc.encode(shift_lop_as!(op, LshiftXor)), - (RShift, And) => enc.encode(shift_lop_as!(op, RshiftAnd)), - (RShift, Or) => enc.encode(shift_lop_as!(op, RshiftOr)), - (RShift, Xor) => enc.encode(shift_lop_as!(op, RshiftXor)), - (ARShift, _) => { - assert!(op.shift.is_zero()); - enc.encode(Arshift { - variant: match op.dst_type { - DataType::I32 => ArshiftVariant::I32, - DataType::I64 => ArshiftVariant::I64, - DataType::V2I16 => ArshiftVariant::V2i16, - DataType::V4I8 => ArshiftVariant::V4i8, - t => panic!("SHIFT_LOP.{t} not supported"), - }, - dst: op_encode_dst(op, &op.dst), - not_result: op.not_result.into(), - src0: op_encode_src(op, &op.src0), - src1: op_encode_src(op, &op.shift), - }) - } - _ => todo!("Implement [lr]rot"), - } - } - Op::Store(op) => enc.encode(Store { - variant: match op.src_type { + fn encode(&self, e: V9Encoder) -> EncodedInstr { + e.encode(Store { + variant: match self.src_type { DataType::I8 => StoreVariant::I8, DataType::I16 => StoreVariant::I16, DataType::I24 => StoreVariant::I24, @@ -592,17 +811,49 @@ fn encode_instr( DataType::I128 => StoreVariant::I128, t => panic!("LOAD.{t} not supported"), }, - access: op.access.into(), - message_slot_index: msg_slot_idx.unwrap(), - sr_src: op_encode_sr_read(op, &op.data), - src0: op_encode_src(op, &op.addr), - offset: op.offset, - }), - op => panic!("Instruction not encoded: {op}"), + access: self.access.into(), + message_slot_index: e.get_msg_slot_idx().unwrap(), + sr_src: op_encode_sr_read(self, &self.data), + src0: op_encode_src(self, &self.addr), + offset: self.offset, + }) } } -const INSTR_SIZE: i64 = size_of::<::Encoded>() as i64; +macro_rules! v9_op_match { + ($op: expr, |$x: ident| $y: expr) => { + match $op { + Op::Branch($x) => $y, + Op::FAdd($x) => $y, + Op::FCmp($x) => $y, + Op::IAdd($x) => $y, + Op::ICmp($x) => $y, + Op::LdPka($x) => $y, + Op::LeaPka($x) => $y, + Op::Load($x) => $y, + Op::Mov($x) => $y, + Op::Nop($x) => $y, + Op::ShiftLop($x) => $y, + Op::Store($x) => $y, + _ => panic!("Unsupported op: {}", $op), + } + }; +} + +fn encode_instr( + ip: i64, + instr: &Instr, + arch: u8, + labels: &FxHashMap, +) -> [u32; 2] { + let e = V9Encoder { + ip, + instr, + arch, + labels, + }; + v9_op_match!(&instr.op, |op| op.encode(e)) +} pub fn encode_v9(s: &Shader<'_>, arch: u8) -> Vec { let mut labels = FxHashMap::default();