Changeset 120867e for src


Ignore:
Timestamp:
Jul 1, 2022, 5:31:57 PM (21 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, ast-experimental, master, pthread-emulation, qualifiedEnum
Children:
7991c7d
Parents:
1ed3fe7c
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Common/Eval.cc

    r1ed3fe7c r120867e  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jul 24 15:09:06 2019
    13 // Update Count     : 64
     12// Last Modified On : Fri Jul  1 08:41:03 2022
     13// Update Count     : 117
    1414//
    1515
     
    1717
    1818#include "Common/PassVisitor.h"
     19#include "CodeGen/OperatorTable.h"                                              // access: OperatorInfo
    1920#include "AST/Pass.hpp"
    2021#include "InitTweak/InitTweak.h"
     
    2425// Old AST
    2526struct EvalOld : public WithShortCircuiting {
    26         long long int value = 0;
    27         bool valid = true;
     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)
    2832
    2933        void previsit( const BaseSyntaxNode * ) { visit_children = false; }
     
    8993// New AST
    9094struct EvalNew : public ast::WithShortCircuiting {
    91         long long int value = 0;
    92         bool valid = true;
     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)
    93100
    94101        void previsit( const ast::Node * ) { visit_children = false; }
    95         void postvisit( const ast::Node * ) { valid = false; }
    96 
    97         void postvisit( const ast::ConstantExpr * expr ) {
     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
    98109                value = expr->intValue();
    99110        }
    100111
    101         void postvisit( const ast::SizeofExpr * expr ) {
    102                 if ( expr->expr ) value = eval(expr->expr).first;
    103                 else if ( expr->type ) value = eval(expr->expr).first;
    104                 else SemanticError( expr->location, ::toString( "Internal error: SizeofExpr has no expression or type value" ) );
    105         }
    106 
    107         void postvisit( const ast::CastExpr * expr ) {
     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.
    108161                auto arg = eval(expr->arg);
    109162                valid = arg.second;
    110163                value = arg.first;
    111                 // TODO: perform type conversion on value if valid
    112         }
    113 
    114         void postvisit( const ast::VariableExpr * expr ) { // No hit
     164                cfavalid = false;
     165        }
     166
     167        void postvisit( const ast::VariableExpr * expr ) {
    115168                if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) {
    116169                        if ( const ast::EnumDecl * decl = inst->base ) {
     
    128181                const std::string & fname = function->name;
    129182                assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
    130                 std::pair<long long int, bool> arg1, arg2;
    131                 arg1 = eval(expr->args.front());
    132                 valid = valid && arg1.second;
    133                 if ( ! valid ) return;
    134                 if ( expr->args.size() == 2 ) {
     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;
    135208                        arg2 = eval(expr->args.back());
    136                         valid = valid && arg2.second;
    137                         if ( ! valid ) return;
    138                 }
    139                 if (fname == "?+?") {
    140                         value = arg1.first + arg2.first;
    141                 } else if (fname == "?-?") {
    142                         value = arg1.first - arg2.first;
    143                 } else if (fname == "?*?") {
    144                         value = arg1.first * arg2.first;
    145                 } else if (fname == "?/?") {
    146                         value = arg1.first / arg2.first;
    147                 } else if (fname == "?%?") {
    148                         value = arg1.first % arg2.first;
    149                 } else {
    150                         valid = false;
    151                 }
     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
    152248                // TODO: implement other intrinsic functions
    153249        }
    154250};
    155251
    156 std::pair<long long int, bool> eval( const Expression * expr) {
     252std::pair<long long int, bool> eval( const Expression * expr ) {
    157253        PassVisitor<EvalOld> ev;
    158         if (expr) {
    159                 expr->accept(ev);
    160                 return std::make_pair(ev.pass.value, ev.pass.valid);
     254        if ( expr ) {
     255                expr->accept( ev );
     256                return std::make_pair( ev.pass.value, ev.pass.valid );
    161257        } else {
    162                 return std::make_pair(0, false);
     258                return std::make_pair( 0, false );
    163259        }
    164260}
    165261
    166 std::pair<long long int, bool> eval(const ast::Expr * expr) {
     262std::pair<long long int, bool> eval( const ast::Expr * expr ) {
    167263        ast::Pass<EvalNew> ev;
    168         if (expr) {
    169                 expr->accept(ev);
    170                 return std::make_pair(ev.core.value, ev.core.valid);
     264        if ( expr ) {
     265                expr->accept( ev );
     266                return std::make_pair( ev.core.value, ev.core.valid );
    171267        } else {
    172                 return std::make_pair(0, false);
     268                return std::make_pair( 0, false );
    173269        }
    174270}
Note: See TracChangeset for help on using the changeset viewer.