Path: blob/main/cranelift/codegen/src/isa/riscv64/inst/args.rs
1693 views
//! Riscv64 ISA definitions: instruction arguments.12use super::*;3use crate::ir::condcodes::CondCode;45use crate::isa::riscv64::lower::isle::generated_code::{6COpcodeSpace, CaOp, CbOp, CiOp, CiwOp, ClOp, CrOp, CsOp, CssOp, CsznOp, FpuOPWidth, ZcbMemOp,7};8use crate::machinst::isle::WritableReg;910use std::fmt::Result;1112/// A macro for defining a newtype of `Reg` that enforces some invariant about13/// the wrapped `Reg` (such as that it is of a particular register class).14macro_rules! newtype_of_reg {15(16$newtype_reg:ident,17$newtype_writable_reg:ident,18|$check_reg:ident| $check:expr19) => {20/// A newtype wrapper around `Reg`.21#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]22pub struct $newtype_reg(Reg);2324impl PartialEq<Reg> for $newtype_reg {25fn eq(&self, other: &Reg) -> bool {26self.0 == *other27}28}2930impl From<$newtype_reg> for Reg {31fn from(r: $newtype_reg) -> Self {32r.033}34}3536impl $newtype_reg {37/// Create this newtype from the given register, or return `None` if the register38/// is not a valid instance of this newtype.39pub fn new($check_reg: Reg) -> Option<Self> {40if $check { Some(Self($check_reg)) } else { None }41}4243/// Get this newtype's underlying `Reg`.44pub fn to_reg(self) -> Reg {45self.046}47}4849// Convenience impl so that people working with this newtype can use it50// "just like" a plain `Reg`.51//52// NB: We cannot implement `DerefMut` because that would let people do53// nasty stuff like `*my_xreg.deref_mut() = some_freg`, breaking the54// invariants that `XReg` provides.55impl std::ops::Deref for $newtype_reg {56type Target = Reg;5758fn deref(&self) -> &Reg {59&self.060}61}6263/// Writable Reg.64pub type $newtype_writable_reg = Writable<$newtype_reg>;65};66}6768// Newtypes for registers classes.69newtype_of_reg!(XReg, WritableXReg, |reg| reg.class() == RegClass::Int);70newtype_of_reg!(FReg, WritableFReg, |reg| reg.class() == RegClass::Float);71newtype_of_reg!(VReg, WritableVReg, |reg| reg.class() == RegClass::Vector);7273/// An addressing mode specified for a load/store operation.74#[derive(Clone, Debug, Copy)]75pub enum AMode {76/// Arbitrary offset from a register. Converted to generation of large77/// offsets with multiple instructions as necessary during code emission.78RegOffset(Reg, i64),79/// Offset from the stack pointer.80SPOffset(i64),8182/// Offset from the frame pointer.83FPOffset(i64),8485/// Offset into the slot area of the stack, which lies just above the86/// outgoing argument area that's setup by the function prologue.87/// At emission time, this is converted to `SPOffset` with a fixup added to88/// the offset constant. The fixup is a running value that is tracked as89/// emission iterates through instructions in linear order, and can be90/// adjusted up and down with [Inst::VirtualSPOffsetAdj].91///92/// The standard ABI is in charge of handling this (by emitting the93/// adjustment meta-instructions). See the diagram in the documentation94/// for [crate::isa::aarch64::abi](the ABI module) for more details.95SlotOffset(i64),9697/// Offset into the argument area.98IncomingArg(i64),99100/// A reference to a constant which is placed outside of the function's101/// body, typically at the end.102Const(VCodeConstant),103104/// A reference to a label.105Label(MachLabel),106}107108impl AMode {109/// Add the registers referenced by this AMode to `collector`.110pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {111match self {112AMode::RegOffset(reg, ..) => collector.reg_use(reg),113// Registers used in these modes aren't allocatable.114AMode::SPOffset(..)115| AMode::FPOffset(..)116| AMode::SlotOffset(..)117| AMode::IncomingArg(..)118| AMode::Const(..)119| AMode::Label(..) => {}120}121}122123pub(crate) fn get_base_register(&self) -> Option<Reg> {124match self {125&AMode::RegOffset(reg, ..) => Some(reg),126&AMode::SPOffset(..) => Some(stack_reg()),127&AMode::FPOffset(..) => Some(fp_reg()),128&AMode::SlotOffset(..) => Some(stack_reg()),129&AMode::IncomingArg(..) => Some(stack_reg()),130&AMode::Const(..) | AMode::Label(..) => None,131}132}133134pub(crate) fn get_offset_with_state(&self, state: &EmitState) -> i64 {135match self {136&AMode::SlotOffset(offset) => {137offset + i64::from(state.frame_layout().outgoing_args_size)138}139140// Compute the offset into the incoming argument area relative to SP141&AMode::IncomingArg(offset) => {142let frame_layout = state.frame_layout();143let sp_offset = frame_layout.tail_args_size144+ frame_layout.setup_area_size145+ frame_layout.clobber_size146+ frame_layout.fixed_frame_storage_size147+ frame_layout.outgoing_args_size;148i64::from(sp_offset) - offset149}150151&AMode::RegOffset(_, offset) => offset,152&AMode::SPOffset(offset) => offset,153&AMode::FPOffset(offset) => offset,154&AMode::Const(_) | &AMode::Label(_) => 0,155}156}157158/// Retrieve a MachLabel that corresponds to this addressing mode, if it exists.159pub(crate) fn get_label_with_sink(&self, sink: &mut MachBuffer<Inst>) -> Option<MachLabel> {160match self {161&AMode::Const(addr) => Some(sink.get_label_for_constant(addr)),162&AMode::Label(label) => Some(label),163&AMode::RegOffset(..)164| &AMode::SPOffset(..)165| &AMode::FPOffset(..)166| &AMode::IncomingArg(..)167| &AMode::SlotOffset(..) => None,168}169}170}171172impl Display for AMode {173fn fmt(&self, f: &mut Formatter<'_>) -> Result {174match self {175&AMode::RegOffset(r, offset, ..) => {176write!(f, "{}({})", offset, reg_name(r))177}178&AMode::SPOffset(offset, ..) => {179write!(f, "{offset}(sp)")180}181&AMode::SlotOffset(offset, ..) => {182write!(f, "{offset}(slot)")183}184&AMode::IncomingArg(offset) => {185write!(f, "-{offset}(incoming_arg)")186}187&AMode::FPOffset(offset, ..) => {188write!(f, "{offset}(fp)")189}190&AMode::Const(addr, ..) => {191write!(f, "[const({})]", addr.as_u32())192}193&AMode::Label(label) => {194write!(f, "[label{}]", label.as_u32())195}196}197}198}199200impl From<StackAMode> for AMode {201fn from(stack: StackAMode) -> AMode {202match stack {203StackAMode::IncomingArg(offset, stack_args_size) => {204AMode::IncomingArg(i64::from(stack_args_size) - offset)205}206StackAMode::OutgoingArg(offset) => AMode::SPOffset(offset),207StackAMode::Slot(offset) => AMode::SlotOffset(offset),208}209}210}211212/// risc-v always take two register to compare213#[derive(Clone, Copy, Debug)]214pub struct IntegerCompare {215pub(crate) kind: IntCC,216pub(crate) rs1: Reg,217pub(crate) rs2: Reg,218}219220pub(crate) enum BranchFunct3 {221// ==222Eq,223// !=224Ne,225// signed <226Lt,227// signed >=228Ge,229// unsigned <230Ltu,231// unsigned >=232Geu,233}234235impl BranchFunct3 {236pub(crate) fn funct3(self) -> u32 {237match self {238BranchFunct3::Eq => 0b000,239BranchFunct3::Ne => 0b001,240BranchFunct3::Lt => 0b100,241BranchFunct3::Ge => 0b101,242BranchFunct3::Ltu => 0b110,243BranchFunct3::Geu => 0b111,244}245}246}247248impl IntegerCompare {249pub(crate) fn op_code(self) -> u32 {2500b1100011251}252253// funct3 and if need inverse the register254pub(crate) fn funct3(&self) -> (BranchFunct3, bool) {255match self.kind {256IntCC::Equal => (BranchFunct3::Eq, false),257IntCC::NotEqual => (BranchFunct3::Ne, false),258IntCC::SignedLessThan => (BranchFunct3::Lt, false),259IntCC::SignedGreaterThanOrEqual => (BranchFunct3::Ge, false),260261IntCC::SignedGreaterThan => (BranchFunct3::Lt, true),262IntCC::SignedLessThanOrEqual => (BranchFunct3::Ge, true),263264IntCC::UnsignedLessThan => (BranchFunct3::Ltu, false),265IntCC::UnsignedGreaterThanOrEqual => (BranchFunct3::Geu, false),266267IntCC::UnsignedGreaterThan => (BranchFunct3::Ltu, true),268IntCC::UnsignedLessThanOrEqual => (BranchFunct3::Geu, true),269}270}271272#[inline]273pub(crate) fn op_name(&self) -> &'static str {274match self.kind {275IntCC::Equal => "beq",276IntCC::NotEqual => "bne",277IntCC::SignedLessThan => "blt",278IntCC::SignedGreaterThanOrEqual => "bge",279IntCC::SignedGreaterThan => "bgt",280IntCC::SignedLessThanOrEqual => "ble",281IntCC::UnsignedLessThan => "bltu",282IntCC::UnsignedGreaterThanOrEqual => "bgeu",283IntCC::UnsignedGreaterThan => "bgtu",284IntCC::UnsignedLessThanOrEqual => "bleu",285}286}287288pub(crate) fn emit(self) -> u32 {289let (funct3, reverse) = self.funct3();290let (rs1, rs2) = if reverse {291(self.rs2, self.rs1)292} else {293(self.rs1, self.rs2)294};295296self.op_code()297| funct3.funct3() << 12298| reg_to_gpr_num(rs1) << 15299| reg_to_gpr_num(rs2) << 20300}301302pub(crate) fn inverse(self) -> Self {303Self {304kind: self.kind.complement(),305..self306}307}308309pub(crate) fn regs(&self) -> [Reg; 2] {310[self.rs1, self.rs2]311}312}313314#[derive(Debug, Clone, Copy, PartialEq)]315pub struct FliConstant(u8);316317impl FliConstant {318pub(crate) fn new(value: u8) -> Self {319debug_assert!(value <= 31, "Invalid FliConstant: {value}");320Self(value)321}322323pub(crate) fn maybe_from_u64(ty: Type, imm: u64) -> Option<Self> {324// Convert the value into an F64, this allows us to represent325// values from both f32 and f64 in the same value.326let value = match ty {327F16 => {328// FIXME(#8312): Use `f16` once it has been stabilised.329// Handle special/non-normal values first.330match imm {331// `f16::MIN_POSITIVE`3320x0400 => return Some(Self::new(1)),333// 2 pow -163340x0100 => return Some(Self::new(2)),335// 2 pow -153360x0200 => return Some(Self::new(3)),337// `f16::INFINITY`3380x7c00 => return Some(Self::new(30)),339// Canonical NaN3400x7e00 => return Some(Self::new(31)),341_ => {342let exponent_bits = imm & 0x7c00;343if exponent_bits == 0 || exponent_bits == 0x7c00 {344// All non-normal values are handled above.345return None;346}347let sign = (imm & 0x8000) << 48;348// Adjust the exponent for the difference between the `f16` exponent bias349// and the `f64` exponent bias.350let exponent = (exponent_bits + ((1023 - 15) << 10)) << 42;351let significand = (imm & 0x3ff) << 42;352f64::from_bits(sign | exponent | significand)353}354}355}356F32 => f32::from_bits(imm as u32) as f64,357F64 => f64::from_bits(imm),358_ => unimplemented!(),359};360361Some(match (ty, value) {362(_, f) if f == -1.0 => Self::new(0),363364// Since f64 can represent all f32 values, f32::min_positive won't be365// the same as f64::min_positive, so we need to check for both indepenendtly366(F32, f) if f == (f32::MIN_POSITIVE as f64) => Self::new(1),367(F64, f) if f == f64::MIN_POSITIVE => Self::new(1),368369(_, f) if f == 2.0f64.powi(-16) => Self::new(2),370(_, f) if f == 2.0f64.powi(-15) => Self::new(3),371(_, f) if f == 2.0f64.powi(-8) => Self::new(4),372(_, f) if f == 2.0f64.powi(-7) => Self::new(5),373(_, f) if f == 0.0625 => Self::new(6),374(_, f) if f == 0.125 => Self::new(7),375(_, f) if f == 0.25 => Self::new(8),376(_, f) if f == 0.3125 => Self::new(9),377(_, f) if f == 0.375 => Self::new(10),378(_, f) if f == 0.4375 => Self::new(11),379(_, f) if f == 0.5 => Self::new(12),380(_, f) if f == 0.625 => Self::new(13),381(_, f) if f == 0.75 => Self::new(14),382(_, f) if f == 0.875 => Self::new(15),383(_, f) if f == 1.0 => Self::new(16),384(_, f) if f == 1.25 => Self::new(17),385(_, f) if f == 1.5 => Self::new(18),386(_, f) if f == 1.75 => Self::new(19),387(_, f) if f == 2.0 => Self::new(20),388(_, f) if f == 2.5 => Self::new(21),389(_, f) if f == 3.0 => Self::new(22),390(_, f) if f == 4.0 => Self::new(23),391(_, f) if f == 8.0 => Self::new(24),392(_, f) if f == 16.0 => Self::new(25),393(_, f) if f == 128.0 => Self::new(26),394(_, f) if f == 256.0 => Self::new(27),395(_, f) if f == 32768.0 => Self::new(28),396(_, f) if f == 65536.0 => Self::new(29),397(_, f) if f == f64::INFINITY => Self::new(30),398399// NaN's are not guaranteed to preserve the sign / payload bits, so we need to check400// the original bits directly.401(F32, f) if f.is_nan() && imm == 0x7fc0_0000 => Self::new(31), // Canonical NaN402(F64, f) if f.is_nan() && imm == 0x7ff8_0000_0000_0000 => Self::new(31), // Canonical NaN403_ => return None,404})405}406407pub(crate) fn format(self) -> &'static str {408// The preferred assembly syntax for entries 1, 30, and 31 is min, inf, and nan, respectively.409// For entries 0 through 29 (including entry 1), the assembler will accept decimal constants410// in C-like syntax.411match self.0 {4120 => "-1.0",4131 => "min",4142 => "2^-16",4153 => "2^-15",4164 => "2^-8",4175 => "2^-7",4186 => "0.0625",4197 => "0.125",4208 => "0.25",4219 => "0.3125",42210 => "0.375",42311 => "0.4375",42412 => "0.5",42513 => "0.625",42614 => "0.75",42715 => "0.875",42816 => "1.0",42917 => "1.25",43018 => "1.5",43119 => "1.75",43220 => "2.0",43321 => "2.5",43422 => "3.0",43523 => "4.0",43624 => "8.0",43725 => "16.0",43826 => "128.0",43927 => "256.0",44028 => "32768.0",44129 => "65536.0",44230 => "inf",44331 => "nan",444_ => panic!("Invalid FliConstant"),445}446}447448pub(crate) fn bits(self) -> u8 {449self.0450}451}452453impl FpuOPRRRR {454pub(crate) fn op_name(self, width: FpuOPWidth) -> String {455match self {456Self::Fmadd => format!("fmadd.{width}"),457Self::Fmsub => format!("fmsub.{width}"),458Self::Fnmsub => format!("fnmsub.{width}"),459Self::Fnmadd => format!("fnmadd.{width}"),460}461}462463pub(crate) fn opcode(self) -> u32 {464match self {465Self::Fmadd => 0b1000011,466Self::Fmsub => 0b1000111,467Self::Fnmsub => 0b1001011,468Self::Fnmadd => 0b1001111,469}470}471}472473impl FpuOPRR {474pub(crate) fn op_name(self, width: FpuOPWidth) -> String {475let fmv_width = match width {476FpuOPWidth::H => "h",477FpuOPWidth::S => "w",478FpuOPWidth::D => "d",479FpuOPWidth::Q => "q",480};481match self {482Self::Fsqrt => format!("fsqrt.{width}"),483Self::Fround => format!("fround.{width}"),484Self::Fclass => format!("fclass.{width}"),485Self::FcvtWFmt => format!("fcvt.w.{width}"),486Self::FcvtWuFmt => format!("fcvt.wu.{width}"),487Self::FcvtLFmt => format!("fcvt.l.{width}"),488Self::FcvtLuFmt => format!("fcvt.lu.{width}"),489Self::FcvtFmtW => format!("fcvt.{width}.w"),490Self::FcvtFmtWu => format!("fcvt.{width}.wu"),491Self::FcvtFmtL => format!("fcvt.{width}.l"),492Self::FcvtFmtLu => format!("fcvt.{width}.lu"),493494// fmv instructions deviate from the normal encoding and instead495// encode the width as "w" instead of "s". The ISA manual gives this rationale:496//497// Instructions FMV.S.X and FMV.X.S were renamed to FMV.W.X and FMV.X.W respectively498// to be more consistent with their semantics, which did not change. The old names will continue499// to be supported in the tools.500Self::FmvXFmt => format!("fmv.x.{fmv_width}"),501Self::FmvFmtX => format!("fmv.{fmv_width}.x"),502503Self::FcvtSD => "fcvt.s.d".to_string(),504Self::FcvtDS => "fcvt.d.s".to_string(),505}506}507508pub(crate) fn is_convert_to_int(self) -> bool {509match self {510Self::FcvtWFmt | Self::FcvtWuFmt | Self::FcvtLFmt | Self::FcvtLuFmt => true,511_ => false,512}513}514515pub(crate) fn has_frm(self) -> bool {516match self {517FpuOPRR::FmvXFmt | FpuOPRR::FmvFmtX | FpuOPRR::Fclass => false,518_ => true,519}520}521522pub(crate) fn opcode(self) -> u32 {523// OP-FP Major opcode5240b1010011525}526527pub(crate) fn rs2(self) -> u32 {528match self {529Self::Fsqrt => 0b00000,530Self::Fround => 0b00100,531Self::Fclass => 0b00000,532Self::FcvtWFmt => 0b00000,533Self::FcvtWuFmt => 0b00001,534Self::FcvtLFmt => 0b00010,535Self::FcvtLuFmt => 0b00011,536Self::FcvtFmtW => 0b00000,537Self::FcvtFmtWu => 0b00001,538Self::FcvtFmtL => 0b00010,539Self::FcvtFmtLu => 0b00011,540Self::FmvXFmt => 0b00000,541Self::FmvFmtX => 0b00000,542Self::FcvtSD => 0b00001,543Self::FcvtDS => 0b00000,544}545}546547pub(crate) fn funct5(self) -> u32 {548match self {549Self::Fsqrt => 0b01011,550Self::Fround => 0b01000,551Self::Fclass => 0b11100,552Self::FcvtWFmt => 0b11000,553Self::FcvtWuFmt => 0b11000,554Self::FcvtLFmt => 0b11000,555Self::FcvtLuFmt => 0b11000,556Self::FcvtFmtW => 0b11010,557Self::FcvtFmtWu => 0b11010,558Self::FcvtFmtL => 0b11010,559Self::FcvtFmtLu => 0b11010,560Self::FmvXFmt => 0b11100,561Self::FmvFmtX => 0b11110,562Self::FcvtSD => 0b01000,563Self::FcvtDS => 0b01000,564}565}566567pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 {568(self.funct5() << 2) | width.as_u32()569}570}571572impl FpuOPRRR {573pub(crate) fn op_name(self, width: FpuOPWidth) -> String {574match self {575Self::Fadd => format!("fadd.{width}"),576Self::Fsub => format!("fsub.{width}"),577Self::Fmul => format!("fmul.{width}"),578Self::Fdiv => format!("fdiv.{width}"),579Self::Fsgnj => format!("fsgnj.{width}"),580Self::Fsgnjn => format!("fsgnjn.{width}"),581Self::Fsgnjx => format!("fsgnjx.{width}"),582Self::Fmin => format!("fmin.{width}"),583Self::Fmax => format!("fmax.{width}"),584Self::Feq => format!("feq.{width}"),585Self::Flt => format!("flt.{width}"),586Self::Fle => format!("fle.{width}"),587Self::Fminm => format!("fminm.{width}"),588Self::Fmaxm => format!("fmaxm.{width}"),589}590}591592pub(crate) fn opcode(self) -> u32 {593// OP-FP Major opcode5940b1010011595}596597pub(crate) const fn funct5(self) -> u32 {598match self {599Self::Fadd => 0b00000,600Self::Fsub => 0b00001,601Self::Fmul => 0b00010,602Self::Fdiv => 0b00011,603Self::Fsgnj => 0b00100,604Self::Fsgnjn => 0b00100,605Self::Fsgnjx => 0b00100,606Self::Fmin => 0b00101,607Self::Fmax => 0b00101,608Self::Feq => 0b10100,609Self::Flt => 0b10100,610Self::Fle => 0b10100,611Self::Fminm => 0b00101,612Self::Fmaxm => 0b00101,613}614}615616pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 {617(self.funct5() << 2) | width.as_u32()618}619620pub(crate) fn has_frm(self) -> bool {621match self {622FpuOPRRR::Fsgnj623| FpuOPRRR::Fsgnjn624| FpuOPRRR::Fsgnjx625| FpuOPRRR::Fmin626| FpuOPRRR::Fmax627| FpuOPRRR::Feq628| FpuOPRRR::Flt629| FpuOPRRR::Fle => false,630_ => true,631}632}633}634635impl Display for FpuOPWidth {636fn fmt(&self, f: &mut Formatter<'_>) -> Result {637write!(638f,639"{}",640match self {641FpuOPWidth::H => "h",642FpuOPWidth::S => "s",643FpuOPWidth::D => "d",644FpuOPWidth::Q => "q",645}646)647}648}649650impl TryFrom<Type> for FpuOPWidth {651type Error = &'static str;652653fn try_from(value: Type) -> std::result::Result<Self, Self::Error> {654match value {655F16 => Ok(FpuOPWidth::H),656F32 => Ok(FpuOPWidth::S),657F64 => Ok(FpuOPWidth::D),658F128 => Ok(FpuOPWidth::Q),659_ => Err("Invalid type for FpuOPWidth"),660}661}662}663664impl FpuOPWidth {665pub(crate) fn as_u32(&self) -> u32 {666match self {667FpuOPWidth::S => 0b00,668FpuOPWidth::D => 0b01,669FpuOPWidth::H => 0b10,670FpuOPWidth::Q => 0b11,671}672}673}674675impl AluOPRRR {676pub(crate) const fn op_name(self) -> &'static str {677match self {678Self::Add => "add",679Self::Sub => "sub",680Self::Sll => "sll",681Self::Slt => "slt",682Self::Sgt => "sgt",683Self::SltU => "sltu",684Self::Sgtu => "sgtu",685Self::Xor => "xor",686Self::Srl => "srl",687Self::Sra => "sra",688Self::Or => "or",689Self::And => "and",690Self::Addw => "addw",691Self::Subw => "subw",692Self::Sllw => "sllw",693Self::Srlw => "srlw",694Self::Sraw => "sraw",695Self::Mul => "mul",696Self::Mulh => "mulh",697Self::Mulhsu => "mulhsu",698Self::Mulhu => "mulhu",699Self::Div => "div",700Self::DivU => "divu",701Self::Rem => "rem",702Self::RemU => "remu",703Self::Mulw => "mulw",704Self::Divw => "divw",705Self::Divuw => "divuw",706Self::Remw => "remw",707Self::Remuw => "remuw",708Self::Adduw => "add.uw",709Self::Andn => "andn",710Self::Bclr => "bclr",711Self::Bext => "bext",712Self::Binv => "binv",713Self::Bset => "bset",714Self::Clmul => "clmul",715Self::Clmulh => "clmulh",716Self::Clmulr => "clmulr",717Self::Max => "max",718Self::Maxu => "maxu",719Self::Min => "min",720Self::Minu => "minu",721Self::Orn => "orn",722Self::Rol => "rol",723Self::Rolw => "rolw",724Self::Ror => "ror",725Self::Rorw => "rorw",726Self::Sh1add => "sh1add",727Self::Sh1adduw => "sh1add.uw",728Self::Sh2add => "sh2add",729Self::Sh2adduw => "sh2add.uw",730Self::Sh3add => "sh3add",731Self::Sh3adduw => "sh3add.uw",732Self::Xnor => "xnor",733Self::Pack => "pack",734Self::Packw => "packw",735Self::Packh => "packh",736Self::CzeroEqz => "czero.eqz",737Self::CzeroNez => "czero.nez",738}739}740741pub fn funct3(self) -> u32 {742match self {743AluOPRRR::Add => 0b000,744AluOPRRR::Sll => 0b001,745AluOPRRR::Slt => 0b010,746AluOPRRR::Sgt => 0b010,747AluOPRRR::SltU => 0b011,748AluOPRRR::Sgtu => 0b011,749AluOPRRR::Xor => 0b100,750AluOPRRR::Srl => 0b101,751AluOPRRR::Sra => 0b101,752AluOPRRR::Or => 0b110,753AluOPRRR::And => 0b111,754AluOPRRR::Sub => 0b000,755756AluOPRRR::Addw => 0b000,757AluOPRRR::Subw => 0b000,758AluOPRRR::Sllw => 0b001,759AluOPRRR::Srlw => 0b101,760AluOPRRR::Sraw => 0b101,761762AluOPRRR::Mul => 0b000,763AluOPRRR::Mulh => 0b001,764AluOPRRR::Mulhsu => 0b010,765AluOPRRR::Mulhu => 0b011,766AluOPRRR::Div => 0b100,767AluOPRRR::DivU => 0b101,768AluOPRRR::Rem => 0b110,769AluOPRRR::RemU => 0b111,770771AluOPRRR::Mulw => 0b000,772AluOPRRR::Divw => 0b100,773AluOPRRR::Divuw => 0b101,774AluOPRRR::Remw => 0b110,775AluOPRRR::Remuw => 0b111,776777// Zbb778AluOPRRR::Adduw => 0b000,779AluOPRRR::Andn => 0b111,780AluOPRRR::Bclr => 0b001,781AluOPRRR::Bext => 0b101,782AluOPRRR::Binv => 0b001,783AluOPRRR::Bset => 0b001,784AluOPRRR::Clmul => 0b001,785AluOPRRR::Clmulh => 0b011,786AluOPRRR::Clmulr => 0b010,787AluOPRRR::Max => 0b110,788AluOPRRR::Maxu => 0b111,789AluOPRRR::Min => 0b100,790AluOPRRR::Minu => 0b101,791AluOPRRR::Orn => 0b110,792AluOPRRR::Rol => 0b001,793AluOPRRR::Rolw => 0b001,794AluOPRRR::Ror => 0b101,795AluOPRRR::Rorw => 0b101,796AluOPRRR::Sh1add => 0b010,797AluOPRRR::Sh1adduw => 0b010,798AluOPRRR::Sh2add => 0b100,799AluOPRRR::Sh2adduw => 0b100,800AluOPRRR::Sh3add => 0b110,801AluOPRRR::Sh3adduw => 0b110,802AluOPRRR::Xnor => 0b100,803804// Zbkb805AluOPRRR::Pack => 0b100,806AluOPRRR::Packw => 0b100,807AluOPRRR::Packh => 0b111,808809// ZiCond810AluOPRRR::CzeroEqz => 0b101,811AluOPRRR::CzeroNez => 0b111,812}813}814815pub fn op_code(self) -> u32 {816match self {817AluOPRRR::Add818| AluOPRRR::Sub819| AluOPRRR::Sll820| AluOPRRR::Slt821| AluOPRRR::Sgt822| AluOPRRR::SltU823| AluOPRRR::Sgtu824| AluOPRRR::Xor825| AluOPRRR::Srl826| AluOPRRR::Sra827| AluOPRRR::Or828| AluOPRRR::And829| AluOPRRR::Pack830| AluOPRRR::Packh => 0b0110011,831832AluOPRRR::Addw833| AluOPRRR::Subw834| AluOPRRR::Sllw835| AluOPRRR::Srlw836| AluOPRRR::Sraw837| AluOPRRR::Packw => 0b0111011,838839AluOPRRR::Mul840| AluOPRRR::Mulh841| AluOPRRR::Mulhsu842| AluOPRRR::Mulhu843| AluOPRRR::Div844| AluOPRRR::DivU845| AluOPRRR::Rem846| AluOPRRR::RemU => 0b0110011,847848AluOPRRR::Mulw849| AluOPRRR::Divw850| AluOPRRR::Divuw851| AluOPRRR::Remw852| AluOPRRR::Remuw => 0b0111011,853854AluOPRRR::Adduw => 0b0111011,855AluOPRRR::Andn856| AluOPRRR::Bclr857| AluOPRRR::Bext858| AluOPRRR::Binv859| AluOPRRR::Bset860| AluOPRRR::Clmul861| AluOPRRR::Clmulh862| AluOPRRR::Clmulr863| AluOPRRR::Max864| AluOPRRR::Maxu865| AluOPRRR::Min866| AluOPRRR::Minu867| AluOPRRR::Orn868| AluOPRRR::Rol869| AluOPRRR::Ror870| AluOPRRR::Sh1add871| AluOPRRR::Sh2add872| AluOPRRR::Sh3add873| AluOPRRR::Xnor874| AluOPRRR::CzeroEqz875| AluOPRRR::CzeroNez => 0b0110011,876877AluOPRRR::Rolw878| AluOPRRR::Rorw879| AluOPRRR::Sh2adduw880| AluOPRRR::Sh3adduw881| AluOPRRR::Sh1adduw => 0b0111011,882}883}884885pub const fn funct7(self) -> u32 {886match self {887AluOPRRR::Add => 0b0000000,888AluOPRRR::Sub => 0b0100000,889AluOPRRR::Sll => 0b0000000,890AluOPRRR::Slt => 0b0000000,891AluOPRRR::Sgt => 0b0000000,892AluOPRRR::SltU => 0b0000000,893AluOPRRR::Sgtu => 0b0000000,894895AluOPRRR::Xor => 0b0000000,896AluOPRRR::Srl => 0b0000000,897AluOPRRR::Sra => 0b0100000,898AluOPRRR::Or => 0b0000000,899AluOPRRR::And => 0b0000000,900901AluOPRRR::Addw => 0b0000000,902AluOPRRR::Subw => 0b0100000,903AluOPRRR::Sllw => 0b0000000,904AluOPRRR::Srlw => 0b0000000,905AluOPRRR::Sraw => 0b0100000,906907AluOPRRR::Mul => 0b0000001,908AluOPRRR::Mulh => 0b0000001,909AluOPRRR::Mulhsu => 0b0000001,910AluOPRRR::Mulhu => 0b0000001,911AluOPRRR::Div => 0b0000001,912AluOPRRR::DivU => 0b0000001,913AluOPRRR::Rem => 0b0000001,914AluOPRRR::RemU => 0b0000001,915916AluOPRRR::Mulw => 0b0000001,917AluOPRRR::Divw => 0b0000001,918AluOPRRR::Divuw => 0b0000001,919AluOPRRR::Remw => 0b0000001,920AluOPRRR::Remuw => 0b0000001,921AluOPRRR::Adduw => 0b0000100,922AluOPRRR::Andn => 0b0100000,923AluOPRRR::Bclr => 0b0100100,924AluOPRRR::Bext => 0b0100100,925AluOPRRR::Binv => 0b0110100,926AluOPRRR::Bset => 0b0010100,927AluOPRRR::Clmul => 0b0000101,928AluOPRRR::Clmulh => 0b0000101,929AluOPRRR::Clmulr => 0b0000101,930AluOPRRR::Max => 0b0000101,931AluOPRRR::Maxu => 0b0000101,932AluOPRRR::Min => 0b0000101,933AluOPRRR::Minu => 0b0000101,934AluOPRRR::Orn => 0b0100000,935AluOPRRR::Rol => 0b0110000,936AluOPRRR::Rolw => 0b0110000,937AluOPRRR::Ror => 0b0110000,938AluOPRRR::Rorw => 0b0110000,939AluOPRRR::Sh1add => 0b0010000,940AluOPRRR::Sh1adduw => 0b0010000,941AluOPRRR::Sh2add => 0b0010000,942AluOPRRR::Sh2adduw => 0b0010000,943AluOPRRR::Sh3add => 0b0010000,944AluOPRRR::Sh3adduw => 0b0010000,945AluOPRRR::Xnor => 0b0100000,946947// Zbkb948AluOPRRR::Pack => 0b0000100,949AluOPRRR::Packw => 0b0000100,950AluOPRRR::Packh => 0b0000100,951952// ZiCond953AluOPRRR::CzeroEqz => 0b0000111,954AluOPRRR::CzeroNez => 0b0000111,955}956}957958pub(crate) fn reverse_rs(self) -> bool {959// special case.960// sgt and sgtu is not defined in isa.961// emit should reverse rs1 and rs2.962self == AluOPRRR::Sgt || self == AluOPRRR::Sgtu963}964}965966impl AluOPRRI {967pub(crate) fn option_funct6(self) -> Option<u32> {968let x: Option<u32> = match self {969Self::Slli => Some(0b00_0000),970Self::Srli => Some(0b00_0000),971Self::Srai => Some(0b01_0000),972Self::Bclri => Some(0b010010),973Self::Bexti => Some(0b010010),974Self::Binvi => Some(0b011010),975Self::Bseti => Some(0b001010),976Self::Rori => Some(0b011000),977Self::SlliUw => Some(0b000010),978_ => None,979};980x981}982983pub(crate) fn option_funct7(self) -> Option<u32> {984let x = match self {985Self::Slliw => Some(0b000_0000),986Self::SrliW => Some(0b000_0000),987Self::Sraiw => Some(0b010_0000),988Self::Roriw => Some(0b0110000),989_ => None,990};991x992}993994pub(crate) fn imm12(self, imm12: Imm12) -> u32 {995let x = imm12.bits();996if let Some(func) = self.option_funct6() {997func << 6 | (x & 0b11_1111)998} else if let Some(func) = self.option_funct7() {999func << 5 | (x & 0b1_1111)1000} else if let Some(func) = self.option_funct12() {1001func1002} else {1003x1004}1005}10061007pub(crate) fn option_funct12(self) -> Option<u32> {1008match self {1009Self::Clz => Some(0b011000000000),1010Self::Clzw => Some(0b011000000000),1011Self::Cpop => Some(0b011000000010),1012Self::Cpopw => Some(0b011000000010),1013Self::Ctz => Some(0b011000000001),1014Self::Ctzw => Some(0b011000000001),1015Self::Rev8 => Some(0b011010111000),1016Self::Sextb => Some(0b011000000100),1017Self::Sexth => Some(0b011000000101),1018Self::Zexth => Some(0b000010000000),1019Self::Orcb => Some(0b001010000111),1020Self::Brev8 => Some(0b0110_1000_0111),1021_ => None,1022}1023}10241025pub(crate) fn op_name(self) -> &'static str {1026match self {1027Self::Addi => "addi",1028Self::Slti => "slti",1029Self::SltiU => "sltiu",1030Self::Xori => "xori",1031Self::Ori => "ori",1032Self::Andi => "andi",1033Self::Slli => "slli",1034Self::Srli => "srli",1035Self::Srai => "srai",1036Self::Addiw => "addiw",1037Self::Slliw => "slliw",1038Self::SrliW => "srliw",1039Self::Sraiw => "sraiw",1040Self::Bclri => "bclri",1041Self::Bexti => "bexti",1042Self::Binvi => "binvi",1043Self::Bseti => "bseti",1044Self::Rori => "rori",1045Self::Roriw => "roriw",1046Self::SlliUw => "slli.uw",1047Self::Clz => "clz",1048Self::Clzw => "clzw",1049Self::Cpop => "cpop",1050Self::Cpopw => "cpopw",1051Self::Ctz => "ctz",1052Self::Ctzw => "ctzw",1053Self::Rev8 => "rev8",1054Self::Sextb => "sext.b",1055Self::Sexth => "sext.h",1056Self::Zexth => "zext.h",1057Self::Orcb => "orc.b",1058Self::Brev8 => "brev8",1059}1060}10611062pub fn funct3(self) -> u32 {1063match self {1064AluOPRRI::Addi => 0b000,1065AluOPRRI::Slti => 0b010,1066AluOPRRI::SltiU => 0b011,1067AluOPRRI::Xori => 0b100,1068AluOPRRI::Ori => 0b110,1069AluOPRRI::Andi => 0b111,1070AluOPRRI::Slli => 0b001,1071AluOPRRI::Srli => 0b101,1072AluOPRRI::Srai => 0b101,1073AluOPRRI::Addiw => 0b000,1074AluOPRRI::Slliw => 0b001,1075AluOPRRI::SrliW => 0b101,1076AluOPRRI::Sraiw => 0b101,1077AluOPRRI::Bclri => 0b001,1078AluOPRRI::Bexti => 0b101,1079AluOPRRI::Binvi => 0b001,1080AluOPRRI::Bseti => 0b001,1081AluOPRRI::Rori => 0b101,1082AluOPRRI::Roriw => 0b101,1083AluOPRRI::SlliUw => 0b001,1084AluOPRRI::Clz => 0b001,1085AluOPRRI::Clzw => 0b001,1086AluOPRRI::Cpop => 0b001,1087AluOPRRI::Cpopw => 0b001,1088AluOPRRI::Ctz => 0b001,1089AluOPRRI::Ctzw => 0b001,1090AluOPRRI::Rev8 => 0b101,1091AluOPRRI::Sextb => 0b001,1092AluOPRRI::Sexth => 0b001,1093AluOPRRI::Zexth => 0b100,1094AluOPRRI::Orcb => 0b101,1095AluOPRRI::Brev8 => 0b101,1096}1097}10981099pub fn op_code(self) -> u32 {1100match self {1101AluOPRRI::Addi1102| AluOPRRI::Slti1103| AluOPRRI::SltiU1104| AluOPRRI::Xori1105| AluOPRRI::Ori1106| AluOPRRI::Andi1107| AluOPRRI::Slli1108| AluOPRRI::Srli1109| AluOPRRI::Srai1110| AluOPRRI::Bclri1111| AluOPRRI::Bexti1112| AluOPRRI::Binvi1113| AluOPRRI::Bseti1114| AluOPRRI::Rori1115| AluOPRRI::Clz1116| AluOPRRI::Cpop1117| AluOPRRI::Ctz1118| AluOPRRI::Rev81119| AluOPRRI::Sextb1120| AluOPRRI::Sexth1121| AluOPRRI::Orcb1122| AluOPRRI::Brev8 => 0b0010011,11231124AluOPRRI::Addiw1125| AluOPRRI::Slliw1126| AluOPRRI::SrliW1127| AluOPRRI::Sraiw1128| AluOPRRI::Roriw1129| AluOPRRI::SlliUw1130| AluOPRRI::Clzw1131| AluOPRRI::Cpopw1132| AluOPRRI::Ctzw => 0b0011011,1133AluOPRRI::Zexth => 0b0111011,1134}1135}1136}11371138impl Default for FRM {1139fn default() -> Self {1140Self::Fcsr1141}1142}11431144/// float rounding mode.1145impl FRM {1146pub(crate) fn to_static_str(self) -> &'static str {1147match self {1148FRM::RNE => "rne",1149FRM::RTZ => "rtz",1150FRM::RDN => "rdn",1151FRM::RUP => "rup",1152FRM::RMM => "rmm",1153FRM::Fcsr => "fcsr",1154}1155}11561157#[inline]1158pub(crate) fn bits(self) -> u8 {1159match self {1160FRM::RNE => 0b000,1161FRM::RTZ => 0b001,1162FRM::RDN => 0b010,1163FRM::RUP => 0b011,1164FRM::RMM => 0b100,1165FRM::Fcsr => 0b111,1166}1167}1168pub(crate) fn as_u32(self) -> u32 {1169self.bits() as u321170}1171}11721173impl FFlagsException {1174#[inline]1175#[expect(dead_code, reason = "here for future use")]1176pub(crate) fn mask(self) -> u32 {1177match self {1178FFlagsException::NV => 1 << 4,1179FFlagsException::DZ => 1 << 3,1180FFlagsException::OF => 1 << 2,1181FFlagsException::UF => 1 << 1,1182FFlagsException::NX => 1 << 0,1183}1184}1185}11861187impl LoadOP {1188pub(crate) fn op_name(self) -> &'static str {1189match self {1190Self::Lb => "lb",1191Self::Lh => "lh",1192Self::Lw => "lw",1193Self::Lbu => "lbu",1194Self::Lhu => "lhu",1195Self::Lwu => "lwu",1196Self::Ld => "ld",1197Self::Flh => "flh",1198Self::Flw => "flw",1199Self::Fld => "fld",1200}1201}12021203pub(crate) fn from_type(ty: Type) -> Self {1204match ty {1205F16 => Self::Flh,1206F32 => Self::Flw,1207F64 => Self::Fld,1208I8 => Self::Lb,1209I16 => Self::Lh,1210I32 => Self::Lw,1211I64 => Self::Ld,1212_ => unreachable!(),1213}1214}12151216pub(crate) fn size(&self) -> i64 {1217match self {1218Self::Lb | Self::Lbu => 1,1219Self::Lh | Self::Lhu | Self::Flh => 2,1220Self::Lw | Self::Lwu | Self::Flw => 4,1221Self::Ld | Self::Fld => 8,1222}1223}12241225pub(crate) fn op_code(self) -> u32 {1226match self {1227Self::Lb | Self::Lh | Self::Lw | Self::Lbu | Self::Lhu | Self::Lwu | Self::Ld => {12280b00000111229}1230Self::Flh | Self::Flw | Self::Fld => 0b0000111,1231}1232}1233pub(crate) fn funct3(self) -> u32 {1234match self {1235Self::Lb => 0b000,1236Self::Lh => 0b001,1237Self::Lw => 0b010,1238Self::Lwu => 0b110,1239Self::Lbu => 0b100,1240Self::Lhu => 0b101,1241Self::Ld => 0b011,1242Self::Flh => 0b001,1243Self::Flw => 0b010,1244Self::Fld => 0b011,1245}1246}1247}12481249impl StoreOP {1250pub(crate) fn op_name(self) -> &'static str {1251match self {1252Self::Sb => "sb",1253Self::Sh => "sh",1254Self::Sw => "sw",1255Self::Sd => "sd",1256Self::Fsh => "fsh",1257Self::Fsw => "fsw",1258Self::Fsd => "fsd",1259}1260}1261pub(crate) fn from_type(ty: Type) -> Self {1262match ty {1263F16 => Self::Fsh,1264F32 => Self::Fsw,1265F64 => Self::Fsd,1266I8 => Self::Sb,1267I16 => Self::Sh,1268I32 => Self::Sw,1269I64 => Self::Sd,1270_ => unreachable!(),1271}1272}12731274pub(crate) fn size(&self) -> i64 {1275match self {1276Self::Sb => 1,1277Self::Sh | Self::Fsh => 2,1278Self::Sw | Self::Fsw => 4,1279Self::Sd | Self::Fsd => 8,1280}1281}12821283pub(crate) fn op_code(self) -> u32 {1284match self {1285Self::Sb | Self::Sh | Self::Sw | Self::Sd => 0b0100011,1286Self::Fsh | Self::Fsw | Self::Fsd => 0b0100111,1287}1288}1289pub(crate) fn funct3(self) -> u32 {1290match self {1291Self::Sb => 0b000,1292Self::Sh => 0b001,1293Self::Sw => 0b010,1294Self::Sd => 0b011,1295Self::Fsh => 0b001,1296Self::Fsw => 0b010,1297Self::Fsd => 0b011,1298}1299}1300}13011302impl FClassResult {1303pub(crate) const fn bit(self) -> u32 {1304match self {1305FClassResult::NegInfinite => 1 << 0,1306FClassResult::NegNormal => 1 << 1,1307FClassResult::NegSubNormal => 1 << 2,1308FClassResult::NegZero => 1 << 3,1309FClassResult::PosZero => 1 << 4,1310FClassResult::PosSubNormal => 1 << 5,1311FClassResult::PosNormal => 1 << 6,1312FClassResult::PosInfinite => 1 << 7,1313FClassResult::SNaN => 1 << 8,1314FClassResult::QNaN => 1 << 9,1315}1316}13171318#[inline]1319#[expect(dead_code, reason = "here for future use")]1320pub(crate) const fn is_nan_bits() -> u32 {1321Self::SNaN.bit() | Self::QNaN.bit()1322}1323#[inline]1324#[expect(dead_code, reason = "here for future use")]1325pub(crate) fn is_zero_bits() -> u32 {1326Self::NegZero.bit() | Self::PosZero.bit()1327}13281329#[inline]1330#[expect(dead_code, reason = "here for future use")]1331pub(crate) fn is_infinite_bits() -> u32 {1332Self::PosInfinite.bit() | Self::NegInfinite.bit()1333}1334}13351336impl AtomicOP {1337#[inline]1338pub(crate) fn is_load(self) -> bool {1339match self {1340Self::LrW | Self::LrD => true,1341_ => false,1342}1343}13441345#[inline]1346pub(crate) fn op_name(self, amo: AMO) -> String {1347let s = match self {1348Self::LrW => "lr.w",1349Self::ScW => "sc.w",13501351Self::AmoswapW => "amoswap.w",1352Self::AmoaddW => "amoadd.w",1353Self::AmoxorW => "amoxor.w",1354Self::AmoandW => "amoand.w",1355Self::AmoorW => "amoor.w",1356Self::AmominW => "amomin.w",1357Self::AmomaxW => "amomax.w",1358Self::AmominuW => "amominu.w",1359Self::AmomaxuW => "amomaxu.w",1360Self::LrD => "lr.d",1361Self::ScD => "sc.d",1362Self::AmoswapD => "amoswap.d",1363Self::AmoaddD => "amoadd.d",1364Self::AmoxorD => "amoxor.d",1365Self::AmoandD => "amoand.d",1366Self::AmoorD => "amoor.d",1367Self::AmominD => "amomin.d",1368Self::AmomaxD => "amomax.d",1369Self::AmominuD => "amominu.d",1370Self::AmomaxuD => "amomaxu.d",1371};1372format!("{}{}", s, amo.to_static_str())1373}1374#[inline]1375pub(crate) fn op_code(self) -> u32 {13760b01011111377}13781379#[inline]1380pub(crate) fn funct7(self, amo: AMO) -> u32 {1381self.funct5() << 2 | amo.as_u32() & 0b111382}13831384pub(crate) fn funct3(self) -> u32 {1385match self {1386AtomicOP::LrW1387| AtomicOP::ScW1388| AtomicOP::AmoswapW1389| AtomicOP::AmoaddW1390| AtomicOP::AmoxorW1391| AtomicOP::AmoandW1392| AtomicOP::AmoorW1393| AtomicOP::AmominW1394| AtomicOP::AmomaxW1395| AtomicOP::AmominuW1396| AtomicOP::AmomaxuW => 0b010,1397AtomicOP::LrD1398| AtomicOP::ScD1399| AtomicOP::AmoswapD1400| AtomicOP::AmoaddD1401| AtomicOP::AmoxorD1402| AtomicOP::AmoandD1403| AtomicOP::AmoorD1404| AtomicOP::AmominD1405| AtomicOP::AmomaxD1406| AtomicOP::AmominuD1407| AtomicOP::AmomaxuD => 0b011,1408}1409}1410pub(crate) fn funct5(self) -> u32 {1411match self {1412AtomicOP::LrW => 0b00010,1413AtomicOP::ScW => 0b00011,1414AtomicOP::AmoswapW => 0b00001,1415AtomicOP::AmoaddW => 0b00000,1416AtomicOP::AmoxorW => 0b00100,1417AtomicOP::AmoandW => 0b01100,1418AtomicOP::AmoorW => 0b01000,1419AtomicOP::AmominW => 0b10000,1420AtomicOP::AmomaxW => 0b10100,1421AtomicOP::AmominuW => 0b11000,1422AtomicOP::AmomaxuW => 0b11100,1423AtomicOP::LrD => 0b00010,1424AtomicOP::ScD => 0b00011,1425AtomicOP::AmoswapD => 0b00001,1426AtomicOP::AmoaddD => 0b00000,1427AtomicOP::AmoxorD => 0b00100,1428AtomicOP::AmoandD => 0b01100,1429AtomicOP::AmoorD => 0b01000,1430AtomicOP::AmominD => 0b10000,1431AtomicOP::AmomaxD => 0b10100,1432AtomicOP::AmominuD => 0b11000,1433AtomicOP::AmomaxuD => 0b11100,1434}1435}14361437pub(crate) fn load_op(t: Type) -> Self {1438if t.bits() <= 32 { Self::LrW } else { Self::LrD }1439}1440pub(crate) fn store_op(t: Type) -> Self {1441if t.bits() <= 32 { Self::ScW } else { Self::ScD }1442}14431444/// extract1445pub(crate) fn extract(rd: WritableReg, offset: Reg, rs: Reg, ty: Type) -> SmallInstVec<Inst> {1446let mut insts = SmallInstVec::new();1447insts.push(Inst::AluRRR {1448alu_op: AluOPRRR::Srl,1449rd,1450rs1: rs,1451rs2: offset,1452});1453//1454insts.push(Inst::Extend {1455rd,1456rn: rd.to_reg(),1457signed: false,1458from_bits: ty.bits() as u8,1459to_bits: 64,1460});1461insts1462}14631464/// like extract but sign extend the value.1465/// suitable for smax,etc.1466pub(crate) fn extract_sext(1467rd: WritableReg,1468offset: Reg,1469rs: Reg,1470ty: Type,1471) -> SmallInstVec<Inst> {1472let mut insts = SmallInstVec::new();1473insts.push(Inst::AluRRR {1474alu_op: AluOPRRR::Srl,1475rd,1476rs1: rs,1477rs2: offset,1478});1479//1480insts.push(Inst::Extend {1481rd,1482rn: rd.to_reg(),1483signed: true,1484from_bits: ty.bits() as u8,1485to_bits: 64,1486});1487insts1488}14891490pub(crate) fn unset(1491rd: WritableReg,1492tmp: WritableReg,1493offset: Reg,1494ty: Type,1495) -> SmallInstVec<Inst> {1496assert!(rd != tmp);1497let mut insts = SmallInstVec::new();1498insts.extend(Inst::load_int_mask(tmp, ty));1499insts.push(Inst::AluRRR {1500alu_op: AluOPRRR::Sll,1501rd: tmp,1502rs1: tmp.to_reg(),1503rs2: offset,1504});1505insts.push(Inst::construct_bit_not(tmp, tmp.to_reg()));1506insts.push(Inst::AluRRR {1507alu_op: AluOPRRR::And,1508rd,1509rs1: rd.to_reg(),1510rs2: tmp.to_reg(),1511});1512insts1513}15141515pub(crate) fn set(1516rd: WritableReg,1517tmp: WritableReg,1518offset: Reg,1519rs: Reg,1520ty: Type,1521) -> SmallInstVec<Inst> {1522assert!(rd != tmp);1523let mut insts = SmallInstVec::new();1524// make rs into tmp.1525insts.push(Inst::Extend {1526rd: tmp,1527rn: rs,1528signed: false,1529from_bits: ty.bits() as u8,1530to_bits: 64,1531});1532insts.push(Inst::AluRRR {1533alu_op: AluOPRRR::Sll,1534rd: tmp,1535rs1: tmp.to_reg(),1536rs2: offset,1537});1538insts.push(Inst::AluRRR {1539alu_op: AluOPRRR::Or,1540rd,1541rs1: rd.to_reg(),1542rs2: tmp.to_reg(),1543});1544insts1545}15461547/// Merge reset part of rs into rd.1548/// Call this function must make sure that other part of value is already in rd.1549pub(crate) fn merge(1550rd: WritableReg,1551tmp: WritableReg,1552offset: Reg,1553rs: Reg,1554ty: Type,1555) -> SmallInstVec<Inst> {1556let mut insts = Self::unset(rd, tmp, offset, ty);1557insts.extend(Self::set(rd, tmp, offset, rs, ty));1558insts1559}1560}15611562///Atomic Memory ordering.1563#[derive(Copy, Clone, Debug)]1564pub enum AMO {1565Relax = 0b00,1566Release = 0b01,1567Acquire = 0b10,1568SeqCst = 0b11,1569}15701571impl AMO {1572pub(crate) fn to_static_str(self) -> &'static str {1573match self {1574AMO::Relax => "",1575AMO::Release => ".rl",1576AMO::Acquire => ".aq",1577AMO::SeqCst => ".aqrl",1578}1579}1580pub(crate) fn as_u32(self) -> u32 {1581self as u321582}1583}15841585impl Inst {1586/// fence request bits.1587pub(crate) const FENCE_REQ_I: u8 = 1 << 3;1588pub(crate) const FENCE_REQ_O: u8 = 1 << 2;1589pub(crate) const FENCE_REQ_R: u8 = 1 << 1;1590pub(crate) const FENCE_REQ_W: u8 = 1 << 0;1591pub(crate) fn fence_req_to_string(x: u8) -> String {1592let mut s = String::default();1593if x & Self::FENCE_REQ_I != 0 {1594s.push_str("i");1595}1596if x & Self::FENCE_REQ_O != 0 {1597s.push_str("o");1598}1599if x & Self::FENCE_REQ_R != 0 {1600s.push_str("r");1601}1602if x & Self::FENCE_REQ_W != 0 {1603s.push_str("w");1604}1605s1606}1607}16081609impl CsrRegOP {1610pub(crate) fn funct3(self) -> u32 {1611match self {1612CsrRegOP::CsrRW => 0b001,1613CsrRegOP::CsrRS => 0b010,1614CsrRegOP::CsrRC => 0b011,1615}1616}16171618pub(crate) fn opcode(self) -> u32 {16190b11100111620}16211622pub(crate) fn name(self) -> &'static str {1623match self {1624CsrRegOP::CsrRW => "csrrw",1625CsrRegOP::CsrRS => "csrrs",1626CsrRegOP::CsrRC => "csrrc",1627}1628}1629}16301631impl Display for CsrRegOP {1632fn fmt(&self, f: &mut Formatter<'_>) -> Result {1633write!(f, "{}", self.name())1634}1635}16361637impl CsrImmOP {1638pub(crate) fn funct3(self) -> u32 {1639match self {1640CsrImmOP::CsrRWI => 0b101,1641CsrImmOP::CsrRSI => 0b110,1642CsrImmOP::CsrRCI => 0b111,1643}1644}16451646pub(crate) fn opcode(self) -> u32 {16470b11100111648}16491650pub(crate) fn name(self) -> &'static str {1651match self {1652CsrImmOP::CsrRWI => "csrrwi",1653CsrImmOP::CsrRSI => "csrrsi",1654CsrImmOP::CsrRCI => "csrrci",1655}1656}1657}16581659impl Display for CsrImmOP {1660fn fmt(&self, f: &mut Formatter<'_>) -> Result {1661write!(f, "{}", self.name())1662}1663}16641665impl CSR {1666pub(crate) fn bits(self) -> Imm12 {1667Imm12::from_i16(match self {1668CSR::Frm => 0x0002,1669})1670}16711672pub(crate) fn name(self) -> &'static str {1673match self {1674CSR::Frm => "frm",1675}1676}1677}16781679impl Display for CSR {1680fn fmt(&self, f: &mut Formatter<'_>) -> Result {1681write!(f, "{}", self.name())1682}1683}16841685impl COpcodeSpace {1686pub fn bits(&self) -> u32 {1687match self {1688COpcodeSpace::C0 => 0b00,1689COpcodeSpace::C1 => 0b01,1690COpcodeSpace::C2 => 0b10,1691}1692}1693}16941695impl CrOp {1696pub fn funct4(&self) -> u32 {1697// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1698match self {1699// `c.jr` has the same op/funct4 as C.MV, but RS2 is 0, which is illegal for mv.1700CrOp::CMv | CrOp::CJr => 0b1000,1701CrOp::CAdd | CrOp::CJalr | CrOp::CEbreak => 0b1001,1702}1703}17041705pub fn op(&self) -> COpcodeSpace {1706// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1707match self {1708CrOp::CMv | CrOp::CAdd | CrOp::CJr | CrOp::CJalr | CrOp::CEbreak => COpcodeSpace::C2,1709}1710}1711}17121713impl CaOp {1714pub fn funct2(&self) -> u32 {1715// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1716match self {1717CaOp::CAnd => 0b11,1718CaOp::COr => 0b10,1719CaOp::CXor => 0b01,1720CaOp::CSub => 0b00,1721CaOp::CAddw => 0b01,1722CaOp::CSubw => 0b00,1723CaOp::CMul => 0b10,1724}1725}17261727pub fn funct6(&self) -> u32 {1728// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1729match self {1730CaOp::CAnd | CaOp::COr | CaOp::CXor | CaOp::CSub => 0b100_011,1731CaOp::CSubw | CaOp::CAddw | CaOp::CMul => 0b100_111,1732}1733}17341735pub fn op(&self) -> COpcodeSpace {1736// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1737match self {1738CaOp::CAnd1739| CaOp::COr1740| CaOp::CXor1741| CaOp::CSub1742| CaOp::CAddw1743| CaOp::CSubw1744| CaOp::CMul => COpcodeSpace::C1,1745}1746}1747}17481749impl CjOp {1750pub fn funct3(&self) -> u32 {1751// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1752match self {1753CjOp::CJ => 0b101,1754}1755}17561757pub fn op(&self) -> COpcodeSpace {1758// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1759match self {1760CjOp::CJ => COpcodeSpace::C1,1761}1762}1763}17641765impl CiOp {1766pub fn funct3(&self) -> u32 {1767// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1768match self {1769CiOp::CAddi | CiOp::CSlli => 0b000,1770CiOp::CAddiw | CiOp::CFldsp => 0b001,1771CiOp::CLi | CiOp::CLwsp => 0b010,1772CiOp::CAddi16sp | CiOp::CLui | CiOp::CLdsp => 0b011,1773}1774}17751776pub fn op(&self) -> COpcodeSpace {1777// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1778match self {1779CiOp::CAddi | CiOp::CAddiw | CiOp::CAddi16sp | CiOp::CLi | CiOp::CLui => {1780COpcodeSpace::C11781}1782CiOp::CSlli | CiOp::CLwsp | CiOp::CLdsp | CiOp::CFldsp => COpcodeSpace::C2,1783}1784}1785}17861787impl CiwOp {1788pub fn funct3(&self) -> u32 {1789// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1790match self {1791CiwOp::CAddi4spn => 0b000,1792}1793}17941795pub fn op(&self) -> COpcodeSpace {1796// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1797match self {1798CiwOp::CAddi4spn => COpcodeSpace::C0,1799}1800}1801}18021803impl CbOp {1804pub fn funct3(&self) -> u32 {1805// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1806match self {1807CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => 0b100,1808}1809}18101811pub fn funct2(&self) -> u32 {1812// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1813match self {1814CbOp::CSrli => 0b00,1815CbOp::CSrai => 0b01,1816CbOp::CAndi => 0b10,1817}1818}18191820pub fn op(&self) -> COpcodeSpace {1821// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1822match self {1823CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => COpcodeSpace::C1,1824}1825}1826}18271828impl CssOp {1829pub fn funct3(&self) -> u32 {1830// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1831match self {1832CssOp::CFsdsp => 0b101,1833CssOp::CSwsp => 0b110,1834CssOp::CSdsp => 0b111,1835}1836}18371838pub fn op(&self) -> COpcodeSpace {1839// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1840match self {1841CssOp::CSwsp | CssOp::CSdsp | CssOp::CFsdsp => COpcodeSpace::C2,1842}1843}1844}18451846impl CsOp {1847pub fn funct3(&self) -> u32 {1848// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1849match self {1850CsOp::CFsd => 0b101,1851CsOp::CSw => 0b110,1852CsOp::CSd => 0b111,1853}1854}18551856pub fn op(&self) -> COpcodeSpace {1857// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1858match self {1859CsOp::CSw | CsOp::CSd | CsOp::CFsd => COpcodeSpace::C0,1860}1861}1862}18631864impl ClOp {1865pub fn funct3(&self) -> u32 {1866// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1867match self {1868ClOp::CFld => 0b001,1869ClOp::CLw => 0b010,1870ClOp::CLd => 0b011,1871}1872}18731874pub fn op(&self) -> COpcodeSpace {1875// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1876match self {1877ClOp::CLw | ClOp::CLd | ClOp::CFld => COpcodeSpace::C0,1878}1879}1880}18811882impl CsznOp {1883pub fn funct6(&self) -> u32 {1884// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1885match self {1886CsznOp::CNot1887| CsznOp::CZextw1888| CsznOp::CZextb1889| CsznOp::CZexth1890| CsznOp::CSextb1891| CsznOp::CSexth => 0b100_111,1892}1893}18941895pub fn funct5(&self) -> u32 {1896// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1897match self {1898CsznOp::CNot => 0b11_101,1899CsznOp::CZextb => 0b11_000,1900CsznOp::CZexth => 0b11_010,1901CsznOp::CZextw => 0b11_100,1902CsznOp::CSextb => 0b11_001,1903CsznOp::CSexth => 0b11_011,1904}1905}19061907pub fn op(&self) -> COpcodeSpace {1908// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1909match self {1910CsznOp::CNot1911| CsznOp::CZextb1912| CsznOp::CZexth1913| CsznOp::CZextw1914| CsznOp::CSextb1915| CsznOp::CSexth => COpcodeSpace::C1,1916}1917}1918}19191920impl ZcbMemOp {1921pub fn funct6(&self) -> u32 {1922// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes1923match self {1924ZcbMemOp::CLbu => 0b100_000,1925// These two opcodes are differentiated in the imm field of the instruction.1926ZcbMemOp::CLhu | ZcbMemOp::CLh => 0b100_001,1927ZcbMemOp::CSb => 0b100_010,1928ZcbMemOp::CSh => 0b100_011,1929}1930}19311932pub fn imm_bits(&self) -> u8 {1933match self {1934ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSh => 1,1935ZcbMemOp::CLbu | ZcbMemOp::CSb => 2,1936}1937}19381939pub fn op(&self) -> COpcodeSpace {1940// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap1941match self {1942ZcbMemOp::CLbu | ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSb | ZcbMemOp::CSh => {1943COpcodeSpace::C01944}1945}1946}1947}194819491950