From ac82de7e3824a449f71303ab8ae95656443ce219 Mon Sep 17 00:00:00 2001 From: Cr0a3 Date: Sat, 9 Nov 2024 20:29:53 +0100 Subject: [PATCH] [IR] switching to IROperand system for select --- src/CodeGen/compilation/mod.rs | 2 +- src/CodeGen/compilation/ret.rs | 3 +- src/CodeGen/compilation/select.rs | 119 +------- src/CodeGen/ir_area.rs | 19 +- src/IR/nodes/mod.rs | 20 ++ src/IR/nodes/ret.rs | 21 +- src/IR/nodes/select.rs | 358 ++++++----------------- src/IR/parser/parser.rs | 109 ++----- src/Optimizations/Passes/InstrCombine.rs | 3 +- src/Target/target_descr.rs | 5 +- src/Target/x64/lower/cmov.rs | 106 ++++--- src/Target/x64/lower/fcmp.rs | 4 +- tests/IR/select/fp0.yl | 2 +- tests/IR/select/select1.yl | 4 +- tests/IR/select/select2.yl | 2 +- 15 files changed, 223 insertions(+), 554 deletions(-) diff --git a/src/CodeGen/compilation/mod.rs b/src/CodeGen/compilation/mod.rs index 15422a95..5a46c48d 100644 --- a/src/CodeGen/compilation/mod.rs +++ b/src/CodeGen/compilation/mod.rs @@ -178,7 +178,7 @@ impl crate::IR::ir::IROperand { fn into_mi(&self, compiler: &mut CompilationHelper) -> MachineOperand { match self { crate::prelude::IROperand::Type(ty) => MachineOperand::Imm(ty.val()), - crate::prelude::IROperand::Var(var) => (*compiler.vars.get(&var.name).unwrap()).into(), + crate::prelude::IROperand::Var(var) => (*compiler.vars.get(&var.name).expect(&format!("unknown variable: {}", var.name))).into(), } } } \ No newline at end of file diff --git a/src/CodeGen/compilation/ret.rs b/src/CodeGen/compilation/ret.rs index 7e30d83d..2be98075 100644 --- a/src/CodeGen/compilation/ret.rs +++ b/src/CodeGen/compilation/ret.rs @@ -1,4 +1,5 @@ -use crate::{prelude::{IROperand, Return}, CodeGen::{MachineInstr, MachineMnemonic, MachineOperand}, IR::{Block, Type, Var}}; +use crate::prelude::{IROperand, Return, Block}; +use crate::CodeGen::{MachineInstr, MachineMnemonic}; use super::CompilationHelper; diff --git a/src/CodeGen/compilation/select.rs b/src/CodeGen/compilation/select.rs index 4cbcbc15..c434698c 100644 --- a/src/CodeGen/compilation/select.rs +++ b/src/CodeGen/compilation/select.rs @@ -4,49 +4,14 @@ use crate::prelude::*; impl CompilationHelper { #[allow(missing_docs)] - pub fn compile_select_tt(&mut self, node: &Select, mc_sink: &mut Vec, _: &Block, _: &mut crate::prelude::Module) { - let out = self.vars.get(&node.out.name).expect("expected valid variable"); - let cond = self.vars.get(&node.cond.name).expect("expected valid variable"); - - let out = (*out).into(); - let cond = (*cond).into(); - - let yes = MachineOperand::Imm(node.yes.val()); - let no = MachineOperand::Imm(node.no.val()); - - let mut yes_instr = MachineInstr::new(MachineMnemonic::MovIfZero); - - yes_instr.set_out(out); - yes_instr.add_operand(cond); - yes_instr.add_operand(no); - - yes_instr.meta = node.yes.into(); - - mc_sink.push(yes_instr); - - let mut no_instr = MachineInstr::new(MachineMnemonic::MovIfNotZero); - - no_instr.set_out(out); - no_instr.add_operand(cond); - no_instr.add_operand(yes); + pub fn compile_select(&mut self, node: &Select, mc_sink: &mut Vec, _: &Block, _: &mut crate::prelude::Module) { + let out = (*self.vars.get(&node.out.name).expect("expected valid variable")).into(); + let cond = (*self.vars.get(&node.cond.name).expect("expected valid variable")).into(); - no_instr.meta = node.no.into(); + let yes = node.yes.into_mi(self); + let no = node.no.into_mi(self); - mc_sink.push(no_instr); - } - - #[allow(missing_docs)] - pub fn compile_select_tv(&mut self, node: &Select, mc_sink: &mut Vec, _: &Block, _: &mut crate::prelude::Module) { - let out = self.vars.get(&node.out.name).expect("expected valid variable"); - let cond = self.vars.get(&node.cond.name).expect("expected valid variable"); - - let no = self.vars.get(&node.no.name).expect("expected valid variable"); - - let out = (*out).into(); - let cond = (*cond).into(); - let no = (*no).into(); - - let yes = MachineOperand::Imm(node.yes.val()); + let ty = node.yes.get_ty(); let mut yes_instr = MachineInstr::new(MachineMnemonic::MovIfZero); @@ -54,7 +19,7 @@ impl CompilationHelper { yes_instr.add_operand(cond); yes_instr.add_operand(yes); - yes_instr.meta = node.yes.into(); + yes_instr.meta = ty; mc_sink.push(yes_instr); @@ -64,75 +29,7 @@ impl CompilationHelper { no_instr.add_operand(cond); no_instr.add_operand(no); - no_instr.meta = node.no.ty; - - mc_sink.push(no_instr); - } - - #[allow(missing_docs)] - pub fn compile_select_vt(&mut self, node: &Select, mc_sink: &mut Vec, _: &Block, _: &mut crate::prelude::Module) { - let out = self.vars.get(&node.out.name).expect("expected valid variable"); - let cond = self.vars.get(&node.cond.name).expect("expected valid variable"); - - let yes = self.vars.get(&node.yes.name).expect("expected valid variable"); - - let out = (*out).into(); - let cond = (*cond).into(); - let yes = (*yes).into(); - - let no = MachineOperand::Imm(node.no.val()); - - let mut yes_instr = MachineInstr::new(MachineMnemonic::MovIfZero); - - yes_instr.set_out(out); - yes_instr.add_operand(cond); - yes_instr.add_operand(no); - - yes_instr.meta = node.yes.ty; - - mc_sink.push(yes_instr); - - let mut no_instr = MachineInstr::new(MachineMnemonic::MovIfNotZero); - - no_instr.set_out(out); - no_instr.add_operand(cond); - no_instr.add_operand(yes); - - no_instr.meta = node.no.into(); - - mc_sink.push(no_instr); - } - - #[allow(missing_docs)] - pub fn compile_select_vv(&mut self, node: &Select, mc_sink: &mut Vec, _: &Block, _: &mut crate::prelude::Module) { - let out = self.vars.get(&node.out.name).expect("expected valid variable"); - let cond = self.vars.get(&node.cond.name).expect("expected valid variable"); - - let yes = self.vars.get(&node.yes.name).expect("expected valid variable"); - let no = self.vars.get(&node.no.name).expect("expected valid variable"); - - let out = (*out).into(); - let cond = (*cond).into(); - let yes = (*yes).into(); - let no = (*no).into(); - - let mut yes_instr = MachineInstr::new(MachineMnemonic::MovIfZero); - - yes_instr.set_out(out); - yes_instr.add_operand(cond); - yes_instr.add_operand(no); - - yes_instr.meta = node.yes.ty; - - mc_sink.push(yes_instr); - - let mut no_instr = MachineInstr::new(MachineMnemonic::MovIfNotZero); - - no_instr.set_out(out); - no_instr.add_operand(cond); - no_instr.add_operand(yes); - - no_instr.meta = node.no.ty; + no_instr.meta = ty; mc_sink.push(no_instr); } diff --git a/src/CodeGen/ir_area.rs b/src/CodeGen/ir_area.rs index 65a2cd5f..17e7219f 100644 --- a/src/CodeGen/ir_area.rs +++ b/src/CodeGen/ir_area.rs @@ -311,24 +311,9 @@ impl IrCodeGenHelper { ir::Neg ); ir_codegen_wrap!( - compile_select_tt, + compile_select, "Loweres the select ty ty node", - ir::Select - ); - ir_codegen_wrap!( - compile_select_vt, - "Loweres the select var ty node", - ir::Select - ); - ir_codegen_wrap!( - compile_select_tv, - "Loweres the select ty var node", - ir::Select - ); - ir_codegen_wrap!( - compile_select_vv, - "Loweres the select var var node", - ir::Select + ir::Select ); ir_codegen_wrap!( compile_getelemptr, diff --git a/src/IR/nodes/mod.rs b/src/IR/nodes/mod.rs index 3af7d09e..946a8706 100644 --- a/src/IR/nodes/mod.rs +++ b/src/IR/nodes/mod.rs @@ -363,6 +363,20 @@ impl IROperand { IROperand::Var(var) => var.ty, } } + + #[inline] + /// Returns the unwraped inner type value (else it panics) + pub fn get_typeconst(&self) -> Type { + let IROperand::Type(ret) = self else { panic!(); }; + return *ret; + } + + #[inline] + /// Returns the unwraped inner var value (else it panics) + pub fn get_var(&self) -> Var { + let IROperand::Var(ret) = self else { panic!(); }; + return ret.to_owned(); + } } impl std::fmt::Display for IROperand { @@ -388,4 +402,10 @@ impl std::fmt::Display for IROperand { IROperand::Var(var) => var.name.to_string(), }) } +} + +impl AsAny for IROperand { + fn as_any(&self) -> &dyn std::any::Any { + self + } } \ No newline at end of file diff --git a/src/IR/nodes/ret.rs b/src/IR/nodes/ret.rs index 38d70cc5..6b1494e1 100644 --- a/src/IR/nodes/ret.rs +++ b/src/IR/nodes/ret.rs @@ -1,5 +1,3 @@ -use std::any::TypeId; - use super::*; impl Ir for Return { @@ -45,7 +43,8 @@ impl Ir for Return { } fn inputs(&self) -> Vec { - vec![] + if let IROperand::Var(ret) = &self.inner1 { vec![ret.to_owned()] } + else { vec![] } } fn inputs_mut(&mut self) -> Vec<&mut Var> { @@ -78,22 +77,30 @@ impl Return where { /// Returns the node a constant type? pub fn isRetConst(&self) -> bool { - self.inner1.type_id() == TypeId::of::() + if let Some(op) = self.inner1.as_any().downcast_ref::() { + op.is_type() + } else { panic!() } } /// Returns the node a variable? pub fn isRetVar(&self) -> bool { - self.inner1.type_id() == TypeId::of::() + if let Some(op) = self.inner1.as_any().downcast_ref::() { + op.is_var() + } else { panic!() } } /// Returns the constant the node returns (else panics) pub fn getRetConst(&self) -> Type { - self.inner1.as_any().downcast_ref::().unwrap().to_owned() + if let Some(op) = self.inner1.as_any().downcast_ref::() { + op.get_typeconst() + } else { panic!() } } /// Returns the variable the node returns (else panics) pub fn getRetVar(&self) -> Var { - self.inner1.as_any().downcast_ref::().unwrap().to_owned() + if let Some(op) = self.inner1.as_any().downcast_ref::() { + op.get_var() + } else { panic!() } } } diff --git a/src/IR/nodes/select.rs b/src/IR/nodes/select.rs index 1f9c7a85..4d12bc70 100644 --- a/src/IR/nodes/select.rs +++ b/src/IR/nodes/select.rs @@ -1,33 +1,32 @@ -use std::any::{Any, TypeId}; - -use super::{Assign, EvalOptVisitor, Ir, IsNode, Select}; +use super::{Assign, EvalOptVisitor, IROperand, Ir, IsNode, Select}; use crate::{prelude::{Type, TypeMetadata, Var}, Support::{AsAny, ColorClass}, IR::Function}; -impl Ir for Select { +impl Ir for Select { fn dump(&self) -> String { - let yes_meta: TypeMetadata = self.yes.into(); - let no_meta: TypeMetadata = self.no.into(); + let yes_meta: TypeMetadata = self.yes.get_ty(); + let no_meta: TypeMetadata = self.no.get_ty(); + format!("{} = select {} {}, {} {}, {} {}", self.out.name, self.cond.ty, self.cond.name, - yes_meta, self.yes.val(), - no_meta, self.no.val() + yes_meta, self.yes, + no_meta, self.no ) } fn dumpColored(&self, profile: crate::Support::ColorProfile) -> String { - let yes_meta: TypeMetadata = self.yes.into(); - let no_meta: TypeMetadata = self.no.into(); + let yes_meta: TypeMetadata = self.yes.get_ty(); + let no_meta: TypeMetadata = self.no.get_ty(); format!("{} = {} {} {}, {} {}, {} {}", profile.markup(&self.out.name, ColorClass::Var), profile.markup("select", ColorClass::Instr), profile.markup(&self.cond.ty.to_string(), ColorClass::Ty), profile.markup(&self.cond.name, ColorClass::Var), profile.markup(&yes_meta.to_string(), ColorClass::Ty), - profile.markup(&self.yes.val().to_string(), ColorClass::Value), + profile.markup(&self.yes.to_string(), ColorClass::Value), profile.markup(&no_meta.to_string(), ColorClass::Ty), - profile.markup(&self.no.val().to_string(), ColorClass::Value), + profile.markup(&self.no.to_string(), ColorClass::Value), ) } @@ -44,100 +43,24 @@ impl Ir for Select { } fn compile(&self, registry: &mut crate::Target::TargetBackendDescr, module: &mut crate::prelude::Module) { - registry.compile_select_tt(self, module) + registry.compile_select(self, module) } fn compile_dir(&self, compiler: &mut crate::CodeGen::IrCodeGenHelper, block: &crate::prelude::Block, module: &mut crate::prelude::Module) { - compiler.compile_select_tt(self, block, module) + compiler.compile_select(self, block, module) } fn inputs(&self) -> Vec { - vec![self.cond.to_owned()] - } - - fn inputs_mut(&mut self) -> Vec<&mut Var> { - vec![&mut self.cond] - } + let mut inputs = vec![self.cond.to_owned()]; - fn output(&self) -> Option { - Some(self.out.clone()) - } -} + if let IROperand::Var(var) = &self.yes { inputs.push(var.to_owned()); } + if let IROperand::Var(var) = &self.no { inputs.push(var.to_owned()); } -impl EvalOptVisitor for Select { - fn maybe_inline(&self, const_values: &std::collections::HashMap) -> Option> { - if let Some(cond) = const_values.get(&self.cond.name) { - if cond.val() == 0.0 { - return Some(Assign::new(self.out.clone(), self.yes)); - } else { - return Some(Assign::new(self.out.clone(), self.no)); - } - } - - None - } - - fn eval(&self) -> Option> { - if self.no == self.yes { - return Some(Assign::new(self.out.clone(), self.yes)); - } - - None - } -} - -impl Ir for Select { - fn dump(&self) -> String { - let no_meta: TypeMetadata = self.no.into(); - format!("{} = select {} {}, {} {}, {} {}", - self.out.name, - self.cond.ty, - self.cond.name, - self.yes.ty, self.yes.name, - no_meta, self.no.val() - ) - } - - fn dumpColored(&self, profile: crate::Support::ColorProfile) -> String { - let no_meta: TypeMetadata = self.no.into(); - format!("{} = {} {} {}, {} {}, {} {}", - profile.markup(&self.out.name, ColorClass::Var), - profile.markup("select", ColorClass::Instr), - profile.markup(&self.cond.ty.to_string(), ColorClass::Ty), - profile.markup(&self.cond.name, ColorClass::Var), - profile.markup(&self.yes.ty.to_string(), ColorClass::Ty), - profile.markup(&self.yes.name, ColorClass::Var), - profile.markup(&no_meta.to_string(), ColorClass::Ty), - profile.markup(&self.no.val().to_string(), ColorClass::Value), - ) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn verify(&self, _: crate::prelude::FunctionType) -> Result<(), crate::prelude::VerifyError> { - Ok(()) - } - - fn clone_box(&self) -> Box { - Box::from( self.clone() ) - } - - fn compile(&self, registry: &mut crate::Target::TargetBackendDescr, module: &mut crate::prelude::Module) { - registry.compile_select_vt(self, module) - } - - fn compile_dir(&self, compiler: &mut crate::CodeGen::IrCodeGenHelper, block: &crate::prelude::Block, module: &mut crate::prelude::Module) { - compiler.compile_select_vt(self, block, module) - } - - fn inputs(&self) -> Vec { - vec![self.cond.to_owned(), self.yes.clone()] + inputs } fn inputs_mut(&mut self) -> Vec<&mut Var> { - vec![&mut self.cond, &mut self.yes] + vec![&mut self.cond] } fn output(&self) -> Option { @@ -145,173 +68,58 @@ impl Ir for Select { } } -impl EvalOptVisitor for Select { +impl EvalOptVisitor for Select { fn maybe_inline(&self, const_values: &std::collections::HashMap) -> Option> { - if let Some(yes) = const_values.get(&self.yes.name) { - return Some(Select { - out: self.out.clone(), - cond: self.cond.clone(), - yes: *yes, - no: self.no, - }.clone_box()); + match (&self.yes, &self.no) { + (IROperand::Type(yes), IROperand::Type(no)) => { + if let Some(cond) = const_values.get(&self.cond.name) { + if cond.val() == 0.0 { + Some(Assign::new(self.out.clone(), *yes)) + } else { + Some(Assign::new(self.out.clone(), *no)) + } + } else { None} + }, + + (IROperand::Var(yes), IROperand::Type(no)) => { + if let Some(yes) = const_values.get(&yes.name) { + return Some(Box::new(Select { + out: self.out.clone(), + cond: self.cond.clone(), + yes: IROperand::Type(*yes), + no: IROperand::Type(*no), + })); + } else { None } + }, + + (IROperand::Type(yes), IROperand::Var(no)) => { + if let Some(no) = const_values.get(&no.name) { + return Some(Box::new(Select { + out: self.out.clone(), + cond: self.cond.clone(), + yes: IROperand::Type(*yes), + no: IROperand::Type(*no), + })); + } else { None } + }, + + _ => None, } - - None } fn eval(&self) -> Option> { - None - } -} - -impl Ir for Select { - fn dump(&self) -> String { - let yes_meta: TypeMetadata = self.yes.into(); - format!("{} = select {} {}, {} {}, {} {}", - self.out.name, - self.cond.ty, - self.cond.name, - yes_meta, self.yes.val(), - self.no.ty, self.no.name - ) - } - - fn dumpColored(&self, profile: crate::Support::ColorProfile) -> String { - let yes_meta: TypeMetadata = self.yes.into(); - format!("{} = {} {} {}, {} {}, {} {}", - profile.markup(&self.out.name, ColorClass::Var), - profile.markup("select", ColorClass::Instr), - profile.markup(&self.cond.ty.to_string(), ColorClass::Ty), - profile.markup(&self.cond.name, ColorClass::Var), - profile.markup(&yes_meta.to_string(), ColorClass::Ty), - profile.markup(&self.yes.val().to_string(), ColorClass::Value), - profile.markup(&self.no.ty.to_string(), ColorClass::Ty), - profile.markup(&self.no.name, ColorClass::Var), - ) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn verify(&self, _: crate::prelude::FunctionType) -> Result<(), crate::prelude::VerifyError> { - Ok(()) - } - - fn clone_box(&self) -> Box { - Box::from( self.clone() ) - } - - fn compile(&self, registry: &mut crate::Target::TargetBackendDescr, module: &mut crate::prelude::Module) { - registry.compile_select_tv(self, module) - } - - fn compile_dir(&self, compiler: &mut crate::CodeGen::IrCodeGenHelper, block: &crate::prelude::Block, module: &mut crate::prelude::Module) { - compiler.compile_select_tv(self, block, module) - } - - fn inputs(&self) -> Vec { - vec![self.cond.to_owned(), self.no.to_owned()] - } - - fn inputs_mut(&mut self) -> Vec<&mut Var> { - vec![&mut self.cond, &mut self.no] - } - - fn output(&self) -> Option { - Some(self.out.clone()) - } -} - -impl EvalOptVisitor for Select { - fn maybe_inline(&self, const_values: &std::collections::HashMap) -> Option> { - if let Some(no) = const_values.get(&self.no.name) { - return Some(Select { - out: self.out.clone(), - cond: self.cond.clone(), - yes: self.yes, - no: *no, - }.clone_box()); + if self.no == self.yes { + let yes: Box = match &self.yes { + IROperand::Type(yes) => Assign::new(self.out.clone(), *yes), + IROperand::Var(yes) => Assign::new(self.out.clone(), yes.to_owned()), + }; + return Some(yes); } None } - - fn eval(&self) -> Option> { - None - } -} - -impl Ir for Select { - fn dump(&self) -> String { - format!("{} = select {} {}, {} {}, {} {}", - self.out.name, - self.cond.ty, - self.cond.name, - self.yes.ty, self.yes.name, - self.no.ty, self.no.name - ) - } - - fn dumpColored(&self, profile: crate::Support::ColorProfile) -> String { - format!("{} = {} {} {}, {} {}, {} {}", - profile.markup(&self.out.name, ColorClass::Var), - profile.markup("select", ColorClass::Instr), - profile.markup(&self.cond.ty.to_string(), ColorClass::Ty), - profile.markup(&self.cond.name, ColorClass::Var), - profile.markup(&self.yes.ty.to_string(), ColorClass::Ty), - profile.markup(&self.yes.name, ColorClass::Var), - profile.markup(&self.no.ty.to_string(), ColorClass::Ty), - profile.markup(&self.no.name, ColorClass::Var), - ) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn verify(&self, _: crate::prelude::FunctionType) -> Result<(), crate::prelude::VerifyError> { - Ok(()) - } - - fn clone_box(&self) -> Box { - Box::from( self.clone() ) - } - - fn compile(&self, registry: &mut crate::Target::TargetBackendDescr, module: &mut crate::prelude::Module) { - registry.compile_select_vv(self, module) - } - - fn compile_dir(&self, compiler: &mut crate::CodeGen::IrCodeGenHelper, block: &crate::prelude::Block, module: &mut crate::prelude::Module) { - compiler.compile_select_vv(self, block, module) - } - - fn inputs(&self) -> Vec { - vec![self.cond.to_owned(), self.yes.to_owned(), self.no.to_owned()] - } - - fn inputs_mut(&mut self) -> Vec<&mut Var> { - vec![&mut self.cond, &mut self.yes, &mut self.no] - } - - fn output(&self) -> Option { - Some(self.out.clone()) - } } -impl EvalOptVisitor for Select { - fn maybe_inline(&self, _: &std::collections::HashMap) -> Option> { - None - } - - fn eval(&self) -> Option> { - if self.yes == self.no { - return Some(Assign::new(self.out.clone(), self.yes.clone())); - } - - None - } -} impl IsNode for Select where T: std::fmt::Debug + Clone + PartialEq + Eq + AsAny, @@ -342,22 +150,22 @@ impl Select /// Returns if the true value is a variable pub fn isTrueVar(&self) -> bool { - self.yes.type_id() == TypeId::of::() + matches!(self.yes.as_any().downcast_ref::(), Some(IROperand::Var(_))) } /// Returns if the false value is a variable pub fn isFalseVar(&self) -> bool { - self.no.type_id() == TypeId::of::() + matches!(self.no.as_any().downcast_ref::(), Some(IROperand::Var(_))) } /// Returns if the true value is a constant pub fn isTrueConst(&self) -> bool { - self.yes.type_id() == TypeId::of::() + matches!(self.yes.as_any().downcast_ref::(), Some(IROperand::Type(_))) } /// Returns if the false value is a constant pub fn isFalseConst(&self) -> bool { - self.no.type_id() == TypeId::of::() + matches!(self.no.as_any().downcast_ref::(), Some(IROperand::Type(_))) } /// Returns the true value as a variable @@ -366,16 +174,22 @@ impl Select /// /// panics if the true value is not a variable so first check pub fn getTrueVar(&self) -> Var { - self.yes.as_any().downcast_ref::().unwrap().clone() + let Some(IROperand::Var(ret)) = self.yes.as_any().downcast_ref::() else { + panic!(); + }; + ret.to_owned() } - /// Returns if the false value is a variable + /// Returns the false value as a variable /// /// ### Panics /// /// panics if the false value is not a variable so first check - pub fn getFalseVar(&self) -> bool { - self.no.type_id() == TypeId::of::() + pub fn getFalseVar(&self) -> Var { + let Some(IROperand::Var(ret)) = self.no.as_any().downcast_ref::() else { + panic!(); + }; + ret.to_owned() } /// Returns the true value as a constant @@ -384,7 +198,10 @@ impl Select /// /// panics if the true value is not a constant so first check pub fn getTrueConst(&self) -> Type { - self.yes.as_any().downcast_ref::().unwrap().clone() + let Some(IROperand::Type(ret)) = self.yes.as_any().downcast_ref::() else { + panic!(); + }; + *ret } /// Returns the false value as a constant @@ -393,7 +210,10 @@ impl Select /// /// panics if the false value is not a constant so first check pub fn getFalseConst(&self) -> Type { - self.no.as_any().downcast_ref::().unwrap().clone() + let Some(IROperand::Type(ret)) = self.no.as_any().downcast_ref::() else { + panic!(); + }; + *ret } } /// This trait is used to build the select node @@ -429,8 +249,8 @@ impl BuildSelect for Function { block.push_ir(Box::new(Select { out: out.clone(), cond: cond, - yes: yes, - no: no, + yes: IROperand::Type(yes), + no: IROperand::Type(no), })); out @@ -446,8 +266,8 @@ impl BuildSelect for Function { block.push_ir(Box::new(Select { out: out.clone(), cond: cond, - yes: yes, - no: no, + yes: IROperand::Type(yes), + no: IROperand::Var(no), })); out @@ -463,8 +283,8 @@ impl BuildSelect for Function { block.push_ir(Box::new(Select { out: out.clone(), cond: cond, - yes: yes, - no: no, + yes: IROperand::Var(yes), + no: IROperand::Type(no), })); out @@ -480,8 +300,8 @@ impl BuildSelect for Function { block.push_ir(Box::new(Select { out: out.clone(), cond: cond, - yes: yes, - no: no, + yes: IROperand::Var(yes), + no: IROperand::Var(no), })); out diff --git a/src/IR/parser/parser.rs b/src/IR/parser/parser.rs index f43d4d85..21ba1b0e 100644 --- a/src/IR/parser/parser.rs +++ b/src/IR/parser/parser.rs @@ -1097,11 +1097,6 @@ impl IrParser { let ty = self.parse_type()?; self.input.pop_front(); // type - let out = Var { - name: var, - ty: ty - }; - self.expect(TokenType::Var(String::new()))?; let cond = if let TokenType::Var(cond) = &self.current_token()?.typ { Var { @@ -1114,97 +1109,29 @@ impl IrParser { self.expect(TokenType::Comma)?; self.input.pop_front(); // , - let _op1_ty = self.parse_type()?; + let op1_ty = self.parse_type()?; self.input.pop_front(); // ty + let ls = self.parse_operand(op1_ty)?; + self.input.pop_front(); - let current = self.current_token()?; - - if let TokenType::Var(op1) = ¤t.typ { - let op1 = Var { - name: op1.to_owned(), - ty: ty - }; - - self.input.pop_front(); // var1 - self.expect(TokenType::Comma)?; - self.input.pop_front(); // , - - //self.parse_type()?; - self.input.pop_front(); - - let current = self.current_token()?; - - if let TokenType::Var(op2) = ¤t.typ { - let op2 = Var { - name: op2.to_owned(), - ty: ty - }; - - self.input.pop_front(); - - Ok(Box::new(Select { - out: out, - cond: cond, - yes: op1, - no: op2, - })) - } else if let TokenType::Int(op2) = ¤t.typ { - let op2 = Type::from_int(ty, *op2); - - self.input.pop_front(); - - Ok(Box::new(Select { - out: out, - cond: cond, - yes: op1, - no: op2, - })) - } else { - Err(IrError::UnexpectedToken(current.clone())) - } - } else if let TokenType::Int(imm) = ¤t.typ { - let op1 = Type::from_int(ty, *imm); - self.input.pop_front(); - - self.expect(TokenType::Comma)?; - self.input.pop_front(); - - self.parse_type()?; - self.input.pop_front(); - - let current = self.current_token()?; - - if let TokenType::Var(op2) = ¤t.typ { - let op2 = Var { - name: op2.to_owned(), - ty: ty - }; - - self.input.pop_front(); + self.expect(TokenType::Comma)?; + self.input.pop_front(); // , - Ok(Box::new(Select { - out: out, - cond: cond, - yes: op1, - no: op2, - })) - } else if let TokenType::Int(op2) = ¤t.typ { - let op2 = Type::from_int(ty, *op2); + let op2_ty = self.parse_type()?; + self.input.pop_front(); // ty + let rs = self.parse_operand(op2_ty)?; + self.input.pop_front(); - self.input.pop_front(); + Ok(Box::new(Select { + out: Var { + name: var, + ty: op1_ty, + }, + cond: cond, + yes: ls, + no: rs, + })) - Ok(Box::new(Select { - out: out, - cond: cond, - yes: op1, - no: op2, - })) - } else { - Err(IrError::UnexpectedToken(current.clone())) - } - } else { - Err(IrError::UnexpectedToken(current.clone())) - } } fn parse_getelemptr(&mut self, var: String) -> Result, IrError> { diff --git a/src/Optimizations/Passes/InstrCombine.rs b/src/Optimizations/Passes/InstrCombine.rs index a462bb5c..27eeadb0 100644 --- a/src/Optimizations/Passes/InstrCombine.rs +++ b/src/Optimizations/Passes/InstrCombine.rs @@ -45,9 +45,8 @@ impl InstrCombinePass { /// Optimizes a single instruction into a more performant one pub(crate) fn opt1(node: &Box) -> Option> { use crate::IR::ir::*; - use crate::IR::*; - opt1_impl!(node, is_select, InstrCombinePass::opt_select, Select); + opt1_impl!(node, is_select, InstrCombinePass::opt_select, Select); None } diff --git a/src/Target/target_descr.rs b/src/Target/target_descr.rs index ee3207df..da5f2971 100644 --- a/src/Target/target_descr.rs +++ b/src/Target/target_descr.rs @@ -295,9 +295,6 @@ compile_func!(compile_switch, compile_switch, Switch); compile_func!(compile_neg, compile_neg, Neg); -compile_func!(compile_select_tt, compile_select_tt, Select); -compile_func!(compile_select_vt, compile_select_vt, Select); -compile_func!(compile_select_tv, compile_select_tv, Select); -compile_func!(compile_select_vv, compile_select_vv, Select); +compile_func!(compile_select, compile_select, Select); compile_func!(compile_getelemptr, compile_getelemptr, GetElemPtr); \ No newline at end of file diff --git a/src/Target/x64/lower/cmov.rs b/src/Target/x64/lower/cmov.rs index bcdcc56d..754f6e6f 100644 --- a/src/Target/x64/lower/cmov.rs +++ b/src/Target/x64/lower/cmov.rs @@ -12,37 +12,44 @@ pub(crate) fn x64_lower_cmov_zero(sink: &mut Vec, instr: &MachineIns let cond = (*cond).into(); let value = instr.operands.get(1).expect("expected value for valid cmov"); - let value = (*value).into(); + let value: Operand = (*value).into(); let out = instr.out.expect("expected output for valid cmov"); - let out = out.into(); + let out: Operand = out.into(); - let cmp = if let Operand::Mem(_) = cond { - vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(0)), - X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11))] + if out.is_mem() || value.is_imm() { + sink.push( X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), value.clone()) ); + } + + if let Operand::Mem(_) = cond { + sink.extend_from_slice(&[ + X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(1)), + X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11)) + ] + ); } else { - vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(0))] + sink.push( X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(1))); }; - if let Operand::Reg(_) = out { - if let Operand::Imm(_) = value { - sink.extend_from_slice(&cmp); - sink.push( X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), value)); + match (&out, &value) { + (Operand::Reg(_), Operand::Imm(_)) => { sink.push( X64MCInstr::with2(Mnemonic::Cmove, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); - } else { - sink.extend_from_slice(&cmp); + }, + (Operand::Reg(_), Operand::Reg(_)) | (Operand::Reg(_), Operand::Mem(_)) => { sink.push( X64MCInstr::with2(Mnemonic::Cmove, out, value)); - } - } else { - if let Operand::Imm(_) = value { - sink.push( X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), value)); - sink.extend_from_slice(&cmp); + }, + + (Operand::Mem(_), Operand::Imm(_)) => { sink.push( X64MCInstr::with2(Mnemonic::Cmove, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); - } else { - sink.extend_from_slice(&cmp); + sink.push( X64MCInstr::with2(Mnemonic::Mov, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); + }, + + (Operand::Mem(_), Operand::Reg(_)) | (Operand::Mem(_), Operand::Mem(_))=> { sink.push( X64MCInstr::with2(Mnemonic::Cmove, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), value)); - } - sink.push( X64MCInstr::with2(Mnemonic::Mov, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); + sink.push( X64MCInstr::with2(Mnemonic::Mov, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); + }, + + _ => todo!(), } } @@ -55,37 +62,44 @@ pub(crate) fn x64_lower_cmov_not_zero(sink: &mut Vec, instr: &Machin let cond = (*cond).into(); let value = instr.operands.get(1).expect("expected value for valid cmov"); - let value = (*value).into(); + let value: Operand = (*value).into(); let out = instr.out.expect("expected output for valid cmov"); - let out = out.into(); + let out: Operand = out.into(); - let cmp = if let Operand::Mem(_) = cond { - vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(0)), - X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11))] + if out.is_mem() || value.is_imm() { + sink.push( X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), value.clone()) ); + } + + if let Operand::Mem(_) = cond { + sink.extend_from_slice(&[ + X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(1)), + X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11)) + ] + ); } else { - vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(0))] + sink.push( X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(1))); }; - if let Operand::Reg(_) = out { - if let Operand::Imm(_) = value { - sink.extend_from_slice(&cmp); - sink.push( X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), value)); + match (&out, &value) { + (Operand::Reg(_), Operand::Imm(_)) => { sink.push( X64MCInstr::with2(Mnemonic::Cmovne, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); - } else { - sink.extend_from_slice(&cmp); + }, + (Operand::Reg(_), Operand::Reg(_)) | (Operand::Reg(_), Operand::Mem(_)) => { sink.push( X64MCInstr::with2(Mnemonic::Cmovne, out, value)); - } - } else { - if let Operand::Imm(_) = value { - sink.push( X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), value)); - sink.extend_from_slice(&cmp); + }, + + (Operand::Mem(_), Operand::Imm(_)) => { sink.push( X64MCInstr::with2(Mnemonic::Cmovne, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); - } else { - sink.extend_from_slice(&cmp); + sink.push( X64MCInstr::with2(Mnemonic::Mov, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); + }, + + (Operand::Mem(_), Operand::Reg(_)) | (Operand::Mem(_), Operand::Mem(_))=> { sink.push( X64MCInstr::with2(Mnemonic::Cmovne, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), value)); - } - sink.push( X64MCInstr::with2(Mnemonic::Mov, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); + sink.push( X64MCInstr::with2(Mnemonic::Mov, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); + }, + + _ => todo!(), } } @@ -109,10 +123,10 @@ pub(crate) fn x64_lower_fcmov0(sink: &mut Vec, instr: &MachineInstr) }; sink.extend_from_slice(&if let Operand::Mem(_) = cond { - vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(0)), + vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(1)), X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11))] } else { - vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(0))] + vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(1))] }); if let Operand::Reg(_) = out { @@ -152,10 +166,10 @@ pub(crate) fn x64_lower_fcmovne0(sink: &mut Vec, instr: &MachineInst }; sink.extend_from_slice(&if let Operand::Mem(_) = cond { - vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(0)), + vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(1)), X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11))] } else { - vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(0))] + vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(1))] }); if let Operand::Reg(_) = out { diff --git a/src/Target/x64/lower/fcmp.rs b/src/Target/x64/lower/fcmp.rs index 1229c3cb..4e25989d 100644 --- a/src/Target/x64/lower/fcmp.rs +++ b/src/Target/x64/lower/fcmp.rs @@ -7,10 +7,12 @@ pub(crate) fn x64_lower_fcmp(sink: &mut Vec, instr: &MachineInstr, m let ls = instr.operands.get(0).expect("expected valid src operand at 1. place"); let rs = instr.operands.get(1).expect("expected valid value to compare at 2. place"); let out = instr.out.expect("expected output"); - let out = out.into(); + let out: Operand = out.into(); let ls: Operand = (*ls).into(); let rs: Operand = (*rs).into(); + sink.push(X64MCInstr::with2(Mnemonic::Mov, out.to_owned(), Operand::Imm(0))); + let mnemonic = if TypeMetadata::f32 == instr.meta { Mnemonic::Ucomiss } else if TypeMetadata::f64 == instr.meta { diff --git a/tests/IR/select/fp0.yl b/tests/IR/select/fp0.yl index 47572439..1dabacd7 100644 --- a/tests/IR/select/fp0.yl +++ b/tests/IR/select/fp0.yl @@ -8,7 +8,7 @@ define f32 @test(f32 %0) { entry: %tmp = f32 1.0 %cond = cmp eq f32 %0, %tmp - %ret = select f32 %cond, f32 1.2, i32 2.4 + %ret = select i8 %cond, f32 1.2, i32 2.4 ret f32 %ret } diff --git a/tests/IR/select/select1.yl b/tests/IR/select/select1.yl index 604d60ac..a3de1bdb 100644 --- a/tests/IR/select/select1.yl +++ b/tests/IR/select/select1.yl @@ -8,8 +8,8 @@ define i32 @main() { entry: %a = i32 0 - %ret = select i32 %a, i32 5, i32 2 + %ret = select i32 %a, i32 2, i32 5 ret i32 %ret } -# EXIT_CODE=2 \ No newline at end of file +# EXIT_CODE=5 \ No newline at end of file diff --git a/tests/IR/select/select2.yl b/tests/IR/select/select2.yl index 025b722a..aaa94d23 100644 --- a/tests/IR/select/select2.yl +++ b/tests/IR/select/select2.yl @@ -14,7 +14,7 @@ define i32 @main() { %ifcond = cmp eq i32 %a, %5 - %ret = select i32 %ifcond, i32 %b, i32 0 + %ret = select i8 %ifcond, i32 %b, i32 0 ret i32 %ret }