Warning
This post was published 37 days ago. The information described in this article may have changed.
Sorry for the vague title, trying to find an efficient way of doing something.
Optimization phase of a compiler, in the constant folding pass. I have a bunch of operations on a bunch of values. If both operands (for a binary op) are constants then the operation can be replaced a constant (int x = 4 + 5
for example). I can obviously make a huge set of multiply nested matches but it seems like I could simplify it
the values are
pub enum Value {
Int32(i32),
Int64(i64),
UInt32(u32),
UInt64(u64),
Double(f64),
Char(i8),
UChar(u8),
String(String),
Variable(String, SymbolType),
Void,
}
the first 7 are all constants of the given type. The binary operators are (I also have Unary ops)
pub enum BinaryOperator {
Add,
Subtract,
Multiply,
Divide,
Remainder,
BitAnd,
BitOr,
BitXor,
ShiftLeft,
ShiftRight,
Equal,
NotEqual,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
}
so for example if the operator is Add and the Values are int32 I need to do (using EnumAsInner for the as_xxx
calls)
let new_constant = Value::Int32(left.as_int32().unwrap().wrapping_add right.as_int32().unwrap()));
(Note the wrapping add)
I wrote this macro
macro_rules! binop_num {
($left:ident,$right:ident, $op:path) => {
match $left.stype() {
SymbolType::Int32 => {
Value::Int32($op($left.as_int32().unwrap(), $right.as_int32().unwrap()))
}
SymbolType::UInt32 => Value::UInt32($op(
$left.as_u_int32().unwrap(),
$right.as_u_int32().unwrap(),
)),
SymbolType::Int64 => {
Value::Int64($op($left.as_int64().unwrap(), $right.as_int64().unwrap()))
}
SymbolType::UInt64 => Value::UInt64($op(
$left.as_u_int64().unwrap(),
$right.as_u_int64().unwrap(),
)),
// SymbolType::Double => {
// Value::Double($op($left.as_double().unwrap(), $right.as_double().unwrap()))
// }
SymbolType::Char | SymbolType::SChar => {
Value::Char($op($left.as_char().unwrap(), $right.as_char().unwrap()))
}
SymbolType::UChar => {
Value::UChar($op($left.as_u_char().unwrap(), $right.as_u_char().unwrap()))
}
_ => panic!("Unsupported type for binop: {:?}", $left.stype()),
}
};
}
used like this
let result = match op {
BinaryOperator::Add => {
binop_num!(left, right, WrappingAdd::wrapping_add)
}
BinaryOperator::Subtract => {
binop_num!(left, right, WrappingSub::wrapping_sub)
}
....
the problems are
Any suggestions about the best way to do this, like I said I can simply type out enormous matches for each combination of Instruction (BinaryOperator, UnaryOperator,..), sub op (BinaryOperator::Add, Unary::Negate,..) and value type
1 post - 1 participant
🏷️ rust_feed