source: src/Common/Eval.cc@ 699a97d

ADT ast-experimental
Last change on this file since 699a97d was 8f06277, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Some clean-up in Common/utility.h. Deleted some unused declarations and moved others to one of two new headers.

  • Property mode set to 100644
File size: 8.6 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Eval.cc -- Evaluate parts of the ast at compile time.
8//
9// Author : Richard C. Bilson
10// Created On : Mon May 18 07:44:20 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Sat Aug 6 12:11:59 2022
13// Update Count : 119
14//
15
16#include "Eval.h"
17
18#include <utility> // for pair
19
20#include "AST/Inspect.hpp"
21#include "Common/PassVisitor.h"
22#include "CodeGen/OperatorTable.h" // access: OperatorInfo
23#include "AST/Pass.hpp"
24#include "InitTweak/InitTweak.h"
25#include "SynTree/Expression.h"
26
27//-------------------------------------------------------------
28// Old AST
29struct EvalOld : public WithShortCircuiting {
30 long long int value = 0; // compose the result of the constant expression
31 bool valid = true; // true => constant expression and value is the result
32 // false => not constant expression, e.g., ++i
33 bool cfavalid = true; // true => constant expression and value computable
34 // false => constant expression but value not computable, e.g., sizeof(int)
35
36 void previsit( const BaseSyntaxNode * ) { visit_children = false; }
37 void postvisit( const BaseSyntaxNode * ) { valid = false; }
38
39 void postvisit( const SizeofExpr * ) {
40 }
41
42 void postvisit( const ConstantExpr * expr ) {
43 value = expr->intValue();
44 }
45
46 void postvisit( const CastExpr * expr ) {
47 auto arg = eval(expr->arg);
48 valid = arg.second;
49 value = arg.first;
50 // TODO: perform type conversion on value if valid
51 }
52
53 void postvisit( const VariableExpr * const expr ) {
54 if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) {
55 if ( EnumDecl * decl = inst->baseEnum ) {
56 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
57 return;
58 }
59 }
60 }
61 valid = false;
62 }
63
64 void postvisit( const ApplicationExpr * expr ) {
65 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr));
66 if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; }
67 const std::string & fname = function->name;
68 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
69 std::pair<long long int, bool> arg1, arg2;
70 arg1 = eval(expr->args.front());
71 valid = valid && arg1.second;
72 if ( ! valid ) return;
73 if ( expr->args.size() == 2 ) {
74 arg2 = eval(expr->args.back());
75 valid = valid && arg2.second;
76 if ( ! valid ) return;
77 }
78 if (fname == "?+?") {
79 value = arg1.first + arg2.first;
80 } else if (fname == "?-?") {
81 value = arg1.first - arg2.first;
82 } else if (fname == "?*?") {
83 value = arg1.first * arg2.first;
84 } else if (fname == "?/?") {
85 value = arg1.first / arg2.first;
86 } else if (fname == "?%?") {
87 value = arg1.first % arg2.first;
88 } else {
89 valid = false;
90 }
91 // TODO: implement other intrinsic functions
92 }
93};
94
95//-------------------------------------------------------------
96// New AST
97struct EvalNew : public ast::WithShortCircuiting {
98 long long int value = 0; // compose the result of the constant expression
99 bool valid = true; // true => constant expression and value is the result
100 // false => not constant expression, e.g., ++i
101 bool cfavalid = true; // true => constant expression and value computable
102 // false => constant expression but value not computable, e.g., sizeof(int)
103
104 void previsit( const ast::Node * ) { visit_children = false; }
105 void postvisit( const ast::Node * ) { cfavalid = valid = false; }
106
107 void postvisit( const ast::UntypedExpr * ) {
108 assertf( false, "UntypedExpr in constant expression evaluation" ); // FIX ME, resolve variable
109 }
110
111 void postvisit( const ast::ConstantExpr * expr ) { // only handle int constants
112 value = expr->intValue();
113 }
114
115 void postvisit( const ast::SizeofExpr * ) {
116 // do not change valid or value => let C figure it out
117 cfavalid = false;
118 }
119
120 void postvisit( const ast::AlignofExpr * ) {
121 // do not change valid or value => let C figure it out
122 cfavalid = false;
123 }
124
125 void postvisit( const ast::OffsetofExpr * ) {
126 // do not change valid or value => let C figure it out
127 cfavalid = false;
128 }
129
130 void postvisit( const ast::LogicalExpr * expr ) {
131 std::pair<long long int, bool> arg1, arg2;
132 arg1 = eval( expr->arg1 );
133 valid &= arg1.second;
134 if ( ! valid ) return;
135 arg2 = eval( expr->arg2 );
136 valid &= arg2.second;
137 if ( ! valid ) return;
138
139 if ( expr->isAnd ) {
140 value = arg1.first && arg2.first;
141 } else {
142 value = arg1.first || arg2.first;
143 } // if
144 }
145
146 void postvisit( const ast::ConditionalExpr * expr ) {
147 std::pair<long long int, bool> arg1, arg2, arg3;
148 arg1 = eval( expr->arg1 );
149 valid &= arg1.second;
150 if ( ! valid ) return;
151 arg2 = eval( expr->arg2 );
152 valid &= arg2.second;
153 if ( ! valid ) return;
154 arg3 = eval( expr->arg3 );
155 valid &= arg3.second;
156 if ( ! valid ) return;
157
158 value = arg1.first ? arg2.first : arg3.first;
159 }
160
161 void postvisit( const ast::CastExpr * expr ) {
162 // cfa-cc generates a cast before every constant and many other places, e.g., (int)3, so the cast argument must
163 // be evaluated to get the constant value.
164 auto arg = eval(expr->arg);
165 valid = arg.second;
166 value = arg.first;
167 cfavalid = false;
168 }
169
170 void postvisit( const ast::VariableExpr * expr ) {
171 if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) {
172 if ( const ast::EnumDecl * decl = inst->base ) {
173 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
174 return;
175 }
176 }
177 }
178 valid = false;
179 }
180
181 void postvisit( const ast::ApplicationExpr * expr ) {
182 const ast::DeclWithType * function = ast::getFunction(expr);
183 if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { valid = false; return; }
184 const std::string & fname = function->name;
185 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
186
187 if ( expr->args.size() == 1 ) {
188 // pre/postfix operators ++ and -- => assignment, which is not constant
189 std::pair<long long int, bool> arg1;
190 arg1 = eval(expr->args.front());
191 valid &= arg1.second;
192 if ( ! valid ) return;
193
194 if (fname == "+?") {
195 value = arg1.first;
196 } else if (fname == "-?") {
197 value = -arg1.first;
198 } else if (fname == "~?") {
199 value = ~arg1.first;
200 } else if (fname == "!?") {
201 value = ! arg1.first;
202 } else {
203 valid = false;
204 } // if
205 } else { // => expr->args.size() == 2
206 // infix assignment operators => assignment, which is not constant
207 std::pair<long long int, bool> arg1, arg2;
208 arg1 = eval(expr->args.front());
209 valid &= arg1.second;
210 if ( ! valid ) return;
211 arg2 = eval(expr->args.back());
212 valid &= arg2.second;
213 if ( ! valid ) return;
214
215 if (fname == "?+?") {
216 value = arg1.first + arg2.first;
217 } else if (fname == "?-?") {
218 value = arg1.first - arg2.first;
219 } else if (fname == "?*?") {
220 value = arg1.first * arg2.first;
221 } else if (fname == "?/?") {
222 if ( arg2.first ) value = arg1.first / arg2.first;
223 } else if (fname == "?%?") {
224 if ( arg2.first ) value = arg1.first % arg2.first;
225 } else if (fname == "?<<?") {
226 value = arg1.first << arg2.first;
227 } else if (fname == "?>>?") {
228 value = arg1.first >> arg2.first;
229 } else if (fname == "?<?") {
230 value = arg1.first < arg2.first;
231 } else if (fname == "?>?") {
232 value = arg1.first > arg2.first;
233 } else if (fname == "?<=?") {
234 value = arg1.first <= arg2.first;
235 } else if (fname == "?>=?") {
236 value = arg1.first >= arg2.first;
237 } else if (fname == "?==?") {
238 value = arg1.first == arg2.first;
239 } else if (fname == "?!=?") {
240 value = arg1.first != arg2.first;
241 } else if (fname == "?&?") {
242 value = arg1.first & arg2.first;
243 } else if (fname == "?^?") {
244 value = arg1.first ^ arg2.first;
245 } else if (fname == "?|?") {
246 value = arg1.first | arg2.first;
247 } else {
248 valid = false;
249 }
250 } // if
251 // TODO: implement other intrinsic functions
252 }
253};
254
255std::pair<long long int, bool> eval( const Expression * expr ) {
256 PassVisitor<EvalOld> ev;
257 if ( expr ) {
258 expr->accept( ev );
259 return std::make_pair( ev.pass.value, ev.pass.valid );
260 } else {
261 return std::make_pair( 0, false );
262 }
263}
264
265std::pair<long long int, bool> eval( const ast::Expr * expr ) {
266 ast::Pass<EvalNew> ev;
267 if ( expr ) {
268 expr->accept( ev );
269 return std::make_pair( ev.core.value, ev.core.valid );
270 } else {
271 return std::make_pair( 0, false );
272 }
273}
274
275// Local Variables: //
276// tab-width: 4 //
277// mode: c++ //
278// compile-command: "make install" //
279// End: //
Note: See TracBrowser for help on using the repository browser.