so this question might seem too newbie, but I'm already reading the book "Advanced Compiler Design and Implementation" by Steven Muchnick and in the first chapter of optimization it talks about constant folding.
first attempt was something like below, but it was almost impossible to implement considering it needed typeclasses Integral
and Bits
.
data Value
= BoolV Bool
| IntegerV Integer
| FloatV Double
| StringV String
deriving (Show, Eq)
data Expression
= Const Value
| Temp Label
| List [Expression]
| Call Label [Expression]
| BinOp Operator Expression Expression
deriving (Show, Eq)
rerunOverIR :: Expression -> Expression
rerunOverIR = \case
Const constant -> Const constant
Temp temporary -> Temp temporary
List list -> List list
Call label args -> Call label (map rerunOverIR args)
BinOp operator lhs rhs ->
case operator of
Addition -> folder (+)
Subtraction -> folder (-)
Multiplication -> folder (*)
Modulo -> folder mod
Division -> folder div
BitwiseAnd -> folder (.&.)
BitwiseOr -> folder (.|.)
BitwiseXor -> folder xor
ShiftRight -> folder shiftR
ShiftLeft -> folder shiftL
Equal -> folder (==)
NotEqual -> folder (/=)
Greater -> folder (>)
GreaterEqual -> folder (>=)
Less -> folder (<)
LessEqual -> folder (<=)
LogicalAnd -> folder (&&)
LogicalOr -> folder (||)
_ -> error $ "this operator doesn't exist " ++ show operator
where
folder op =
case lhs of
Const c1 -> case rhs of
Const c2 -> Const $ op c1 c2
expr -> rerunOverIR $ BinOp operator (Const c1) (rerunOverIR expr)
e1 -> case rhs of
Const c2 -> rerunOverIR $ BinOp operator (rerunOverIR e1) (Const c2)
e2 -> rerunOverIR $ BinOp operator (rerunOverIR e1) (rerunOverIR e2)
so I tried to this time change expressions to below, but it's even worse.
data Expression
= Bool Bool
| Integer Integer
| Float Double
| String String
| Temp Label
| List [Expression]
| Call Label [Expression]
| BinOp Operator Expression Expression
deriving (Show, Eq)
so my question is that, how compilers or interpreters written in Haskell properly handle constant folding at the late stage? I'm pretty sure I'm on the wrong track...
It looks like you should certainly be able to do it by doing, for example,
Addition -> folderNum (+)
...
where folderNum :: (forall a. Num a => a -> a -> a) -> Expression
folderNum op = case (lhs, rhs) of
(Const (IntegerV a), Const (IntegerV b)) -> Const (IntegerV (op a b))
(Const (FloatV a), Const (FloatV b)) -> Const (FloatV (op a b))
else -> ...
You're on the right track, but you're going to have to do the detailed case work to match which binary operations apply to which constant types, presumably for each distinct type class in Haskell that supports the operations you'll need.