Changes in src/Common/Eval.cc [8f557161:8f06277]
- File:
-
- 1 edited
-
src/Common/Eval.cc (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/Common/Eval.cc
r8f557161 r8f06277 96 96 // New AST 97 97 struct EvalNew : public ast::WithShortCircuiting { 98 Evaluation result = { 0, true, true }; 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) 99 103 100 104 void previsit( const ast::Node * ) { visit_children = false; } 101 void postvisit( const ast::Node * ) { result.isEvaluableInGCC = result.hasKnownValue= false; }105 void postvisit( const ast::Node * ) { cfavalid = valid = false; } 102 106 103 107 void postvisit( const ast::UntypedExpr * ) { … … 106 110 107 111 void postvisit( const ast::ConstantExpr * expr ) { // only handle int constants 108 result.knownValue = expr->intValue(); 109 result.hasKnownValue = true; 110 result.isEvaluableInGCC = true; 112 value = expr->intValue(); 111 113 } 112 114 113 115 void postvisit( const ast::SizeofExpr * ) { 114 result.hasKnownValue = false;115 result.isEvaluableInGCC = true;116 // do not change valid or value => let C figure it out 117 cfavalid = false; 116 118 } 117 119 118 120 void postvisit( const ast::AlignofExpr * ) { 119 result.hasKnownValue = false;120 result.isEvaluableInGCC = true;121 // do not change valid or value => let C figure it out 122 cfavalid = false; 121 123 } 122 124 123 125 void postvisit( const ast::OffsetofExpr * ) { 124 result.hasKnownValue = false;125 result.isEvaluableInGCC = true;126 // do not change valid or value => let C figure it out 127 cfavalid = false; 126 128 } 127 129 128 130 void postvisit( const ast::LogicalExpr * expr ) { 129 Evaluationarg1, arg2;131 std::pair<long long int, bool> arg1, arg2; 130 132 arg1 = eval( expr->arg1 ); 131 result.isEvaluableInGCC &= arg1.isEvaluableInGCC;132 if ( ! result.isEvaluableInGCC) return;133 valid &= arg1.second; 134 if ( ! valid ) return; 133 135 arg2 = eval( expr->arg2 ); 134 result.isEvaluableInGCC &= arg2.isEvaluableInGCC; 135 if ( ! result.isEvaluableInGCC ) return; 136 137 result.hasKnownValue &= arg1.hasKnownValue; 138 result.hasKnownValue &= arg2.hasKnownValue; 139 if ( ! result.hasKnownValue ) return; 136 valid &= arg2.second; 137 if ( ! valid ) return; 140 138 141 139 if ( expr->isAnd ) { 142 result.knownValue = arg1.knownValue && arg2.knownValue;140 value = arg1.first && arg2.first; 143 141 } else { 144 result.knownValue = arg1.knownValue || arg2.knownValue;142 value = arg1.first || arg2.first; 145 143 } // if 146 144 } 147 145 148 146 void postvisit( const ast::ConditionalExpr * expr ) { 149 Evaluationarg1, arg2, arg3;147 std::pair<long long int, bool> arg1, arg2, arg3; 150 148 arg1 = eval( expr->arg1 ); 151 result.isEvaluableInGCC &= arg1.isEvaluableInGCC;152 if ( ! result.isEvaluableInGCC) return;149 valid &= arg1.second; 150 if ( ! valid ) return; 153 151 arg2 = eval( expr->arg2 ); 154 result.isEvaluableInGCC &= arg2.isEvaluableInGCC;155 if ( ! result.isEvaluableInGCC) return;152 valid &= arg2.second; 153 if ( ! valid ) return; 156 154 arg3 = eval( expr->arg3 ); 157 result.isEvaluableInGCC &= arg3.isEvaluableInGCC; 158 if ( ! result.isEvaluableInGCC ) return; 159 160 result.hasKnownValue &= arg1.hasKnownValue; 161 result.hasKnownValue &= arg2.hasKnownValue; 162 result.hasKnownValue &= arg3.hasKnownValue; 163 if ( ! result.hasKnownValue ) return; 164 165 result.knownValue = arg1.knownValue ? arg2.knownValue : arg3.knownValue; 155 valid &= arg3.second; 156 if ( ! valid ) return; 157 158 value = arg1.first ? arg2.first : arg3.first; 166 159 } 167 160 168 161 void postvisit( const ast::CastExpr * expr ) { 169 // cfa-cc generates a cast before every constant and many other places, e.g., (int)3, 170 // so we must use the value from the cast argument, even though we lack any basis for evaluating wraparound effects, etc 171 result = eval(expr->arg); 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; 172 168 } 173 169 174 170 void postvisit( const ast::VariableExpr * expr ) { 175 result.hasKnownValue = false;176 result.isEvaluableInGCC = false;177 171 if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) { 178 172 if ( const ast::EnumDecl * decl = inst->base ) { 179 result.isEvaluableInGCC = true; 180 result.hasKnownValue = decl->valueOf( expr->var, result.knownValue ); // result.knownValue filled by valueOf 173 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf 174 return; 175 } 181 176 } 182 177 } 178 valid = false; 183 179 } 184 180 185 181 void postvisit( const ast::ApplicationExpr * expr ) { 186 182 const ast::DeclWithType * function = ast::getFunction(expr); 187 if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { 188 result.isEvaluableInGCC = false; 189 result.hasKnownValue = false; 190 return; 191 } 183 if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { valid = false; return; } 192 184 const std::string & fname = function->name; 193 185 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() ); … … 195 187 if ( expr->args.size() == 1 ) { 196 188 // pre/postfix operators ++ and -- => assignment, which is not constant 197 Evaluationarg1;189 std::pair<long long int, bool> arg1; 198 190 arg1 = eval(expr->args.front()); 199 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 200 if ( ! result.isEvaluableInGCC ) return; 201 202 result.hasKnownValue &= arg1.hasKnownValue; 203 if ( ! result.hasKnownValue ) return; 191 valid &= arg1.second; 192 if ( ! valid ) return; 204 193 205 194 if (fname == "+?") { 206 result.knownValue = arg1.knownValue;195 value = arg1.first; 207 196 } else if (fname == "-?") { 208 result.knownValue = -arg1.knownValue;197 value = -arg1.first; 209 198 } else if (fname == "~?") { 210 result.knownValue = ~arg1.knownValue;199 value = ~arg1.first; 211 200 } else if (fname == "!?") { 212 result.knownValue = ! arg1.knownValue;201 value = ! arg1.first; 213 202 } else { 214 result.isEvaluableInGCC = false; 215 result.hasKnownValue = false; 203 valid = false; 216 204 } // if 217 205 } else { // => expr->args.size() == 2 218 206 // infix assignment operators => assignment, which is not constant 219 Evaluationarg1, arg2;207 std::pair<long long int, bool> arg1, arg2; 220 208 arg1 = eval(expr->args.front()); 221 result.isEvaluableInGCC &= arg1.isEvaluableInGCC;222 if ( ! result.isEvaluableInGCC) return;209 valid &= arg1.second; 210 if ( ! valid ) return; 223 211 arg2 = eval(expr->args.back()); 224 result.isEvaluableInGCC &= arg2.isEvaluableInGCC; 225 if ( ! result.isEvaluableInGCC ) return; 226 227 result.hasKnownValue &= arg1.hasKnownValue; 228 result.hasKnownValue &= arg2.hasKnownValue; 229 if ( ! result.hasKnownValue ) return; 212 valid &= arg2.second; 213 if ( ! valid ) return; 230 214 231 215 if (fname == "?+?") { 232 result.knownValue = arg1.knownValue + arg2.knownValue;216 value = arg1.first + arg2.first; 233 217 } else if (fname == "?-?") { 234 result.knownValue = arg1.knownValue - arg2.knownValue;218 value = arg1.first - arg2.first; 235 219 } else if (fname == "?*?") { 236 result.knownValue = arg1.knownValue * arg2.knownValue;220 value = arg1.first * arg2.first; 237 221 } else if (fname == "?/?") { 238 if ( arg2. knownValue ) result.knownValue = arg1.knownValue / arg2.knownValue;222 if ( arg2.first ) value = arg1.first / arg2.first; 239 223 } else if (fname == "?%?") { 240 if ( arg2. knownValue ) result.knownValue = arg1.knownValue % arg2.knownValue;224 if ( arg2.first ) value = arg1.first % arg2.first; 241 225 } else if (fname == "?<<?") { 242 result.knownValue = arg1.knownValue << arg2.knownValue;226 value = arg1.first << arg2.first; 243 227 } else if (fname == "?>>?") { 244 result.knownValue = arg1.knownValue >> arg2.knownValue;228 value = arg1.first >> arg2.first; 245 229 } else if (fname == "?<?") { 246 result.knownValue = arg1.knownValue < arg2.knownValue;230 value = arg1.first < arg2.first; 247 231 } else if (fname == "?>?") { 248 result.knownValue = arg1.knownValue > arg2.knownValue;232 value = arg1.first > arg2.first; 249 233 } else if (fname == "?<=?") { 250 result.knownValue = arg1.knownValue <= arg2.knownValue;234 value = arg1.first <= arg2.first; 251 235 } else if (fname == "?>=?") { 252 result.knownValue = arg1.knownValue >= arg2.knownValue;236 value = arg1.first >= arg2.first; 253 237 } else if (fname == "?==?") { 254 result.knownValue = arg1.knownValue == arg2.knownValue;238 value = arg1.first == arg2.first; 255 239 } else if (fname == "?!=?") { 256 result.knownValue = arg1.knownValue != arg2.knownValue;240 value = arg1.first != arg2.first; 257 241 } else if (fname == "?&?") { 258 result.knownValue = arg1.knownValue & arg2.knownValue;242 value = arg1.first & arg2.first; 259 243 } else if (fname == "?^?") { 260 result.knownValue = arg1.knownValue ^ arg2.knownValue;244 value = arg1.first ^ arg2.first; 261 245 } else if (fname == "?|?") { 262 result.knownValue = arg1.knownValue | arg2.knownValue;246 value = arg1.first | arg2.first; 263 247 } else { 264 result.isEvaluableInGCC = false; 265 result.hasKnownValue = false; 248 valid = false; 266 249 } 267 250 } // if … … 280 263 } 281 264 282 Evaluation eval( const ast::Expr * expr ) { 265 std::pair<long long int, bool> eval( const ast::Expr * expr ) { 266 ast::Pass<EvalNew> ev; 283 267 if ( expr ) { 284 285 return ast::Pass<EvalNew>::read(expr); 286 // Evaluation ret = ast::Pass<EvalNew>::read(expr); 287 // ret.knownValue = 777; 288 // return ret; 289 268 expr->accept( ev ); 269 return std::make_pair( ev.core.value, ev.core.valid ); 290 270 } else { 291 return { 0, false, false };271 return std::make_pair( 0, false ); 292 272 } 293 273 }
Note:
See TracChangeset
for help on using the changeset viewer.