diff --git a/hercules_cg/src/cpu_beta.rs b/hercules_cg/src/cpu_beta.rs
index 9a1c6741009e121a6b9fce71a939e733ec0f4ca0..e3974111b8f57aa75d456eeb367c0daf8aa861cf 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 2657447e2d8f28dd4b66ce17b8273dede6df8205..e2c8c39b0f515ba7b8083a7de279dec5376a0f77 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 ff631bd7d64828cb0519fd709f513736cc41b08b..bcd3a1523748445f673ab69c92de44e04660d4f1 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 8999730fcb78065433519e1ed219065ccba53ff9..a7bc60bf5fa94cb98a7b704a7bb4c5560f2c92a3 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()
             };