source: src/Common/Eval.cc@ 30159e5

ADT ast-experimental pthread-emulation
Last change on this file since 30159e5 was 120867e, checked in by Peter A. Buhr <pabuhr@…>, 3 years ago

update EvalNew to handle more compile-time constant-expression evaluation

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