Something went wrong. Try again.
🌱 A minimal programming language and compiler. git.urbach.dev/cli/q
high-performance programming-language compiler
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154package optimizer
import ( "math"
"git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/cli/q/src/token")
// foldBinaryOp folds the values for binary operations.func foldBinaryOp(ir ssa.IR, block *ssa.Block, binaryOp *ssa.BinaryOp, folded map[ssa.Value]struct{}) map[ssa.Value]struct{} { if binaryOp.Op.IsComparison() { return folded }
i := block.Index(binaryOp)
if i == -1 { return folded }
if binaryOp.Op == token.Add || binaryOp.Op == token.Sub { leftZero, leftIsZero := binaryOp.Left.(*ssa.Int)
if leftIsZero && leftZero.Int == 0 && binaryOp.Op == token.Add { return foldTo(ir, binaryOp, binaryOp.Right, binaryOp.Left, folded) }
rightZero, rightIsZero := binaryOp.Right.(*ssa.Int)
if rightIsZero && rightZero.Int == 0 { return foldTo(ir, binaryOp, binaryOp.Left, binaryOp.Right, folded) } }
isAssociative := binaryOp.Op.IsAssociative() foldLeft := binaryOp.Left leftBinOp, leftIsBinOp := foldLeft.(*ssa.BinaryOp)
if isAssociative && leftIsBinOp && leftBinOp.Op == binaryOp.Op { innerRight, innerRightIsInt := leftBinOp.Right.(*ssa.Int)
if innerRightIsInt { foldLeft = innerRight } else { if !binaryOp.Op.IsCommutative() { return folded }
innerLeft, innerLeftIsInt := leftBinOp.Left.(*ssa.Int)
if !innerLeftIsInt { return folded }
foldLeft = innerLeft } }
left, leftIsInt := foldLeft.(*ssa.Int)
if !leftIsInt { return folded }
foldRight := binaryOp.Right rightBinOp, rightIsBinOp := foldRight.(*ssa.BinaryOp)
if isAssociative && rightIsBinOp && rightBinOp.Op == binaryOp.Op { foldRight = rightBinOp.Left }
if isAssociative && rightIsBinOp && rightBinOp.Op == binaryOp.Op { innerLeft, innerLeftIsInt := rightBinOp.Left.(*ssa.Int)
if innerLeftIsInt { foldRight = innerLeft } else { if !binaryOp.Op.IsCommutative() { return folded }
innerRight, innerRightIsInt := rightBinOp.Right.(*ssa.Int)
if !innerRightIsInt { return folded }
foldRight = innerRight } }
right, rightIsInt := foldRight.(*ssa.Int)
if !rightIsInt { return folded }
if binaryOp.Op == token.Div || binaryOp.Op == token.Mod { if right.Int == 0 { return folded }
if left.Int == math.MinInt64 && right.Int == -1 { return folded } }
if leftIsBinOp && rightIsBinOp { return folded }
if folded == nil { folded = make(map[ssa.Value]struct{}) }
folded[foldLeft] = struct{}{} folded[foldRight] = struct{}{}
constant := &ssa.Int{ Int: foldBinary(binaryOp.Op, left.Int, right.Int), Source: binaryOp.Source, }
switch { case !leftIsBinOp && !rightIsBinOp: block.Instructions[i] = constant ir.ReplaceAll(binaryOp, constant) case leftIsBinOp && !rightIsBinOp: folded[leftBinOp] = struct{}{}
if foldLeft == leftBinOp.Right { binaryOp.Left = leftBinOp.Left } else { binaryOp.Left = leftBinOp.Right }
binaryOp.Right = constant block.InsertAt(i, constant) case !leftIsBinOp && rightIsBinOp: folded[rightBinOp] = struct{}{} binaryOp.Left = constant
if foldRight == rightBinOp.Left { binaryOp.Right = rightBinOp.Right } else { binaryOp.Right = rightBinOp.Left }
block.InsertAt(i, constant) }
return folded}