source: src/Common/Eval.cc@ 79a6b17

ADT ast-experimental
Last change on this file since 79a6b17 was e01eb4a, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Moved some functions from InitTweak to Inspect.

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