
1 // 2 // Copyright (c) 2006, Brian Frank and Andy Frank 3 // Licensed under the Academic Free License version 3.0 4 // 5 // History: 6 // 23 Oct 06 Brian Frank Creation 7 // 8 9 ** 10 ** ConstantFolder is used to implement constant folding optimizations 11 ** where known literals and operations can be performed ahead of time 12 ** by the compiler. 13 ** 14 class ConstantFolder : CompilerSupport 15 { 16 17 ////////////////////////////////////////////////////////////////////////// 18 // Construction 19 ////////////////////////////////////////////////////////////////////////// 20 21 ** 22 ** Constructor 23 ** 24 new make(Compiler compiler) 25 : super(compiler) 26 { 27 } 28 29 ////////////////////////////////////////////////////////////////////////// 30 // Resolve 31 ////////////////////////////////////////////////////////////////////////// 32 33 ** 34 ** Check shortcut expression for constant folding 35 ** 36 Expr fold(CallExpr call) 37 { 38 // there are certain methods we never optimize 39 name := call.name 40 if (never.containsKey(name)) return call 41 42 // check if target is constant 43 target := exprToConst(call.target) 44 if (target == null) return call 45 46 // check if all the parameters are constant 47 Obj[] args := null 48 for (i:=0; i<call.args.size; ++i) 49 { 50 arg := exprToConst(call.args[i]) 51 if (arg == null) return call 52 if (i === 0) args = [,] 53 args.add(arg) 54 } 55 56 // everything is constant, so try to find an instance method 57 method := target.type.method(name, false) 58 if (method == null || method.isStatic || 59 method.params.size != call.args.size) return call 60 61 // try to invoke the method to get the result 62 Obj result := null 63 try 64 { 65 result = method.callOn(target, args) 66 } 67 catch 68 { 69 return call 70 } 71 72 // always skip constant folding on sysTest 73 if (compiler.pod.name == "sysTest") return call 74 75 // try to map result to literal 76 return constToExpr(call, result) 77 } 78 79 private Obj exprToConst(Expr expr) 80 { 81 if (expr == null) return null 82 switch (expr.id) 83 { 84 case ExprId.intLiteral: return ((LiteralExpr)expr).val 85 case ExprId.floatLiteral: return ((LiteralExpr)expr).val 86 case ExprId.strLiteral: return ((LiteralExpr)expr).val 87 case ExprId.durationLiteral: return ((LiteralExpr)expr).val 88 default: return null 89 } 90 } 91 92 private Expr constToExpr(Expr orig, Obj val) 93 { 94 if (val is Int) return LiteralExpr.make(orig.location, ExprId.intLiteral, ns.intType, val) 95 if (val is Float) return LiteralExpr.make(orig.location, ExprId.floatLiteral, ns.floatType, val) 96 if (val is Str) return LiteralExpr.make(orig.location, ExprId.strLiteral, ns.strType, val) 97 if (val is Duration) return LiteralExpr.make(orig.location, ExprId.durationLiteral, ns.durationType, val) 98 return orig 99 } 100 101 private const static Str:Int never := ["compare":1, "equal":1, "hash":1, "intern":1].toImmutable 102 103 }