Skip to content

Commit

Permalink
[X64] implementing fcast
Browse files Browse the repository at this point in the history
  • Loading branch information
Cr0a3 committed Oct 18, 2024
1 parent 52a4a70 commit 970117d
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 12 deletions.
18 changes: 9 additions & 9 deletions src/CodeGen/compilation/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ impl CompilationHelper {
let out = *self.vars.get(&node.inner3.name).unwrap();

let op = {

if node.inner1.ty.bitSize() > node.inner2.bitSize() {
MachineMnemonic::Zext
} else if node.inner1.ty.bitSize() < node.inner2.bitSize(){
MachineMnemonic::Downcast
} else {
return;
}

if node.inner1.ty.float() {
MachineMnemonic::FCast(node.inner1.ty)
} else if node.inner1.ty.bitSize() > node.inner2.bitSize() {
MachineMnemonic::Zext
} else if node.inner1.ty.bitSize() < node.inner2.bitSize(){
MachineMnemonic::Downcast
} else {
return;
}
};

let mut instr = MachineInstr::new(op);
Expand Down
2 changes: 2 additions & 0 deletions src/CodeGen/instr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ pub enum MachineMnemonic {
FShl,
FShr,
FCompare(CmpMode),
FCast(/*from type*/TypeMetadata),

BrCond(/*if yes*/String, /*if no*/String),
Compare(CmpMode),
Expand Down Expand Up @@ -328,6 +329,7 @@ impl MachineMnemonic {
MachineMnemonic::FShl => "fshl",
MachineMnemonic::FShr => "fshr",
MachineMnemonic::FCompare(_) => "fcompare",
MachineMnemonic::FCast(_) => "fcast",
}.to_string()
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/IR/nodes/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ use super::*;

impl Ir for Cast<Var, TypeMetadata, Var> {
fn dump(&self) -> String {
format!("{} = cast {} to {}", self.inner3.name, self.inner1.name, self.inner2)
format!("{} = cast {} {} to {}", self.inner3.name, self.inner1.ty, self.inner1.name, self.inner2)
}

fn dumpColored(&self, profile: ColorProfile) -> String {
format!("{} = {} {} {} {}",
format!("{} = {} {} {} {} {}",
profile.markup(&self.inner3.name, ColorClass::Var),
profile.markup(&"cast", ColorClass::Instr),
profile.markup(&self.inner1.ty.to_string(), ColorClass::Ty),
profile.markup(&self.inner1.name, ColorClass::Var),
profile.markup(&"to", ColorClass::Instr),
profile.markup(&self.inner2.to_string(), ColorClass::Ty),
Expand Down
5 changes: 4 additions & 1 deletion src/IR/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,12 +669,15 @@ impl IrParser {
fn parse_cast(&mut self, var: String) -> Result<Box<dyn Ir>, IrError> {
self.input.pop_front();

let ty = self.parse_type()?;
self.input.pop_front();

self.expect(TokenType::Var(String::new()))?;

let in_var = if let TokenType::Var(name) = &self.current_token()?.typ {
Var {
name: name.to_owned(),
ty: TypeMetadata::i32,
ty: ty,
}
} else { unreachable!() };

Expand Down
73 changes: 73 additions & 0 deletions src/Target/x64/asm/instr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,66 @@ impl X64MCInstr {
} else { todo!("{}", self) }
} else { todo!("{}", self) }
},
Mnemonic::Cvtss2si => {
if let Some(Operand::Reg(op1)) = &self.op1 {
if let Some(Operand::Reg(op2)) = &self.op2 {
if op1.is_gr32() {
Instruction::with2::<Register, Register>(Code::Cvtss2si_r32_xmmm32, (*op1).into(), (*op2).into())?
} else if op1.is_gr64() {
Instruction::with2::<Register, Register>(Code::Cvtss2si_r64_xmmm32, (*op1).into(), (*op2).into())?
} else { todo!("{}", self) }
} else if let Some(Operand::Mem(op2)) = &self.op2 {
if op1.is_gr32() {
Instruction::with2::<Register, MemoryOperand>(Code::Cvtss2si_r32_xmmm32, (*op1).into(), op2.into())?
} else if op1.is_gr64() {
Instruction::with2::<Register, MemoryOperand>(Code::Cvtss2si_r64_xmmm32, (*op1).into(), op2.into())?
} else { todo!("{}", self) }
} else { todo!("{}", self) }
} else { todo!("{}", self) }
},
Mnemonic::Cvtsd2si => {
if let Some(Operand::Reg(op1)) = &self.op1 {
if let Some(Operand::Reg(op2)) = &self.op2 {
if op1.is_gr32() {
Instruction::with2::<Register, Register>(Code::Cvtsd2si_r32_xmmm64, (*op1).into(), (*op2).into())?
} else if op1.is_gr64() {
Instruction::with2::<Register, Register>(Code::Cvtsd2si_r64_xmmm64, (*op1).into(), (*op2).into())?
} else { todo!("{}", self) }
} else if let Some(Operand::Mem(op2)) = &self.op2 {
if op1.is_gr32() {
Instruction::with2::<Register, MemoryOperand>(Code::Cvtsd2si_r32_xmmm64, (*op1).into(), op2.into())?
} else if op1.is_gr64() {
Instruction::with2::<Register, MemoryOperand>(Code::Cvtsd2si_r64_xmmm64, (*op1).into(), op2.into())?
} else { todo!("{}", self) }
} else { todo!("{}", self) }
} else { todo!("{}", self) }
},
Mnemonic::Cvtss2sd => {
if let Some(Operand::Reg(op1)) = &self.op1 {
if let Some(Operand::Reg(op2)) = &self.op2 {
if op1.is_xmm() {
Instruction::with2::<Register, Register>(Code::Cvtss2sd_xmm_xmmm32, (*op1).into(), (*op2).into())?
} else { todo!("{}", self) }
} else if let Some(Operand::Mem(op2)) = &self.op2 {
if op1.is_xmm() {
Instruction::with2::<Register, MemoryOperand>(Code::Cvtss2sd_xmm_xmmm32, (*op1).into(), op2.into())?
} else { todo!("{}", self) }
} else { todo!("{}", self) }
} else { todo!("{}", self) }
},
Mnemonic::Cvtsd2ss => {
if let Some(Operand::Reg(op1)) = &self.op1 {
if let Some(Operand::Reg(op2)) = &self.op2 {
if op1.is_xmm() {
Instruction::with2::<Register, Register>(Code::Cvtsd2ss_xmm_xmmm64, (*op1).into(), (*op2).into())?
} else { todo!("{}", self) }
} else if let Some(Operand::Mem(op2)) = &self.op2 {
if op1.is_xmm() {
Instruction::with2::<Register, MemoryOperand>(Code::Cvtsd2ss_xmm_xmmm64, (*op1).into(), op2.into())?
} else { todo!("{}", self) }
} else { todo!("{}", self) }
} else { todo!("{}", self) }
},

};

Expand Down Expand Up @@ -1294,6 +1354,11 @@ pub enum Mnemonic {

Ucomiss,
Ucomisd,

Cvtss2si,
Cvtsd2si,
Cvtss2sd,
Cvtsd2ss,
}

impl FromStr for Mnemonic {
Expand Down Expand Up @@ -1351,6 +1416,10 @@ impl FromStr for Mnemonic {
"subsd" => Ok(Mnemonic::Subsd),
"ucomiss" => Ok(Mnemonic::Ucomiss),
"ucomisd" => Ok(Mnemonic::Ucomisd),
"cvtss2si" => Ok(Mnemonic::Cvtss2si),
"cvtsd2si" => Ok(Mnemonic::Cvtsd2si),
"cvtss2sd" => Ok(Mnemonic::Cvtss2sd),
"cvtsd2ss" => Ok(Mnemonic::Cvtsd2ss),
_ => Err(()),
}
}
Expand Down Expand Up @@ -1413,6 +1482,10 @@ impl Display for Mnemonic {
Mnemonic::Subsd => "subsd",
Mnemonic::Ucomiss => "ucomiss",
Mnemonic::Ucomisd => "ucomisd",
Mnemonic::Cvtss2si => "cvtss2si",
Mnemonic::Cvtsd2si => "cvtsd2si",
Mnemonic::Cvtss2sd => "cvtss2sd",
Mnemonic::Cvtsd2ss => "cvtsd2ss",
})
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/Target/x64/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod cmov;
mod fmath;
mod fcmp;
mod fmove;
mod fcast;

use super::{instr::{Mnemonic, Operand, X64MCInstr}, x64Reg};

Expand Down Expand Up @@ -85,6 +86,7 @@ pub(crate) fn x64_lower_instr(conv: CallConv, sink: &mut Vec<X64MCInstr>, instr:
MachineMnemonic::FMul => fmath::x64_lower_fmul(sink, &instr),
MachineMnemonic::FSub => fmath::x64_lower_fsub(sink, &instr),
MachineMnemonic::FCompare(mode) => fcmp::x64_lower_fcmp(sink, &instr, mode),
MachineMnemonic::FCast(input_type) => fcast::X64_lower_fcast(sink, &instr, *input_type),
_ => todo!("TDOD: {}", instr.mnemonic),
}
}
Expand Down
45 changes: 45 additions & 0 deletions src/Target/x64/lower/fcast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::{CodeGen::MachineInstr, Target::{x64::instr::*, x64Reg}, IR::TypeMetadata};

pub(crate) fn X64_lower_fcast(sink: &mut Vec<X64MCInstr>, instr: &MachineInstr, input_type: TypeMetadata) {
let out = instr.out.expect("fcast expects output");
let out = out.into();

let input = instr.operands.get(0).expect("fcast expects input operand");
let input = (*input).into();

let mut output_reg = x64Reg::Rax.sub_ty(instr.meta);

if let Operand::Reg(reg) = &out {
output_reg = *reg;
}

if input_type == TypeMetadata::f32 {
match instr.meta {
TypeMetadata::i32 => sink.push(X64MCInstr::with2(Mnemonic::Cvtss2si, Operand::Reg(output_reg), input)),
TypeMetadata::i64 => sink.push(X64MCInstr::with2(Mnemonic::Cvtss2si, Operand::Reg(output_reg), input)),

TypeMetadata::f32 => sink.push(X64MCInstr::with2(Mnemonic::Movss, Operand::Reg(output_reg), input)),
TypeMetadata::f64 => sink.push(X64MCInstr::with2(Mnemonic::Cvtss2sd, Operand::Reg(output_reg), input)),
_ => panic!("fcast can only cast from f32/f64 to i32/i64/f32/f64")
}
} else if input_type == TypeMetadata::f64 {
match instr.meta {
TypeMetadata::i32 => sink.push(X64MCInstr::with2(Mnemonic::Cvtsd2si, Operand::Reg(output_reg), input)),
TypeMetadata::i64 => sink.push(X64MCInstr::with2(Mnemonic::Cvtsd2si, Operand::Reg(output_reg), input)),

TypeMetadata::f32 => sink.push(X64MCInstr::with2(Mnemonic::Cvtsd2ss, Operand::Reg(output_reg), input)),
TypeMetadata::f64 => sink.push(X64MCInstr::with2(Mnemonic::Cvtsd2ss, Operand::Reg(output_reg), input)),
_ => panic!("fcast can only cast from f32/f64 to i32/i64/f32/f64")
}
} else { panic!("fcast expect that the input type is a float") }

if let Operand::Mem(out) = &out {
sink.push(if instr.meta == TypeMetadata::f32 {
X64MCInstr::with2(Mnemonic::Movd, Operand::Mem(out.to_owned()), Operand::Reg(output_reg))
} else if instr.meta == TypeMetadata::f64 {
X64MCInstr::with2(Mnemonic::Movq, Operand::Mem(out.to_owned()), Operand::Reg(output_reg))
} else {
X64MCInstr::with2(Mnemonic::Mov, Operand::Mem(out.to_owned()), Operand::Reg(output_reg))
});
}
}

0 comments on commit 970117d

Please sign in to comment.