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 }
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 }