logo
class

compiler::ConstantFolder

sys::Obj
  compiler::CompilerSupport
    compiler::ConstantFolder
   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  }