mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-16 15:38:48 +00:00
Add fmt to kecc IR and Assembly (#7)
* Add fmt to kecc ir structs * Add fmt for KECC asm
This commit is contained in:
401
src/asm/mod.rs
401
src/asm/mod.rs
@@ -1,8 +1,10 @@
|
|||||||
mod write_asm;
|
mod write_asm;
|
||||||
|
|
||||||
use crate::ir;
|
use crate::ir;
|
||||||
|
use crate::write_base::*;
|
||||||
|
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Todo {}
|
pub struct Todo {}
|
||||||
@@ -21,7 +23,7 @@ pub struct TranslationUnit {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Section<T> {
|
pub struct Section<T> {
|
||||||
/// Section Headers provice size, offset, type, alignment and flags of the sections
|
/// Section Headers provide size, offset, type, alignment and flags of the sections
|
||||||
///
|
///
|
||||||
/// For more details: <https://github.com/michaeljclark/michaeljclark.github.io/blob/master/asm.md#section-header>
|
/// For more details: <https://github.com/michaeljclark/michaeljclark.github.io/blob/master/asm.md#section-header>
|
||||||
pub header: Vec<Directive>,
|
pub header: Vec<Directive>,
|
||||||
@@ -115,6 +117,24 @@ impl Directive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Directive {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Align(value) => write!(f, ".align\t{}", value),
|
||||||
|
Self::Globl(label) => write!(f, ".globl\t{}", label),
|
||||||
|
Self::Type(symbol, symbol_type) => {
|
||||||
|
write!(f, ".type\t{}, {}", symbol, symbol_type)
|
||||||
|
}
|
||||||
|
Self::Section(section_type) => write!(f, ".section\t{}", section_type),
|
||||||
|
Self::Byte(value) => write!(f, ".byte\t{:#x?}", value),
|
||||||
|
Self::Half(value) => write!(f, ".half\t{:#x?}", value),
|
||||||
|
Self::Word(value) => write!(f, ".word\t{:#x?}", value),
|
||||||
|
Self::Quad(value) => write!(f, ".quad\t{:#x?}", value),
|
||||||
|
Self::Zero(bytes) => write!(f, ".zero\t{:#x?}", bytes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum SectionType {
|
pub enum SectionType {
|
||||||
Text,
|
Text,
|
||||||
@@ -123,12 +143,40 @@ pub enum SectionType {
|
|||||||
Bss,
|
Bss,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SectionType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Text => ".text",
|
||||||
|
Self::Data => ".data",
|
||||||
|
Self::Rodata => ".rodata",
|
||||||
|
Self::Bss => ".bss",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum SymbolType {
|
pub enum SymbolType {
|
||||||
Function,
|
Function,
|
||||||
Object,
|
Object,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SymbolType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Function => "@function",
|
||||||
|
Self::Object => "@object",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
/// R-type instruction format
|
/// R-type instruction format
|
||||||
@@ -175,6 +223,66 @@ pub enum Instruction {
|
|||||||
Pseudo(Pseudo),
|
Pseudo(Pseudo),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Instruction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::RType {
|
||||||
|
instr,
|
||||||
|
rd,
|
||||||
|
rs1,
|
||||||
|
rs2,
|
||||||
|
} => {
|
||||||
|
let rounding_mode = if let RType::FcvtFloatToInt { .. } = instr {
|
||||||
|
",rtz"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}\t{},{}{}{}",
|
||||||
|
instr,
|
||||||
|
rd,
|
||||||
|
rs1,
|
||||||
|
if let Some(rs2) = rs2 {
|
||||||
|
format!(",{}", rs2)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
},
|
||||||
|
rounding_mode
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::IType {
|
||||||
|
instr,
|
||||||
|
rd,
|
||||||
|
rs1,
|
||||||
|
imm,
|
||||||
|
} => {
|
||||||
|
if let IType::Load { .. } = instr {
|
||||||
|
write!(f, "{}\t{},{}({})", instr, rd, imm, rs1)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}\t{},{},{}", instr, rd, rs1, imm,)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::SType {
|
||||||
|
instr,
|
||||||
|
rs1,
|
||||||
|
rs2,
|
||||||
|
imm,
|
||||||
|
} => write!(f, "{}\t{},{}({})", instr, rs2, imm, rs1),
|
||||||
|
Self::BType {
|
||||||
|
instr,
|
||||||
|
rs1,
|
||||||
|
rs2,
|
||||||
|
imm,
|
||||||
|
} => write!(f, "{}\t{},{}, {}", instr, rs1, rs2, imm.0,),
|
||||||
|
Self::UType { instr, rd, imm } => write!(f, "{}\t{}, {}", instr, rd, imm,),
|
||||||
|
Self::Pseudo(pseudo) => write!(f, "{}", pseudo),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// If the enum variant contains `bool`,
|
/// If the enum variant contains `bool`,
|
||||||
/// It means that different instructions exist
|
/// It means that different instructions exist
|
||||||
/// depending on whether the operand is signed or not.
|
/// depending on whether the operand is signed or not.
|
||||||
@@ -405,6 +513,114 @@ impl RType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Add(data_size) => write!(f, "add{}", data_size.word().write_string()),
|
||||||
|
Self::Sub(data_size) => write!(f, "sub{}", data_size.word().write_string()),
|
||||||
|
Self::Sll(data_size) => write!(f, "sll{}", data_size.word().write_string()),
|
||||||
|
Self::Srl(data_size) => write!(f, "srl{}", data_size.word().write_string()),
|
||||||
|
Self::Sra(data_size) => write!(f, "sra{}", data_size.word().write_string()),
|
||||||
|
Self::Mul(data_size) => write!(f, "mul{}", data_size.word().write_string()),
|
||||||
|
Self::Div {
|
||||||
|
data_size,
|
||||||
|
is_signed,
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"div{}{}",
|
||||||
|
if *is_signed { "" } else { "u" },
|
||||||
|
data_size.word().write_string()
|
||||||
|
),
|
||||||
|
Self::Rem {
|
||||||
|
data_size,
|
||||||
|
is_signed,
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"rem{}{}",
|
||||||
|
if *is_signed { "" } else { "u" },
|
||||||
|
data_size.word().write_string()
|
||||||
|
),
|
||||||
|
Self::Slt { is_signed } => write!(f, "slt{}", if *is_signed { "" } else { "u" }),
|
||||||
|
Self::Xor => write!(f, "xor"),
|
||||||
|
Self::Or => write!(f, "or"),
|
||||||
|
Self::And => write!(f, "and"),
|
||||||
|
Self::Fadd(data_size) => write!(f, "fadd.{}", data_size),
|
||||||
|
Self::Fsub(data_size) => write!(f, "fsub.{}", data_size),
|
||||||
|
Self::Fmul(data_size) => write!(f, "fmul.{}", data_size),
|
||||||
|
Self::Fdiv(data_size) => write!(f, "fdiv.{}", data_size),
|
||||||
|
Self::Feq(data_size) => write!(f, "feq.{}", data_size),
|
||||||
|
Self::Flt(data_size) => write!(f, "flt.{}", data_size),
|
||||||
|
Self::FmvFloatToInt { float_data_size } => {
|
||||||
|
assert!(float_data_size.is_floating_point());
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"fmv.x.{}",
|
||||||
|
if *float_data_size == DataSize::SinglePrecision {
|
||||||
|
"w"
|
||||||
|
} else {
|
||||||
|
"d"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::FmvIntToFloat { float_data_size } => {
|
||||||
|
assert!(float_data_size.is_floating_point());
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"fmv.{}.x",
|
||||||
|
if *float_data_size == DataSize::SinglePrecision {
|
||||||
|
"w"
|
||||||
|
} else {
|
||||||
|
"d"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::FcvtFloatToInt {
|
||||||
|
float_data_size,
|
||||||
|
int_data_size,
|
||||||
|
is_signed,
|
||||||
|
} => {
|
||||||
|
assert!(float_data_size.is_floating_point());
|
||||||
|
assert!(matches!(int_data_size, DataSize::Word | DataSize::Double));
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"fcvt.{}{}.{}",
|
||||||
|
if matches!(int_data_size, DataSize::Word) {
|
||||||
|
"w"
|
||||||
|
} else {
|
||||||
|
"l"
|
||||||
|
},
|
||||||
|
if *is_signed { "" } else { "u" },
|
||||||
|
float_data_size
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::FcvtIntToFloat {
|
||||||
|
int_data_size,
|
||||||
|
float_data_size,
|
||||||
|
is_signed,
|
||||||
|
} => {
|
||||||
|
assert!(float_data_size.is_floating_point());
|
||||||
|
assert!(matches!(int_data_size, DataSize::Word | DataSize::Double));
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"fcvt.{}.{}{}",
|
||||||
|
float_data_size,
|
||||||
|
if matches!(int_data_size, DataSize::Word) {
|
||||||
|
"w"
|
||||||
|
} else {
|
||||||
|
"l"
|
||||||
|
},
|
||||||
|
if *is_signed { "" } else { "u" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::FcvtFloatToFloat { from, to } => {
|
||||||
|
assert!(from.is_floating_point());
|
||||||
|
assert!(to.is_floating_point());
|
||||||
|
write!(f, "fcvt.{}.{}", to, from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum IType {
|
pub enum IType {
|
||||||
Load {
|
Load {
|
||||||
@@ -481,6 +697,39 @@ impl IType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for IType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Load {
|
||||||
|
data_size,
|
||||||
|
is_signed,
|
||||||
|
} => {
|
||||||
|
if data_size.is_integer() {
|
||||||
|
write!(f, "l{}{}", data_size, if *is_signed { "" } else { "u" })
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"fl{}",
|
||||||
|
if *data_size == DataSize::SinglePrecision {
|
||||||
|
"w"
|
||||||
|
} else {
|
||||||
|
"d"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Addi(data_size) => write!(f, "addi{}", data_size.word().write_string()),
|
||||||
|
Self::Xori => write!(f, "xori"),
|
||||||
|
Self::Ori => write!(f, "ori"),
|
||||||
|
Self::Andi => write!(f, "andi"),
|
||||||
|
Self::Slli(data_size) => write!(f, "slli{}", data_size.word().write_string()),
|
||||||
|
Self::Srli(data_size) => write!(f, "srli{}", data_size.word().write_string()),
|
||||||
|
Self::Srai(data_size) => write!(f, "srai{}", data_size.word().write_string()),
|
||||||
|
Self::Slti { is_signed } => write!(f, "slti{}", if *is_signed { "" } else { "u" }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum SType {
|
pub enum SType {
|
||||||
Store(DataSize),
|
Store(DataSize),
|
||||||
@@ -497,6 +746,28 @@ impl SType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Store(data_size) => {
|
||||||
|
if data_size.is_integer() {
|
||||||
|
write!(f, "s{}", data_size)
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"fs{}",
|
||||||
|
if *data_size == DataSize::SinglePrecision {
|
||||||
|
"w"
|
||||||
|
} else {
|
||||||
|
"d"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum BType {
|
pub enum BType {
|
||||||
Beq,
|
Beq,
|
||||||
@@ -505,11 +776,34 @@ pub enum BType {
|
|||||||
Bge { is_signed: bool },
|
Bge { is_signed: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Beq => "beq".to_string(),
|
||||||
|
Self::Bne => "bne".to_string(),
|
||||||
|
Self::Blt { is_signed } => format!("blt{}", if *is_signed { "" } else { "u" }),
|
||||||
|
Self::Bge { is_signed } => format!("bge{}", if *is_signed { "" } else { "u" }),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum UType {
|
pub enum UType {
|
||||||
Lui,
|
Lui,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for UType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Lui => write!(f, "lui"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The assembler implements a number of convenience psuedo-instructions that are formed from
|
/// The assembler implements a number of convenience psuedo-instructions that are formed from
|
||||||
/// instructions in the base ISA, but have implicit arguments or in some case reversed arguments,
|
/// instructions in the base ISA, but have implicit arguments or in some case reversed arguments,
|
||||||
/// that result in distinct semantics.
|
/// that result in distinct semantics.
|
||||||
@@ -583,6 +877,31 @@ impl Pseudo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Pseudo {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::La { rd, symbol } => write!(f, "la\t{},{}", rd, symbol),
|
||||||
|
Self::Li { rd, imm } => write!(f, "li\t{},{}", rd, *imm as i64),
|
||||||
|
Self::Mv { rd, rs } => write!(f, "mv\t{},{}", rd, rs),
|
||||||
|
Self::Fmv { data_size, rd, rs } => write!(f, "fmv.{}\t{},{}", data_size, rd, rs),
|
||||||
|
Self::Neg { data_size, rd, rs } => {
|
||||||
|
write!(f, "neg{}\t{},{}", data_size.word().write_string(), rd, rs)
|
||||||
|
}
|
||||||
|
Self::SextW { rs, rd } => {
|
||||||
|
write!(f, "sext.w\t{},{}", rd, rs)
|
||||||
|
}
|
||||||
|
Self::Seqz { rd, rs } => write!(f, "seqz\t{},{}", rd, rs),
|
||||||
|
Self::Snez { rd, rs } => write!(f, "snez\t{},{}", rd, rs),
|
||||||
|
Self::Fneg { data_size, rd, rs } => write!(f, "fneg.{}\t{},{}", data_size, rd, rs),
|
||||||
|
Self::J { offset } => write!(f, "j\t{}", offset),
|
||||||
|
Self::Jr { rs } => write!(f, "jr\t{}", rs),
|
||||||
|
Self::Jalr { rs } => write!(f, "jalr\t{}", rs),
|
||||||
|
Self::Ret => write!(f, "ret"),
|
||||||
|
Self::Call { offset } => write!(f, "call\t{}", offset),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Immediate {
|
pub enum Immediate {
|
||||||
// TODO: consider architecture dependency (current: 64-bit architecture)
|
// TODO: consider architecture dependency (current: 64-bit architecture)
|
||||||
@@ -600,6 +919,21 @@ impl Immediate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Immediate {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Value(value) => format!("{}", *value as i64),
|
||||||
|
Self::Relocation { relocation, symbol } => {
|
||||||
|
format!("{}({})", relocation, symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The relocation function creates synthesize operand values that are resolved
|
/// The relocation function creates synthesize operand values that are resolved
|
||||||
/// at program link time and are used as immediate parameters to specific instructions.
|
/// at program link time and are used as immediate parameters to specific instructions.
|
||||||
///
|
///
|
||||||
@@ -612,6 +946,19 @@ pub enum RelocationFunction {
|
|||||||
Lo12,
|
Lo12,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RelocationFunction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Hi20 => "%hi",
|
||||||
|
Self::Lo12 => "%lo",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `Label` is used as branch, unconditional jump targets and symbol offsets.
|
/// `Label` is used as branch, unconditional jump targets and symbol offsets.
|
||||||
///
|
///
|
||||||
/// For more details: <https://github.com/michaeljclark/michaeljclark.github.io/blob/master/asm.md#labels>
|
/// For more details: <https://github.com/michaeljclark/michaeljclark.github.io/blob/master/asm.md#labels>
|
||||||
@@ -625,6 +972,12 @@ impl Label {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Label {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum DataSize {
|
pub enum DataSize {
|
||||||
Byte,
|
Byte,
|
||||||
@@ -684,6 +1037,23 @@ impl DataSize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DataSize {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Byte => "b",
|
||||||
|
Self::Half => "h",
|
||||||
|
Self::Word => "w",
|
||||||
|
Self::Double => "d",
|
||||||
|
Self::SinglePrecision => "s",
|
||||||
|
Self::DoublePrecision => "d",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Add calling convention information (caller/callee-save registers)
|
// TODO: Add calling convention information (caller/callee-save registers)
|
||||||
/// ABI name for RISC-V integer and floating-point register
|
/// ABI name for RISC-V integer and floating-point register
|
||||||
///
|
///
|
||||||
@@ -789,8 +1159,37 @@ impl Register {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Register {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let register = match self {
|
||||||
|
Self::Zero => "zero".to_string(),
|
||||||
|
Self::Ra => "ra".to_string(),
|
||||||
|
Self::Sp => "sp".to_string(),
|
||||||
|
Self::Gp => "gp".to_string(),
|
||||||
|
Self::Tp => "tp".to_string(),
|
||||||
|
Self::Temp(register_type, id) => format!("{}t{}", register_type, id),
|
||||||
|
Self::Saved(register_type, id) => format!("{}s{}", register_type, id),
|
||||||
|
Self::Arg(register_type, id) => format!("{}a{}", register_type, id),
|
||||||
|
};
|
||||||
|
write!(f, "{}", register)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
|
||||||
pub enum RegisterType {
|
pub enum RegisterType {
|
||||||
Integer,
|
Integer,
|
||||||
FloatingPoint,
|
FloatingPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RegisterType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::FloatingPoint => "f",
|
||||||
|
Self::Integer => "",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -76,418 +76,84 @@ impl WriteLine for Block {
|
|||||||
|
|
||||||
impl WriteString for Directive {
|
impl WriteString for Directive {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Align(value) => format!(".align\t{}", value),
|
|
||||||
Self::Globl(label) => format!(".globl\t{}", label.0),
|
|
||||||
Self::Type(symbol, symbol_type) => {
|
|
||||||
format!(".type\t{}, {}", symbol.0, symbol_type.write_string())
|
|
||||||
}
|
|
||||||
Self::Section(section_type) => format!(".section\t{}", section_type.write_string()),
|
|
||||||
Self::Byte(value) => format!(".byte\t{:#x?}", value),
|
|
||||||
Self::Half(value) => format!(".half\t{:#x?}", value),
|
|
||||||
Self::Word(value) => format!(".word\t{:#x?}", value),
|
|
||||||
Self::Quad(value) => format!(".quad\t{:#x?}", value),
|
|
||||||
Self::Zero(bytes) => format!(".zero\t{:#x?}", bytes),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for SectionType {
|
impl WriteString for SectionType {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Text => ".text",
|
|
||||||
Self::Data => ".data",
|
|
||||||
Self::Rodata => ".rodata",
|
|
||||||
Self::Bss => ".bss",
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for SymbolType {
|
impl WriteString for SymbolType {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Function => "@function",
|
|
||||||
Self::Object => "@object",
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for Instruction {
|
impl WriteString for Instruction {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::RType {
|
|
||||||
instr,
|
|
||||||
rd,
|
|
||||||
rs1,
|
|
||||||
rs2,
|
|
||||||
} => {
|
|
||||||
let rounding_mode = if let RType::FcvtFloatToInt { .. } = instr {
|
|
||||||
",rtz"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
format!(
|
|
||||||
"{}\t{},{}{}{}",
|
|
||||||
instr.write_string(),
|
|
||||||
rd.write_string(),
|
|
||||||
rs1.write_string(),
|
|
||||||
if let Some(rs2) = rs2 {
|
|
||||||
format!(",{}", rs2.write_string())
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
},
|
|
||||||
rounding_mode
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::IType {
|
|
||||||
instr,
|
|
||||||
rd,
|
|
||||||
rs1,
|
|
||||||
imm,
|
|
||||||
} => {
|
|
||||||
if let IType::Load { .. } = instr {
|
|
||||||
format!(
|
|
||||||
"{}\t{},{}({})",
|
|
||||||
instr.write_string(),
|
|
||||||
rd.write_string(),
|
|
||||||
imm.write_string(),
|
|
||||||
rs1.write_string()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"{}\t{},{},{}",
|
|
||||||
instr.write_string(),
|
|
||||||
rd.write_string(),
|
|
||||||
rs1.write_string(),
|
|
||||||
imm.write_string(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self::SType {
|
|
||||||
instr,
|
|
||||||
rs1,
|
|
||||||
rs2,
|
|
||||||
imm,
|
|
||||||
} => format!(
|
|
||||||
"{}\t{},{}({})",
|
|
||||||
instr.write_string(),
|
|
||||||
rs2.write_string(),
|
|
||||||
imm.write_string(),
|
|
||||||
rs1.write_string()
|
|
||||||
),
|
|
||||||
Self::BType {
|
|
||||||
instr,
|
|
||||||
rs1,
|
|
||||||
rs2,
|
|
||||||
imm,
|
|
||||||
} => format!(
|
|
||||||
"{}\t{},{}, {}",
|
|
||||||
instr.write_string(),
|
|
||||||
rs1.write_string(),
|
|
||||||
rs2.write_string(),
|
|
||||||
imm.0,
|
|
||||||
),
|
|
||||||
Self::UType { instr, rd, imm } => format!(
|
|
||||||
"{}\t{}, {}",
|
|
||||||
instr.write_string(),
|
|
||||||
rd.write_string(),
|
|
||||||
imm.write_string(),
|
|
||||||
),
|
|
||||||
Self::Pseudo(pseudo) => pseudo.write_string(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for RType {
|
impl WriteString for RType {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Add(data_size) => format!("add{}", data_size.word().write_string()),
|
|
||||||
Self::Sub(data_size) => format!("sub{}", data_size.word().write_string()),
|
|
||||||
Self::Sll(data_size) => format!("sll{}", data_size.word().write_string()),
|
|
||||||
Self::Srl(data_size) => format!("srl{}", data_size.word().write_string()),
|
|
||||||
Self::Sra(data_size) => format!("sra{}", data_size.word().write_string()),
|
|
||||||
Self::Mul(data_size) => format!("mul{}", data_size.word().write_string()),
|
|
||||||
Self::Div {
|
|
||||||
data_size,
|
|
||||||
is_signed,
|
|
||||||
} => format!(
|
|
||||||
"div{}{}",
|
|
||||||
if *is_signed { "" } else { "u" },
|
|
||||||
data_size.word().write_string()
|
|
||||||
),
|
|
||||||
Self::Rem {
|
|
||||||
data_size,
|
|
||||||
is_signed,
|
|
||||||
} => format!(
|
|
||||||
"rem{}{}",
|
|
||||||
if *is_signed { "" } else { "u" },
|
|
||||||
data_size.word().write_string()
|
|
||||||
),
|
|
||||||
Self::Slt { is_signed } => format!("slt{}", if *is_signed { "" } else { "u" }),
|
|
||||||
Self::Xor => "xor".to_string(),
|
|
||||||
Self::Or => "or".to_string(),
|
|
||||||
Self::And => "and".to_string(),
|
|
||||||
Self::Fadd(data_size) => format!("fadd.{}", data_size.write_string()),
|
|
||||||
Self::Fsub(data_size) => format!("fsub.{}", data_size.write_string()),
|
|
||||||
Self::Fmul(data_size) => format!("fmul.{}", data_size.write_string()),
|
|
||||||
Self::Fdiv(data_size) => format!("fdiv.{}", data_size.write_string()),
|
|
||||||
Self::Feq(data_size) => format!("feq.{}", data_size.write_string()),
|
|
||||||
Self::Flt(data_size) => format!("flt.{}", data_size.write_string()),
|
|
||||||
Self::FmvFloatToInt { float_data_size } => {
|
|
||||||
assert!(float_data_size.is_floating_point());
|
|
||||||
format!(
|
|
||||||
"fmv.x.{}",
|
|
||||||
if *float_data_size == DataSize::SinglePrecision {
|
|
||||||
"w"
|
|
||||||
} else {
|
|
||||||
"d"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::FmvIntToFloat { float_data_size } => {
|
|
||||||
assert!(float_data_size.is_floating_point());
|
|
||||||
format!(
|
|
||||||
"fmv.{}.x",
|
|
||||||
if *float_data_size == DataSize::SinglePrecision {
|
|
||||||
"w"
|
|
||||||
} else {
|
|
||||||
"d"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::FcvtFloatToInt {
|
|
||||||
float_data_size,
|
|
||||||
int_data_size,
|
|
||||||
is_signed,
|
|
||||||
} => {
|
|
||||||
assert!(float_data_size.is_floating_point());
|
|
||||||
assert!(matches!(int_data_size, DataSize::Word | DataSize::Double));
|
|
||||||
format!(
|
|
||||||
"fcvt.{}{}.{}",
|
|
||||||
if matches!(int_data_size, DataSize::Word) {
|
|
||||||
"w"
|
|
||||||
} else {
|
|
||||||
"l"
|
|
||||||
},
|
|
||||||
if *is_signed { "" } else { "u" },
|
|
||||||
float_data_size.write_string()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::FcvtIntToFloat {
|
|
||||||
int_data_size,
|
|
||||||
float_data_size,
|
|
||||||
is_signed,
|
|
||||||
} => {
|
|
||||||
assert!(float_data_size.is_floating_point());
|
|
||||||
assert!(matches!(int_data_size, DataSize::Word | DataSize::Double));
|
|
||||||
format!(
|
|
||||||
"fcvt.{}.{}{}",
|
|
||||||
float_data_size.write_string(),
|
|
||||||
if matches!(int_data_size, DataSize::Word) {
|
|
||||||
"w"
|
|
||||||
} else {
|
|
||||||
"l"
|
|
||||||
},
|
|
||||||
if *is_signed { "" } else { "u" }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::FcvtFloatToFloat { from, to } => {
|
|
||||||
assert!(from.is_floating_point());
|
|
||||||
assert!(to.is_floating_point());
|
|
||||||
format!("fcvt.{}.{}", to.write_string(), from.write_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for IType {
|
impl WriteString for IType {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Load {
|
|
||||||
data_size,
|
|
||||||
is_signed,
|
|
||||||
} => {
|
|
||||||
if data_size.is_integer() {
|
|
||||||
format!(
|
|
||||||
"l{}{}",
|
|
||||||
data_size.write_string(),
|
|
||||||
if *is_signed { "" } else { "u" }
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"fl{}",
|
|
||||||
if *data_size == DataSize::SinglePrecision {
|
|
||||||
"w"
|
|
||||||
} else {
|
|
||||||
"d"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self::Addi(data_size) => format!("addi{}", data_size.word().write_string()),
|
|
||||||
Self::Xori => "xori".to_string(),
|
|
||||||
Self::Ori => "ori".to_string(),
|
|
||||||
Self::Andi => "andi".to_string(),
|
|
||||||
Self::Slli(data_size) => format!("slli{}", data_size.word().write_string()),
|
|
||||||
Self::Srli(data_size) => format!("srli{}", data_size.word().write_string()),
|
|
||||||
Self::Srai(data_size) => format!("srai{}", data_size.word().write_string()),
|
|
||||||
Self::Slti { is_signed } => format!("slti{}", if *is_signed { "" } else { "u" }),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for SType {
|
impl WriteString for SType {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Store(data_size) => {
|
|
||||||
if data_size.is_integer() {
|
|
||||||
format!("s{}", data_size.write_string())
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"fs{}",
|
|
||||||
if *data_size == DataSize::SinglePrecision {
|
|
||||||
"w"
|
|
||||||
} else {
|
|
||||||
"d"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for BType {
|
impl WriteString for BType {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Beq => "beq".to_string(),
|
|
||||||
Self::Bne => "bne".to_string(),
|
|
||||||
Self::Blt { is_signed } => format!("blt{}", if *is_signed { "" } else { "u" }),
|
|
||||||
Self::Bge { is_signed } => format!("bge{}", if *is_signed { "" } else { "u" }),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for UType {
|
impl WriteString for UType {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Lui => "lui".to_string(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for Pseudo {
|
impl WriteString for Pseudo {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::La { rd, symbol } => format!("la\t{},{}", rd.write_string(), symbol.0),
|
|
||||||
Self::Li { rd, imm } => format!("li\t{},{}", rd.write_string(), *imm as i64),
|
|
||||||
Self::Mv { rd, rs } => format!("mv\t{},{}", rd.write_string(), rs.write_string()),
|
|
||||||
Self::Fmv { data_size, rd, rs } => format!(
|
|
||||||
"fmv.{}\t{},{}",
|
|
||||||
data_size.write_string(),
|
|
||||||
rd.write_string(),
|
|
||||||
rs.write_string()
|
|
||||||
),
|
|
||||||
Self::Neg { data_size, rd, rs } => format!(
|
|
||||||
"neg{}\t{},{}",
|
|
||||||
data_size.word().write_string(),
|
|
||||||
rd.write_string(),
|
|
||||||
rs.write_string()
|
|
||||||
),
|
|
||||||
Self::SextW { rs, rd } => {
|
|
||||||
format!("sext.w\t{},{}", rd.write_string(), rs.write_string())
|
|
||||||
}
|
|
||||||
Self::Seqz { rd, rs } => format!("seqz\t{},{}", rd.write_string(), rs.write_string()),
|
|
||||||
Self::Snez { rd, rs } => format!("snez\t{},{}", rd.write_string(), rs.write_string()),
|
|
||||||
Self::Fneg { data_size, rd, rs } => format!(
|
|
||||||
"fneg.{}\t{},{}",
|
|
||||||
data_size.write_string(),
|
|
||||||
rd.write_string(),
|
|
||||||
rs.write_string()
|
|
||||||
),
|
|
||||||
Self::J { offset } => format!("j\t{}", offset.0),
|
|
||||||
Self::Jr { rs } => format!("jr\t{}", rs.write_string()),
|
|
||||||
Self::Jalr { rs } => format!("jalr\t{}", rs.write_string()),
|
|
||||||
Self::Ret => "ret".to_string(),
|
|
||||||
Self::Call { offset } => format!("call\t{}", offset.0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for Immediate {
|
impl WriteString for Immediate {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Value(value) => format!("{}", *value as i64),
|
|
||||||
Self::Relocation { relocation, symbol } => {
|
|
||||||
format!("{}({})", relocation.write_string(), symbol.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for RelocationFunction {
|
impl WriteString for RelocationFunction {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Hi20 => "%hi",
|
|
||||||
Self::Lo12 => "%lo",
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for DataSize {
|
impl WriteString for DataSize {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Byte => "b",
|
|
||||||
Self::Half => "h",
|
|
||||||
Self::Word => "w",
|
|
||||||
Self::Double => "d",
|
|
||||||
Self::SinglePrecision => "s",
|
|
||||||
Self::DoublePrecision => "d",
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteString for Register {
|
impl WriteString for Register {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Self::Zero => "zero".to_string(),
|
|
||||||
Self::Ra => "ra".to_string(),
|
|
||||||
Self::Sp => "sp".to_string(),
|
|
||||||
Self::Gp => "gp".to_string(),
|
|
||||||
Self::Tp => "tp".to_string(),
|
|
||||||
Self::Temp(registr_type, id) => format!(
|
|
||||||
"{}t{}",
|
|
||||||
if *registr_type == RegisterType::FloatingPoint {
|
|
||||||
"f"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
},
|
|
||||||
id
|
|
||||||
),
|
|
||||||
Self::Saved(registr_type, id) => format!(
|
|
||||||
"{}s{}",
|
|
||||||
if *registr_type == RegisterType::FloatingPoint {
|
|
||||||
"f"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
},
|
|
||||||
id
|
|
||||||
),
|
|
||||||
Self::Arg(registr_type, id) => format!(
|
|
||||||
"{}a{}",
|
|
||||||
if *registr_type == RegisterType::FloatingPoint {
|
|
||||||
"f"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
},
|
|
||||||
id
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1366,21 +1366,17 @@ impl fmt::Display for Dtype {
|
|||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let fields = if let Some(fields) = fields {
|
let fields = if let Some(fields) = fields {
|
||||||
let fields = fields
|
let fields = fields.iter().format_with(", ", |field, f| {
|
||||||
.iter()
|
f(&format_args!(
|
||||||
.map(|f| {
|
"{}:{}",
|
||||||
format!(
|
if let Some(name) = field.name() {
|
||||||
"{}:{}",
|
name
|
||||||
if let Some(name) = f.name() {
|
} else {
|
||||||
name
|
"%anon"
|
||||||
} else {
|
},
|
||||||
"%anon"
|
field.deref()
|
||||||
},
|
))
|
||||||
f.deref()
|
});
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
format!(":<{}>", fields)
|
format!(":<{}>", fields)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
@@ -1393,16 +1389,9 @@ impl fmt::Display for Dtype {
|
|||||||
fields
|
fields
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Self::Function { ret, params } => write!(
|
Self::Function { ret, params } => {
|
||||||
f,
|
write!(f, "[ret:{} params:({})]", ret, params.iter().format(", "))
|
||||||
"[ret:{} params:({})]",
|
}
|
||||||
ret,
|
|
||||||
params
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ")
|
|
||||||
),
|
|
||||||
Self::Typedef { name, is_const } => {
|
Self::Typedef { name, is_const } => {
|
||||||
write!(f, "{}{}", if *is_const { "const " } else { "" }, name)
|
write!(f, "{}{}", if *is_const { "const " } else { "" }, name)
|
||||||
}
|
}
|
||||||
|
|||||||
139
src/ir/mod.rs
139
src/ir/mod.rs
@@ -12,11 +12,13 @@ use core::convert::TryFrom;
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use hexf_parse::{parse_hexf32, parse_hexf64};
|
use hexf_parse::{parse_hexf32, parse_hexf64};
|
||||||
|
use itertools::Itertools;
|
||||||
use lang_c::ast;
|
use lang_c::ast;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
use crate::write_base::*;
|
||||||
pub use dtype::{Dtype, DtypeError, HasDtype};
|
pub use dtype::{Dtype, DtypeError, HasDtype};
|
||||||
pub use interp::{interp, Value};
|
pub use interp::{interp, Value};
|
||||||
pub use parse::Parse;
|
pub use parse::Parse;
|
||||||
@@ -257,6 +259,96 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WriteOp for ast::BinaryOperator {
|
||||||
|
fn write_operation(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Multiply => "mul",
|
||||||
|
Self::Divide => "div",
|
||||||
|
Self::Modulo => "mod",
|
||||||
|
Self::Plus => "add",
|
||||||
|
Self::Minus => "sub",
|
||||||
|
Self::ShiftLeft => "shl",
|
||||||
|
Self::ShiftRight => "shr",
|
||||||
|
Self::Equals => "cmp eq",
|
||||||
|
Self::NotEquals => "cmp ne",
|
||||||
|
Self::Less => "cmp lt",
|
||||||
|
Self::LessOrEqual => "cmp le",
|
||||||
|
Self::Greater => "cmp gt",
|
||||||
|
Self::GreaterOrEqual => "cmp ge",
|
||||||
|
Self::BitwiseAnd => "and",
|
||||||
|
Self::BitwiseXor => "xor",
|
||||||
|
Self::BitwiseOr => "or",
|
||||||
|
_ => todo!(
|
||||||
|
"ast::BinaryOperator::WriteOp: write operation for {:?} is needed",
|
||||||
|
self
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WriteOp for ast::UnaryOperator {
|
||||||
|
fn write_operation(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Plus => "plus",
|
||||||
|
Self::Minus => "minus",
|
||||||
|
Self::Negate => "negate",
|
||||||
|
_ => todo!(
|
||||||
|
"ast::UnaryOperator::WriteOp: write operation for {:?} is needed",
|
||||||
|
self
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Instruction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Instruction::Nop => write!(f, "nop"),
|
||||||
|
Instruction::BinOp { op, lhs, rhs, .. } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} {} {}",
|
||||||
|
op.write_operation(),
|
||||||
|
lhs.write_string(),
|
||||||
|
rhs.write_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Instruction::UnaryOp { op, operand, .. } => {
|
||||||
|
write!(f, "{} {}", op.write_operation(), operand.write_string())
|
||||||
|
}
|
||||||
|
Instruction::Store { ptr, value } => {
|
||||||
|
write!(f, "store {} {}", value.write_string(), ptr.write_string())
|
||||||
|
}
|
||||||
|
Instruction::Load { ptr } => write!(f, "load {}", ptr.write_string()),
|
||||||
|
Instruction::Call { callee, args, .. } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"call {}({})",
|
||||||
|
callee.write_string(),
|
||||||
|
args.iter().format_with(", ", |operand, f| f(&format_args!(
|
||||||
|
"{}",
|
||||||
|
operand.write_string()
|
||||||
|
)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Instruction::TypeCast {
|
||||||
|
value,
|
||||||
|
target_dtype,
|
||||||
|
} => write!(f, "typecast {} to {}", value.write_string(), target_dtype),
|
||||||
|
Instruction::GetElementPtr { ptr, offset, .. } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"getelementptr {} offset {}",
|
||||||
|
ptr.write_string(),
|
||||||
|
offset.write_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum BlockExit {
|
pub enum BlockExit {
|
||||||
Jump {
|
Jump {
|
||||||
@@ -302,6 +394,43 @@ impl BlockExit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BlockExit {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
BlockExit::Jump { arg } => write!(f, "j {}", arg),
|
||||||
|
BlockExit::ConditionalJump {
|
||||||
|
condition,
|
||||||
|
arg_then,
|
||||||
|
arg_else,
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"br {}, {}, {}",
|
||||||
|
condition.write_string(),
|
||||||
|
arg_then,
|
||||||
|
arg_else
|
||||||
|
),
|
||||||
|
BlockExit::Switch {
|
||||||
|
value,
|
||||||
|
default,
|
||||||
|
cases,
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"switch {} default {} [\n{}\n ]",
|
||||||
|
value.write_string(),
|
||||||
|
default,
|
||||||
|
cases.iter().format_with("\n", |(v, b), f| f(&format_args!(
|
||||||
|
" {}:{} {}",
|
||||||
|
v,
|
||||||
|
v.dtype(),
|
||||||
|
b
|
||||||
|
)))
|
||||||
|
),
|
||||||
|
BlockExit::Return { value } => write!(f, "ret {}", value.write_string()),
|
||||||
|
BlockExit::Unreachable => write!(f, "<unreachable>\t\t\t\t; error state"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct JumpArg {
|
pub struct JumpArg {
|
||||||
pub bid: BlockId,
|
pub bid: BlockId,
|
||||||
@@ -322,9 +451,7 @@ impl fmt::Display for JumpArg {
|
|||||||
self.bid,
|
self.bid,
|
||||||
self.args
|
self.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| format!("{}:{}", a, a.dtype()))
|
.format_with(", ", |a, f| f(&format_args!("{}:{}", a, a.dtype())))
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ")
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -880,3 +1007,9 @@ impl<T> Named<T> {
|
|||||||
self.name.as_ref()
|
self.name.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Display> fmt::Display for Named<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ use std::io::{Result, Write};
|
|||||||
use crate::write_base::*;
|
use crate::write_base::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
use lang_c::ast;
|
|
||||||
|
|
||||||
impl WriteLine for TranslationUnit {
|
impl WriteLine for TranslationUnit {
|
||||||
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
|
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
|
||||||
// TODO: consider KECC IR parser in the future.
|
// TODO: consider KECC IR parser in the future.
|
||||||
@@ -18,21 +16,17 @@ impl WriteLine for TranslationUnit {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("`fields` must be `Some`");
|
.expect("`fields` must be `Some`");
|
||||||
|
|
||||||
let fields = fields
|
let fields = fields.iter().format_with(", ", |field, f| {
|
||||||
.iter()
|
f(&format_args!(
|
||||||
.map(|f| {
|
"{}:{}",
|
||||||
format!(
|
if let Some(name) = field.name() {
|
||||||
"{}:{}",
|
name
|
||||||
if let Some(name) = f.name() {
|
} else {
|
||||||
name
|
"%anon"
|
||||||
} else {
|
},
|
||||||
"%anon"
|
field.deref()
|
||||||
},
|
))
|
||||||
f.deref()
|
});
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
format!("{{ {} }}", fields)
|
format!("{{ {} }}", fields)
|
||||||
} else {
|
} else {
|
||||||
@@ -80,12 +74,7 @@ impl WriteLine for (&String, &Declaration) {
|
|||||||
signature,
|
signature,
|
||||||
definition,
|
definition,
|
||||||
} => {
|
} => {
|
||||||
let params = signature
|
let params = signature.params.iter().format(", ");
|
||||||
.params
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
if let Some(definition) = definition.as_ref() {
|
if let Some(definition) = definition.as_ref() {
|
||||||
// print function definition
|
// print function definition
|
||||||
@@ -99,7 +88,7 @@ impl WriteLine for (&String, &Declaration) {
|
|||||||
.allocations
|
.allocations
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, a)| format!(
|
.format_with("\n", |(i, a), f| f(&format_args!(
|
||||||
" %l{}:{}{}",
|
" %l{}:{}{}",
|
||||||
i,
|
i,
|
||||||
a.deref(),
|
a.deref(),
|
||||||
@@ -108,9 +97,7 @@ impl WriteLine for (&String, &Declaration) {
|
|||||||
} else {
|
} else {
|
||||||
"".into()
|
"".into()
|
||||||
}
|
}
|
||||||
))
|
)))
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n")
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for (id, block) in &definition.blocks {
|
for (id, block) in &definition.blocks {
|
||||||
@@ -173,39 +160,7 @@ impl WriteLine for (&BlockId, &Block) {
|
|||||||
|
|
||||||
impl WriteString for Instruction {
|
impl WriteString for Instruction {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
Instruction::Nop => "nop".into(),
|
|
||||||
Instruction::BinOp { op, lhs, rhs, .. } => format!(
|
|
||||||
"{} {} {}",
|
|
||||||
op.write_operation(),
|
|
||||||
lhs.write_string(),
|
|
||||||
rhs.write_string()
|
|
||||||
),
|
|
||||||
Instruction::UnaryOp { op, operand, .. } => {
|
|
||||||
format!("{} {}", op.write_operation(), operand.write_string(),)
|
|
||||||
}
|
|
||||||
Instruction::Store { ptr, value } => {
|
|
||||||
format!("store {} {}", value.write_string(), ptr.write_string())
|
|
||||||
}
|
|
||||||
Instruction::Load { ptr } => format!("load {}", ptr.write_string()),
|
|
||||||
Instruction::Call { callee, args, .. } => format!(
|
|
||||||
"call {}({})",
|
|
||||||
callee.write_string(),
|
|
||||||
args.iter()
|
|
||||||
.map(WriteString::write_string)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ")
|
|
||||||
),
|
|
||||||
Instruction::TypeCast {
|
|
||||||
value,
|
|
||||||
target_dtype,
|
|
||||||
} => format!("typecast {} to {}", value.write_string(), target_dtype),
|
|
||||||
Instruction::GetElementPtr { ptr, offset, .. } => format!(
|
|
||||||
"getelementptr {} offset {}",
|
|
||||||
ptr.write_string(),
|
|
||||||
offset.write_string()
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,79 +170,8 @@ impl WriteString for Operand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteOp for ast::BinaryOperator {
|
|
||||||
fn write_operation(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Self::Multiply => "mul",
|
|
||||||
Self::Divide => "div",
|
|
||||||
Self::Modulo => "mod",
|
|
||||||
Self::Plus => "add",
|
|
||||||
Self::Minus => "sub",
|
|
||||||
Self::ShiftLeft => "shl",
|
|
||||||
Self::ShiftRight => "shr",
|
|
||||||
Self::Equals => "cmp eq",
|
|
||||||
Self::NotEquals => "cmp ne",
|
|
||||||
Self::Less => "cmp lt",
|
|
||||||
Self::LessOrEqual => "cmp le",
|
|
||||||
Self::Greater => "cmp gt",
|
|
||||||
Self::GreaterOrEqual => "cmp ge",
|
|
||||||
Self::BitwiseAnd => "and",
|
|
||||||
Self::BitwiseXor => "xor",
|
|
||||||
Self::BitwiseOr => "or",
|
|
||||||
_ => todo!(
|
|
||||||
"ast::BinaryOperator::WriteOp: write operation for {:?} is needed",
|
|
||||||
self
|
|
||||||
),
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WriteOp for ast::UnaryOperator {
|
|
||||||
fn write_operation(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Self::Plus => "plus",
|
|
||||||
Self::Minus => "minus",
|
|
||||||
Self::Negate => "negate",
|
|
||||||
_ => todo!(
|
|
||||||
"ast::UnaryOperator::WriteOp: write operation for {:?} is needed",
|
|
||||||
self
|
|
||||||
),
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WriteString for BlockExit {
|
impl WriteString for BlockExit {
|
||||||
fn write_string(&self) -> String {
|
fn write_string(&self) -> String {
|
||||||
match self {
|
format!("{}", self)
|
||||||
BlockExit::Jump { arg } => format!("j {}", arg),
|
|
||||||
BlockExit::ConditionalJump {
|
|
||||||
condition,
|
|
||||||
arg_then,
|
|
||||||
arg_else,
|
|
||||||
} => format!(
|
|
||||||
"br {}, {}, {}",
|
|
||||||
condition.write_string(),
|
|
||||||
arg_then,
|
|
||||||
arg_else
|
|
||||||
),
|
|
||||||
BlockExit::Switch {
|
|
||||||
value,
|
|
||||||
default,
|
|
||||||
cases,
|
|
||||||
} => format!(
|
|
||||||
"switch {} default {} [\n{}\n ]",
|
|
||||||
value.write_string(),
|
|
||||||
default,
|
|
||||||
cases
|
|
||||||
.iter()
|
|
||||||
.map(|(v, b)| format!(" {}:{} {}", v, v.dtype(), b))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n")
|
|
||||||
),
|
|
||||||
BlockExit::Return { value } => format!("ret {}", value.write_string()),
|
|
||||||
BlockExit::Unreachable => "<unreachable>\t\t\t\t; error state".to_string(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user