From ffbb263d7deedc236a0685f998639f09e93ebafd Mon Sep 17 00:00:00 2001
From: Russel Arbore <russel.jma@gmail.com>
Date: Mon, 19 Feb 2024 19:57:24 -0600
Subject: [PATCH] Cast node

---
 hercules_cg/src/cpu_beta.rs  |  1 +
 hercules_ir/src/ir.rs        |  3 +++
 hercules_ir/src/typecheck.rs | 20 ++++++++++++++++++++
 hercules_opt/src/ccp.rs      | 30 +++++++++++++++---------------
 4 files changed, 39 insertions(+), 15 deletions(-)

diff --git a/hercules_cg/src/cpu_beta.rs b/hercules_cg/src/cpu_beta.rs
index 9a1c6741..e3974111 100644
--- a/hercules_cg/src/cpu_beta.rs
+++ b/hercules_cg/src/cpu_beta.rs
@@ -614,6 +614,7 @@ fn emit_llvm_for_node(
                     todo!()
                 }
             }
+            UnaryOperator::Cast(_) => todo!(),
         },
         Node::Binary { left, right, op } => {
             let opcode = match op {
diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs
index 2657447e..e2c8c39b 100644
--- a/hercules_ir/src/ir.rs
+++ b/hercules_ir/src/ir.rs
@@ -225,6 +225,7 @@ pub enum Node {
 pub enum UnaryOperator {
     Not,
     Neg,
+    Cast(TypeID),
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -1005,6 +1006,7 @@ impl UnaryOperator {
         match self {
             UnaryOperator::Not => "Not",
             UnaryOperator::Neg => "Neg",
+            UnaryOperator::Cast(_) => "Cast",
         }
     }
 
@@ -1012,6 +1014,7 @@ impl UnaryOperator {
         match self {
             UnaryOperator::Not => "not",
             UnaryOperator::Neg => "neg",
+            UnaryOperator::Cast(_) => "cast",
         }
     }
 }
diff --git a/hercules_ir/src/typecheck.rs b/hercules_ir/src/typecheck.rs
index ff631bd7..bcd3a152 100644
--- a/hercules_ir/src/typecheck.rs
+++ b/hercules_ir/src/typecheck.rs
@@ -625,6 +625,17 @@ fn typeflow(
                             ));
                         }
                     }
+                    UnaryOperator::Cast(dst_id) => {
+                        let src_ty = &types[id.idx()];
+                        let dst_ty = &types[dst_id.idx()];
+                        if cast_compatible(src_ty, dst_ty) {
+                            return Concrete(*dst_id);
+                        } else {
+                            return Error(String::from(
+                                "Cast unary node has incompatible input and output types.",
+                            ));
+                        }
+                    }
                 }
             }
 
@@ -940,3 +951,12 @@ pub fn fork_join_map(
     }
     fork_join_map
 }
+
+/*
+ * Determine if a given cast conversion is valid.
+ */
+pub fn cast_compatible(src_ty: &Type, dst_ty: &Type) -> bool {
+    // Can convert between any pair of primitive types, as long as the cast is
+    // not from a floating point type to a boolean type.
+    src_ty.is_primitive() && dst_ty.is_primitive() && !(src_ty.is_float() && dst_ty.is_bool())
+}
diff --git a/hercules_opt/src/ccp.rs b/hercules_opt/src/ccp.rs
index 8999730f..a7bc60bf 100644
--- a/hercules_opt/src/ccp.rs
+++ b/hercules_opt/src/ccp.rs
@@ -444,22 +444,22 @@ fn ccp_flow_function(
             } = inputs[input.idx()];
 
             let new_constant = if let ConstantLattice::Constant(cons) = constant {
-                let new_cons = match (op, cons) {
-                    (UnaryOperator::Not, Constant::Boolean(val)) => Constant::Boolean(!val),
-                    (UnaryOperator::Not, Constant::Integer8(val)) => Constant::Integer8(!val),
-                    (UnaryOperator::Not, Constant::Integer16(val)) => Constant::Integer16(!val),
-                    (UnaryOperator::Not, Constant::Integer32(val)) => Constant::Integer32(!val),
-                    (UnaryOperator::Not, Constant::Integer64(val)) => Constant::Integer64(!val),
-                    (UnaryOperator::Neg, Constant::Integer8(val)) => Constant::Integer8(-val),
-                    (UnaryOperator::Neg, Constant::Integer16(val)) => Constant::Integer16(-val),
-                    (UnaryOperator::Neg, Constant::Integer32(val)) => Constant::Integer32(-val),
-                    (UnaryOperator::Neg, Constant::Integer64(val)) => Constant::Integer64(-val),
-                    (UnaryOperator::Neg, Constant::Float32(val)) => Constant::Float32(-val),
-                    (UnaryOperator::Neg, Constant::Float64(val)) => Constant::Float64(-val),
-                    (UnaryOperator::Neg, Constant::Zero(id)) => Constant::Zero(*id),
+                match (op, cons) {
+                    (UnaryOperator::Not, Constant::Boolean(val)) => ConstantLattice::Constant(Constant::Boolean(!val)),
+                    (UnaryOperator::Not, Constant::Integer8(val)) => ConstantLattice::Constant(Constant::Integer8(!val)),
+                    (UnaryOperator::Not, Constant::Integer16(val)) => ConstantLattice::Constant(Constant::Integer16(!val)),
+                    (UnaryOperator::Not, Constant::Integer32(val)) => ConstantLattice::Constant(Constant::Integer32(!val)),
+                    (UnaryOperator::Not, Constant::Integer64(val)) => ConstantLattice::Constant(Constant::Integer64(!val)),
+                    (UnaryOperator::Neg, Constant::Integer8(val)) => ConstantLattice::Constant(Constant::Integer8(-val)),
+                    (UnaryOperator::Neg, Constant::Integer16(val)) => ConstantLattice::Constant(Constant::Integer16(-val)),
+                    (UnaryOperator::Neg, Constant::Integer32(val)) => ConstantLattice::Constant(Constant::Integer32(-val)),
+                    (UnaryOperator::Neg, Constant::Integer64(val)) => ConstantLattice::Constant(Constant::Integer64(-val)),
+                    (UnaryOperator::Neg, Constant::Float32(val)) => ConstantLattice::Constant(Constant::Float32(-val)),
+                    (UnaryOperator::Neg, Constant::Float64(val)) => ConstantLattice::Constant(Constant::Float64(-val)),
+                    (UnaryOperator::Neg, Constant::Zero(id)) => ConstantLattice::Constant(Constant::Zero(*id)),
+                    (UnaryOperator::Cast(_), _) => ConstantLattice::Bottom,
                     _ => panic!("Unsupported combination of unary operation and constant value. Did typechecking succeed?")
-                };
-                ConstantLattice::Constant(new_cons)
+                }
             } else {
                 constant.clone()
             };
-- 
GitLab