From 6398a11b58b2a891ee14b8e72d5330f5a75c1dbd Mon Sep 17 00:00:00 2001 From: Juni May Date: Fri, 23 Feb 2024 13:30:26 +0800 Subject: [PATCH] feat(ir): add cast operations --- src/ir/builder.rs | 7 ++--- src/ir/frontend.rs | 4 +-- src/ir/frontend/ast.rs | 11 +++++-- src/ir/frontend/convert.rs | 4 +-- src/ir/frontend/lexer.rs | 14 +++++++-- src/ir/frontend/parser.rs | 5 +-- src/ir/values.rs | 59 ++++++++++++++++++++++++++++++++++-- src/passes/printer.rs | 2 +- tests/ir_cases/06_cast.orzir | 2 +- 9 files changed, 89 insertions(+), 19 deletions(-) diff --git a/src/ir/builder.rs b/src/ir/builder.rs index ec40713..efa287a 100644 --- a/src/ir/builder.rs +++ b/src/ir/builder.rs @@ -3,8 +3,7 @@ use super::{ module::{DataFlowGraph, Module}, types::{Type, TypeKind}, values::{ - Alloc, Binary, BinaryOp, Block, Branch, Call, Cast, Function, GetElemPtr, GlobalSlot, Jump, - Load, Return, Store, Unary, UnaryOp, Value, + Alloc, Binary, BinaryOp, Block, Branch, Call, Cast, CastOp, Function, GetElemPtr, GlobalSlot, Jump, Load, Return, Store, Unary, UnaryOp, Value }, }; use thiserror::Error; @@ -232,8 +231,8 @@ pub trait LocalValueBuilder: QueryDfgData + AddValue + ConstantBuilder { } /// Build a cast instruction - fn cast(&mut self, ty: Type, val: Value) -> Result { - self.add_value(Cast::new_value_data(ty, val)) + fn cast(&mut self, op: CastOp, ty: Type, val: Value) -> Result { + self.add_value(Cast::new_value_data(op, ty, val)) } /// Build a store instruction. diff --git a/src/ir/frontend.rs b/src/ir/frontend.rs index c0728ef..9dd4fee 100644 --- a/src/ir/frontend.rs +++ b/src/ir/frontend.rs @@ -1,4 +1,4 @@ -use super::values::{BinaryOp, UnaryOp}; +use super::values::{BinaryOp, CastOp, UnaryOp}; mod lexer; @@ -79,7 +79,7 @@ pub enum InstKind { Call, /// `cast` - Cast, + Cast(CastOp), /// `getelemptr` GetElemPtr, diff --git a/src/ir/frontend/ast.rs b/src/ir/frontend/ast.rs index 035385e..3a79c31 100644 --- a/src/ir/frontend/ast.rs +++ b/src/ir/frontend/ast.rs @@ -1,4 +1,4 @@ -use crate::ir::types::Type; +use crate::ir::{types::Type, values::CastOp}; use super::InstKind; @@ -283,9 +283,14 @@ impl Inst { })) } - pub(super) fn new_boxed_cast(dest: String, ty: Type, val: AstNodeBox) -> AstNodeBox { + pub(super) fn new_boxed_cast( + dest: String, + op: CastOp, + ty: Type, + val: AstNodeBox, + ) -> AstNodeBox { Box::new(AstNode::Inst(Inst { - kind: InstKind::Cast, + kind: InstKind::Cast(op), dest: Some(dest), operands: vec![val], ty: Some(ty), diff --git a/src/ir/frontend/convert.rs b/src/ir/frontend/convert.rs index fb6dc54..db68fc6 100644 --- a/src/ir/frontend/convert.rs +++ b/src/ir/frontend/convert.rs @@ -221,12 +221,12 @@ impl Ast { .builder() .load(ast_inst.ty.clone().unwrap(), ptr)? } - InstKind::Cast => { + InstKind::Cast(op) => { let val = self.operand_to_value(&ast_inst.operands[0], ctx, function)?; dfg_mut!(ctx.module, function) .builder() - .cast(ast_inst.ty.clone().unwrap(), val)? + .cast(op.clone(), ast_inst.ty.clone().unwrap(), val)? } InstKind::Alloc => dfg_mut!(ctx.module, function) .builder() diff --git a/src/ir/frontend/lexer.rs b/src/ir/frontend/lexer.rs index faf3373..6124ad9 100644 --- a/src/ir/frontend/lexer.rs +++ b/src/ir/frontend/lexer.rs @@ -2,7 +2,7 @@ use std::io; use crate::ir::{ frontend::tokens::{Span, TokenKind}, - values::{BinaryOp, FCmpCond, ICmpCond, UnaryOp}, + values::{BinaryOp, CastOp, FCmpCond, ICmpCond, UnaryOp}, GLOBAL_PREFIX_CHAR, LABEL_PREFIX_CHAR, LOCAL_PREFIX_CHAR, TYPE_PREFIX_CHAR, }; @@ -265,7 +265,17 @@ where "ret" => TokenKind::Inst(InstKind::Return), "call" => TokenKind::Inst(InstKind::Call), "getelemptr" => TokenKind::Inst(InstKind::GetElemPtr), - "cast" => TokenKind::Inst(InstKind::Cast), + + "trunc" => TokenKind::Inst(InstKind::Cast(CastOp::Trunc)), + "zext" => TokenKind::Inst(InstKind::Cast(CastOp::ZExt)), + "sext" => TokenKind::Inst(InstKind::Cast(CastOp::SExt)), + "fptrunc" => TokenKind::Inst(InstKind::Cast(CastOp::FpTrunc)), + "fpext" => TokenKind::Inst(InstKind::Cast(CastOp::FpExt)), + "fptoui" => TokenKind::Inst(InstKind::Cast(CastOp::FpToUI)), + "fptosi" => TokenKind::Inst(InstKind::Cast(CastOp::FpToSI)), + "uitofp" => TokenKind::Inst(InstKind::Cast(CastOp::UIToFp)), + "sitofp" => TokenKind::Inst(InstKind::Cast(CastOp::SIToFp)), + "bitcast" => TokenKind::Inst(InstKind::Cast(CastOp::Bitcast)), _ => { if word.starts_with('i') { diff --git a/src/ir/frontend/parser.rs b/src/ir/frontend/parser.rs index e3dad0c..2dcbcc7 100644 --- a/src/ir/frontend/parser.rs +++ b/src/ir/frontend/parser.rs @@ -424,11 +424,12 @@ where let ptr = self.parse_operand()?; Inst::new_boxed_load(dest, ty, ptr) } - InstKind::Cast => { + InstKind::Cast(op) => { + let op = op.clone(); let ty = self.parse_type()?; self.expect(TokenKind::Comma)?; let val = self.parse_operand()?; - Inst::new_boxed_cast(dest, ty, val) + Inst::new_boxed_cast(dest, op, ty, val) } InstKind::Alloc => { let ty = self.parse_type()?; diff --git a/src/ir/values.rs b/src/ir/values.rs index dd1fa40..d70e9c3 100644 --- a/src/ir/values.rs +++ b/src/ir/values.rs @@ -359,21 +359,76 @@ impl Load { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum CastOp { + /// Truncate + Trunc, + + /// Zero extend + ZExt, + + /// Sign extend + SExt, + + /// Float to unsigned int + FpToUI, + + /// Float to signed int + FpToSI, + + /// Unsigned int to float + UIToFp, + + /// Signed int to float + SIToFp, + + /// Float truncation + FpTrunc, + + /// Float extension + FpExt, + + /// Bitcast + Bitcast, +} + +impl fmt::Display for CastOp { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CastOp::Trunc => write!(f, "trunc"), + CastOp::ZExt => write!(f, "zext"), + CastOp::SExt => write!(f, "sext"), + CastOp::FpToUI => write!(f, "fptoui"), + CastOp::FpToSI => write!(f, "fptosi"), + CastOp::UIToFp => write!(f, "uitofp"), + CastOp::SIToFp => write!(f, "sitofp"), + CastOp::FpTrunc => write!(f, "fptrunc"), + CastOp::FpExt => write!(f, "fpext"), + CastOp::Bitcast => write!(f, "bitcast"), + } + } +} + /// Type cast /// /// Perform bitcast operation, the type is available in [`ValueData`]. pub struct Cast { + op: CastOp, val: Value, } impl Cast { - pub(super) fn new_value_data(ty: Type, val: Value) -> ValueData { - ValueData::new(ty, ValueKind::Cast(Cast { val })) + pub(super) fn new_value_data(op: CastOp, ty: Type, val: Value) -> ValueData { + ValueData::new(ty, ValueKind::Cast(Cast { op, val })) } pub fn val(&self) -> Value { self.val } + + pub fn op(&self) -> CastOp { + self.op.clone() + } } /// Allocation instruction internals. diff --git a/src/passes/printer.rs b/src/passes/printer.rs index 79b7bde..a3cfe5d 100644 --- a/src/passes/printer.rs +++ b/src/passes/printer.rs @@ -207,7 +207,7 @@ where self.print_operand(load.ptr(), dfg) } ValueKind::Cast(cast) => { - write!(self.buf, "{} = cast {}, ", dfg.value_name(value), data.ty())?; + write!(self.buf, "{} = {} {}, ", dfg.value_name(value), cast.op(), data.ty())?; self.print_operand(cast.val(), dfg) } ValueKind::Store(store) => { diff --git a/tests/ir_cases/06_cast.orzir b/tests/ir_cases/06_cast.orzir index 1acd56d..b836b24 100644 --- a/tests/ir_cases/06_cast.orzir +++ b/tests/ir_cases/06_cast.orzir @@ -1,6 +1,6 @@ func @check(i32) -> i32 { ^entry(i32 %0): - %cond = cast i1, i32 %0 + %cond = bitcast i1, i32 %0 br i1 %cond, ^true, ^false ^true: