blob: 3be2f94f23f7549a4cdc4693cb22d9cc9e9ffb16 [file] [log] [blame]
Anders Carlssonc44eec62008-07-03 04:20:39 +00001//===--- Expr.cpp - Expression Constant Evaluator -------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Expr constant evaluator.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/APValue.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/Expr.h"
Seo Sanghyeon0fe52e12008-07-08 07:23:12 +000017#include "clang/AST/StmtVisitor.h"
Anders Carlsson06a36752008-07-08 05:49:43 +000018#include "clang/Basic/TargetInfo.h"
Anders Carlssonc754aa62008-07-08 05:13:58 +000019#include "llvm/Support/Compiler.h"
Anders Carlssonc44eec62008-07-03 04:20:39 +000020
21using namespace clang;
22
Anders Carlssonc754aa62008-07-08 05:13:58 +000023#define USE_NEW_EVALUATOR 0
Anders Carlssonc44eec62008-07-03 04:20:39 +000024
25static bool CalcFakeICEVal(const Expr* Expr,
26 llvm::APSInt& Result,
27 ASTContext& Context) {
28 // Calculate the value of an expression that has a calculatable
29 // value, but isn't an ICE. Currently, this only supports
30 // a very narrow set of extensions, but it can be expanded if needed.
31 if (const ParenExpr *PE = dyn_cast<ParenExpr>(Expr))
32 return CalcFakeICEVal(PE->getSubExpr(), Result, Context);
33
34 if (const CastExpr *CE = dyn_cast<CastExpr>(Expr)) {
35 QualType CETy = CE->getType();
36 if ((CETy->isIntegralType() && !CETy->isBooleanType()) ||
37 CETy->isPointerType()) {
38 if (CalcFakeICEVal(CE->getSubExpr(), Result, Context)) {
39 Result.extOrTrunc(Context.getTypeSize(CETy));
40 // FIXME: This assumes pointers are signed.
41 Result.setIsSigned(CETy->isSignedIntegerType() ||
42 CETy->isPointerType());
43 return true;
44 }
45 }
46 }
47
48 if (Expr->getType()->isIntegralType())
49 return Expr->isIntegerConstantExpr(Result, Context);
50
51 return false;
52}
53
Anders Carlssonc754aa62008-07-08 05:13:58 +000054namespace {
55class VISIBILITY_HIDDEN IntExprEvaluator
56 : public StmtVisitor<IntExprEvaluator, APValue> {
57 ASTContext &Ctx;
58
59 IntExprEvaluator(ASTContext &ctx)
60 : Ctx(ctx) {}
61
62public:
Anders Carlsson06a36752008-07-08 05:49:43 +000063 static bool Evaluate(const Expr* E, llvm::APSInt& Result, ASTContext &Ctx) {
64 APValue Value = IntExprEvaluator(Ctx).Visit(const_cast<Expr*>(E));
65 if (!Value.isSInt())
66 return false;
67
68 Result = Value.getSInt();
69 return true;
Anders Carlssonc754aa62008-07-08 05:13:58 +000070 }
71
72 //===--------------------------------------------------------------------===//
73 // Visitor Methods
74 //===--------------------------------------------------------------------===//
75 APValue VisitStmt(Stmt *S) {
76 // FIXME: Remove this when we support more expressions.
77 printf("Unhandled statement\n");
78 S->dump();
79 return APValue();
80 }
81
Anders Carlsson06a36752008-07-08 05:49:43 +000082 APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
Anders Carlssonc754aa62008-07-08 05:13:58 +000083
Anders Carlsson06a36752008-07-08 05:49:43 +000084 APValue VisitBinaryOperator(const BinaryOperator *E) {
85 // The LHS of a constant expr is always evaluated and needed.
86 llvm::APSInt Result(32);
87 if (!Evaluate(E->getRHS(), Result, Ctx))
88 return APValue();
89
90 llvm::APSInt RHS(32);
91 if (!Evaluate(E->getRHS(), RHS, Ctx))
92 return APValue();
93
94 switch (E->getOpcode()) {
95 default:
96 return APValue();
97 case BinaryOperator::Mul:
98 Result *= RHS;
99 break;
100 case BinaryOperator::Div:
101 if (RHS == 0)
102 return APValue();
103 Result /= RHS;
104 break;
105 case BinaryOperator::Rem:
106 if (RHS == 0)
107 return APValue();
108 Result %= RHS;
109 break;
110 case BinaryOperator::Add: Result += RHS; break;
111 case BinaryOperator::Sub: Result -= RHS; break;
112 case BinaryOperator::Shl:
113 Result <<=
114 static_cast<uint32_t>(RHS.getLimitedValue(Result.getBitWidth()-1));
115 break;
116 case BinaryOperator::Shr:
117 Result >>=
118 static_cast<uint32_t>(RHS.getLimitedValue(Result.getBitWidth()-1));
119 break;
120 case BinaryOperator::LT: Result = Result < RHS; break;
121 case BinaryOperator::GT: Result = Result > RHS; break;
122 case BinaryOperator::LE: Result = Result <= RHS; break;
123 case BinaryOperator::GE: Result = Result >= RHS; break;
124 case BinaryOperator::EQ: Result = Result == RHS; break;
125 case BinaryOperator::NE: Result = Result != RHS; break;
126 case BinaryOperator::And: Result &= RHS; break;
127 case BinaryOperator::Xor: Result ^= RHS; break;
128 case BinaryOperator::Or: Result |= RHS; break;
129
130 case BinaryOperator::Comma:
131 // C99 6.6p3: "shall not contain assignment, ..., or comma operators,
132 // *except* when they are contained within a subexpression that is not
133 // evaluated". Note that Assignment can never happen due to constraints
134 // on the LHS subexpr, so we don't need to check it here.
135 // FIXME: Need to come up with an efficient way to deal with the C99
136 // rules on evaluation while still evaluating this. Maybe a
137 // "evaluated comma" out parameter?
138 return APValue();
139 }
140
141 Result.setIsUnsigned(E->getType()->isUnsignedIntegerType());
142
143 return APValue(Result);
144 }
145
146 APValue VisitUnaryOperator(const UnaryOperator *E) {
147 llvm::APSInt Result(32);
148
149 if (E->isOffsetOfOp())
150 Result = E->evaluateOffsetOf(Ctx);
151 else if (E->isSizeOfAlignOfOp()) {
152 // Return the result in the right width.
153 Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(E->getType())));
154
155 // sizeof(void) and __alignof__(void) = 1 as a gcc extension.
156 if (E->getSubExpr()->getType()->isVoidType())
157 Result = 1;
158
159 // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
160 if (!E->getSubExpr()->getType()->isConstantSizeType()) {
161 // FIXME: Should we attempt to evaluate this?
162 return APValue();
163 }
164
165 // Get information about the size or align.
166 if (E->getSubExpr()->getType()->isFunctionType()) {
167 // GCC extension: sizeof(function) = 1.
168 // FIXME: AlignOf shouldn't be unconditionally 4!
169 Result = E->getOpcode() == UnaryOperator::AlignOf ? 4 : 1;
170 } else {
171 unsigned CharSize = Ctx.Target.getCharWidth();
172 if (E->getOpcode() == UnaryOperator::AlignOf)
173 Result = Ctx.getTypeAlign(E->getSubExpr()->getType()) / CharSize;
174 else
175 Result = Ctx.getTypeSize(E->getSubExpr()->getType()) / CharSize;
176 }
177 } else {
178 // Get the operand value. If this is sizeof/alignof, do not evalute the
179 // operand. This affects C99 6.6p3.
180 if (!Evaluate(E->getSubExpr(), Result, Ctx))
181 return APValue();
182
183 switch (E->getOpcode()) {
184 // Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
185 // See C99 6.6p3.
186 default:
187 return APValue();
188 case UnaryOperator::Extension:
189 assert(0 && "Handle UnaryOperator::Extension");
190 return APValue();
191 case UnaryOperator::LNot: {
192 bool Val = Result == 0;
193 uint32_t typeSize = Ctx.getTypeSize(E->getType());
194 Result.zextOrTrunc(typeSize);
195 Result = Val;
196 break;
197 }
198 case UnaryOperator::Plus:
199 break;
200 case UnaryOperator::Minus:
201 Result = -Result;
202 break;
203 case UnaryOperator::Not:
204 Result = ~Result;
205 break;
206 }
207 }
208
209 Result.setIsUnsigned(E->getType()->isUnsignedIntegerType());
210 return APValue(Result);
211 }
Anders Carlssonc754aa62008-07-08 05:13:58 +0000212};
213}
214
Anders Carlssonc44eec62008-07-03 04:20:39 +0000215bool Expr::tryEvaluate(APValue& Result, ASTContext &Ctx) const
216{
217 llvm::APSInt sInt(1);
218
Anders Carlssonc754aa62008-07-08 05:13:58 +0000219#if USE_NEW_EVALUATOR
Anders Carlsson06a36752008-07-08 05:49:43 +0000220 if (getType()->isIntegerType()) {
221 if (IntExprEvaluator::Evaluate(this, sInt, Ctx)) {
222 Result = APValue(sInt);
223 return true;
224 }
225 } else
Anders Carlssonc754aa62008-07-08 05:13:58 +0000226 return false;
227
228#else
Anders Carlssonc44eec62008-07-03 04:20:39 +0000229 if (CalcFakeICEVal(this, sInt, Ctx)) {
230 Result = APValue(sInt);
231 return true;
232 }
Anders Carlssonc754aa62008-07-08 05:13:58 +0000233#endif
Anders Carlssonc44eec62008-07-03 04:20:39 +0000234
235 return false;
236}