source: src/Common/Eval.cc@ 70056ed

ADT ast-experimental
Last change on this file since 70056ed 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
RevLine 
[5cbacf1]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//
[8f06277]7// Eval.cc -- Evaluate parts of the ast at compile time.
[5cbacf1]8//
9// Author : Richard C. Bilson
10// Created On : Mon May 18 07:44:20 2015
11// Last Modified By : Peter A. Buhr
[ba48a9b]12// Last Modified On : Sat Aug 6 12:11:59 2022
13// Update Count : 119
[5cbacf1]14//
15
[8f06277]16#include "Eval.h"
17
[5cbacf1]18#include <utility> // for pair
19
[e01eb4a]20#include "AST/Inspect.hpp"
[5cbacf1]21#include "Common/PassVisitor.h"
[120867e]22#include "CodeGen/OperatorTable.h" // access: OperatorInfo
[d7aa12c]23#include "AST/Pass.hpp"
[5cbacf1]24#include "InitTweak/InitTweak.h"
25#include "SynTree/Expression.h"
26
[d7aa12c]27//-------------------------------------------------------------
28// Old AST
29struct EvalOld : public WithShortCircuiting {
[120867e]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)
[5cbacf1]35
[77d2432]36 void previsit( const BaseSyntaxNode * ) { visit_children = false; }
37 void postvisit( const BaseSyntaxNode * ) { valid = false; }
[5cbacf1]38
[77d2432]39 void postvisit( const SizeofExpr * ) {
40 }
41
42 void postvisit( const ConstantExpr * expr ) {
[5cbacf1]43 value = expr->intValue();
44 }
45
[77d2432]46 void postvisit( const CastExpr * expr ) {
[5cbacf1]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
[77d2432]53 void postvisit( const VariableExpr * const expr ) {
[5cbacf1]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
[77d2432]64 void postvisit( const ApplicationExpr * expr ) {
65 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr));
[5cbacf1]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
[d7aa12c]95//-------------------------------------------------------------
96// New AST
97struct EvalNew : public ast::WithShortCircuiting {
[120867e]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)
[d7aa12c]103
104 void previsit( const ast::Node * ) { visit_children = false; }
[120867e]105 void postvisit( const ast::Node * ) { cfavalid = valid = false; }
[d7aa12c]106
[120867e]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
[d7aa12c]112 value = expr->intValue();
113 }
114
[120867e]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;
[77d2432]128 }
129
[120867e]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.
[d7aa12c]164 auto arg = eval(expr->arg);
165 valid = arg.second;
166 value = arg.first;
[120867e]167 cfavalid = false;
[d7aa12c]168 }
169
[120867e]170 void postvisit( const ast::VariableExpr * expr ) {
[d7aa12c]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 ) {
[e01eb4a]182 const ast::DeclWithType * function = ast::getFunction(expr);
[d7aa12c]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() );
[120867e]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;
[d7aa12c]211 arg2 = eval(expr->args.back());
[120867e]212 valid &= arg2.second;
[d7aa12c]213 if ( ! valid ) return;
[120867e]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 == "?/?") {
[ba48a9b]222 if ( arg2.first ) value = arg1.first / arg2.first;
[120867e]223 } else if (fname == "?%?") {
[ba48a9b]224 if ( arg2.first ) value = arg1.first % arg2.first;
[120867e]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
[d7aa12c]251 // TODO: implement other intrinsic functions
252 }
253};
254
[120867e]255std::pair<long long int, bool> eval( const Expression * expr ) {
[d7aa12c]256 PassVisitor<EvalOld> ev;
[120867e]257 if ( expr ) {
258 expr->accept( ev );
259 return std::make_pair( ev.pass.value, ev.pass.valid );
[5cbacf1]260 } else {
[120867e]261 return std::make_pair( 0, false );
[5cbacf1]262 }
263}
264
[120867e]265std::pair<long long int, bool> eval( const ast::Expr * expr ) {
[d7aa12c]266 ast::Pass<EvalNew> ev;
[120867e]267 if ( expr ) {
268 expr->accept( ev );
269 return std::make_pair( ev.core.value, ev.core.valid );
[d7aa12c]270 } else {
[120867e]271 return std::make_pair( 0, false );
[d7aa12c]272 }
[0588d8c]273}
274
[5cbacf1]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.