source: src/Common/Eval.cc @ f403c46

ADTast-experimentalpthread-emulation
Last change on this file since f403c46 was ba48a9b, checked in by Peter A. Buhr <pabuhr@…>, 2 years ago

ignore zero divide when evaluating constexpr expressions

  • 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 : Sat Aug  6 12:11:59 2022
13// Update Count     : 119
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                                if ( arg2.first ) value = arg1.first / arg2.first;
220                        } else if (fname == "?%?") {
221                                if ( arg2.first ) 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.