source: src/Common/Eval.cc @ a5294af

ast-experimental
Last change on this file since a5294af was 8f06277, checked in by Andrew Beach <ajbeach@…>, 21 months 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.