1 /*
2   Copyright (c) 2010-2021, Intel Corporation
3   All rights reserved.
4 
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are
7   met:
8 
9     * Redistributions of source code must retain the above copyright
10       notice, this list of conditions and the following disclaimer.
11 
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15 
16     * Neither the name of Intel Corporation nor the names of its
17       contributors may be used to endorse or promote products derived from
18       this software without specific prior written permission.
19 
20 
21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 /** @file expr.h
35     @brief Expr abstract base class and expression implementations
36 */
37 
38 #pragma once
39 
40 #include "ast.h"
41 #include "ispc.h"
42 #include "type.h"
43 
44 namespace ispc {
45 
46 /** @brief Expr is the abstract base class that defines the interface that
47     all expression types must implement.
48  */
49 class Expr : public ASTNode {
50   public:
Expr(SourcePos p,unsigned scid)51     Expr(SourcePos p, unsigned scid) : ASTNode(p, scid) {}
52 
classof(Expr const *)53     static inline bool classof(Expr const *) { return true; }
classof(ASTNode const * N)54     static inline bool classof(ASTNode const *N) { return N->getValueID() < MaxExprID; }
55 
56     /** This is the main method for Expr implementations to implement.  It
57         should call methods in the FunctionEmitContext to emit LLVM IR
58         instructions to the current basic block in order to generate an
59         llvm::Value that represents the expression's value. */
60     virtual llvm::Value *GetValue(FunctionEmitContext *ctx) const = 0;
61 
62     /** For expressions that can provide an lvalue (e.g. array indexing),
63         this function should emit IR that computes the expression's lvalue
64         and returns the corresponding llvm::Value.  Expressions that can't
65         provide an lvalue should leave this unimplemented; the default
66         implementation returns NULL.  */
67     virtual llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
68 
69     /** Returns the Type of the expression. */
70     virtual const Type *GetType() const = 0;
71 
72     /** Returns the type of the value returned by GetLValueType(); this
73         should be a pointer type of some sort (uniform or varying). */
74     virtual const Type *GetLValueType() const;
75 
76     /** For expressions that have values based on a symbol (e.g. regular
77         symbol references, array indexing, etc.), this returns a pointer to
78         that symbol. */
79     virtual Symbol *GetBaseSymbol() const;
80 
81     /** If this is a constant expression that can be converted to a
82         constant of storage type of the given type, this method should return the
83         corresponding llvm::Constant value and a flag denoting if it's
84         valid for multi-target compilation for use as an initializer of
85         a global variable. Otherwise it should return the llvm::constant
86         value as NULL. */
87     virtual std::pair<llvm::Constant *, bool> GetStorageConstant(const Type *type) const;
88 
89     /** If this is a constant expression that can be converted to a
90         constant of the given type, this method should return the
91         corresponding llvm::Constant value and a flag denoting if it's
92         valid for multi-target compilation for use as an initializer of
93         a global variable. Otherwise it should return the llvm::constant
94         value as NULL. */
95     virtual std::pair<llvm::Constant *, bool> GetConstant(const Type *type) const;
96 
97     /** This method should perform early optimizations of the expression
98         (constant folding, etc.) and return a pointer to the resulting
99         expression.  If an error is encountered during optimization, NULL
100         should be returned. */
101     virtual Expr *Optimize() = 0;
102 
103     /** This method should perform type checking of the expression and
104         return a pointer to the resulting expression.  If an error is
105         encountered, NULL should be returned. */
106     virtual Expr *TypeCheck() = 0;
107 
108     /** Prints the expression to standard output (used for debugging). */
109     virtual void Print() const = 0;
110 
111     virtual bool HasAmbiguousVariability(std::vector<const Expr *> &warn) const;
112 };
113 
114 /** @brief Unary expression */
115 class UnaryExpr : public Expr {
116   public:
117     enum Op {
118         PreInc,     ///< Pre-increment
119         PreDec,     ///< Pre-decrement
120         PostInc,    ///< Post-increment
121         PostDec,    ///< Post-decrement
122         Negate,     ///< Negation
123         LogicalNot, ///< Logical not
124         BitNot,     ///< Bit not
125     };
126 
127     UnaryExpr(Op op, Expr *expr, SourcePos pos);
128 
classof(UnaryExpr const *)129     static inline bool classof(UnaryExpr const *) { return true; }
classof(ASTNode const * N)130     static inline bool classof(ASTNode const *N) { return N->getValueID() == UnaryExprID; }
131 
132     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
133     const Type *GetType() const;
134     void Print() const;
135     Expr *Optimize();
136     Expr *TypeCheck();
137     int EstimateCost() const;
138 
139     const Op op;
140     Expr *expr;
141 };
142 
143 /** @brief Binary expression */
144 class BinaryExpr : public Expr {
145   public:
146     enum Op {
147         Add, ///< Addition
148         Sub, ///< Subtraction
149         Mul, ///< Multiplication
150         Div, ///< Division
151         Mod, ///< Modulus
152         Shl, ///< Shift left
153         Shr, ///< Shift right
154 
155         Lt,       ///< Less than
156         Gt,       ///< Greater than
157         Le,       ///< Less than or equal
158         Ge,       ///< Greater than or equal
159         Equal,    ///< Equal
160         NotEqual, ///< Not equal
161 
162         BitAnd,     ///< Bitwise AND
163         BitXor,     ///< Bitwise XOR
164         BitOr,      ///< Bitwise OR
165         LogicalAnd, ///< Logical AND
166         LogicalOr,  ///< Logical OR
167 
168         Comma, ///< Comma operator
169     };
170 
171     BinaryExpr(Op o, Expr *a, Expr *b, SourcePos p);
172 
classof(BinaryExpr const *)173     static inline bool classof(BinaryExpr const *) { return true; }
classof(ASTNode const * N)174     static inline bool classof(ASTNode const *N) { return N->getValueID() == BinaryExprID; }
175 
176     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
177     const Type *GetType() const;
178     const Type *GetLValueType() const;
179     void Print() const;
180 
181     Expr *Optimize();
182     Expr *TypeCheck();
183     int EstimateCost() const;
184     std::pair<llvm::Constant *, bool> GetStorageConstant(const Type *type) const;
185     std::pair<llvm::Constant *, bool> GetConstant(const Type *type) const;
186     bool HasAmbiguousVariability(std::vector<const Expr *> &warn) const;
187 
188     const Op op;
189     Expr *arg0, *arg1;
190 };
191 
192 /** @brief Assignment expression */
193 class AssignExpr : public Expr {
194   public:
195     enum Op {
196         Assign,    ///< Regular assignment
197         MulAssign, ///< *= assignment
198         DivAssign, ///< /= assignment
199         ModAssign, ///< %= assignment
200         AddAssign, ///< += assignment
201         SubAssign, ///< -= assignment
202         ShlAssign, ///< <<= assignment
203         ShrAssign, ///< >>= assignment
204         AndAssign, ///< &= assignment
205         XorAssign, ///< ^= assignment
206         OrAssign,  ///< |= assignment
207     };
208 
209     AssignExpr(Op o, Expr *a, Expr *b, SourcePos p);
210 
classof(AssignExpr const *)211     static inline bool classof(AssignExpr const *) { return true; }
classof(ASTNode const * N)212     static inline bool classof(ASTNode const *N) { return N->getValueID() == AssignExprID; }
213 
214     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
215     const Type *GetType() const;
216     void Print() const;
217 
218     Expr *Optimize();
219     Expr *TypeCheck();
220     int EstimateCost() const;
221 
222     const Op op;
223     Expr *lvalue, *rvalue;
224 };
225 
226 /** @brief Selection expression, corresponding to "test ? a : b".
227 
228     Returns the value of "a" or "b", depending on the value of "test".
229 */
230 class SelectExpr : public Expr {
231   public:
232     SelectExpr(Expr *test, Expr *a, Expr *b, SourcePos p);
233 
classof(SelectExpr const *)234     static inline bool classof(SelectExpr const *) { return true; }
classof(ASTNode const * N)235     static inline bool classof(ASTNode const *N) { return N->getValueID() == SelectExprID; }
236 
237     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
238     const Type *GetType() const;
239     void Print() const;
240 
241     Expr *Optimize();
242     Expr *TypeCheck();
243     int EstimateCost() const;
244     bool HasAmbiguousVariability(std::vector<const Expr *> &warn) const;
245 
246     Expr *test, *expr1, *expr2;
247 };
248 
249 /** @brief A list of expressions.
250 
251     These are mostly used for representing curly-brace delimited
252     initializers for initializers for complex types and for representing
253     the arguments passed to a function call.
254  */
255 class ExprList : public Expr {
256   public:
ExprList(SourcePos p)257     ExprList(SourcePos p) : Expr(p, ExprListID) {}
ExprList(Expr * e,SourcePos p)258     ExprList(Expr *e, SourcePos p) : Expr(p, ExprListID) { exprs.push_back(e); }
259 
classof(ExprList const *)260     static inline bool classof(ExprList const *) { return true; }
classof(ASTNode const * N)261     static inline bool classof(ASTNode const *N) { return N->getValueID() == ExprListID; }
262 
263     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
264     const Type *GetType() const;
265     void Print() const;
266     std::pair<llvm::Constant *, bool> GetStorageConstant(const Type *type) const;
267     std::pair<llvm::Constant *, bool> GetConstant(const Type *type) const;
268     ExprList *Optimize();
269     ExprList *TypeCheck();
270     int EstimateCost() const;
271     bool HasAmbiguousVariability(std::vector<const Expr *> &warn) const;
272 
273     std::vector<Expr *> exprs;
274 };
275 
276 /** @brief Expression representing a function call.
277  */
278 class FunctionCallExpr : public Expr {
279   public:
280     FunctionCallExpr(Expr *func, ExprList *args, SourcePos p, bool isLaunch = false, Expr *launchCountExpr[3] = NULL);
281 
classof(FunctionCallExpr const *)282     static inline bool classof(FunctionCallExpr const *) { return true; }
classof(ASTNode const * N)283     static inline bool classof(ASTNode const *N) { return N->getValueID() == FunctionCallExprID; }
284 
285     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
286     llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
287     const Type *GetType() const;
288     const Type *GetLValueType() const;
289     void Print() const;
290 
291     Expr *Optimize();
292     Expr *TypeCheck();
293     int EstimateCost() const;
294 
295     Expr *func;
296     ExprList *args;
297     bool isLaunch;
298     Expr *launchCountExpr[3];
299 };
300 
301 /** @brief Expression representing indexing into something with an integer
302     offset.
303 
304     This is used for both array indexing and indexing into VectorTypes.
305 */
306 class IndexExpr : public Expr {
307   public:
308     IndexExpr(Expr *baseExpr, Expr *index, SourcePos p);
309 
classof(IndexExpr const *)310     static inline bool classof(IndexExpr const *) { return true; }
classof(ASTNode const * N)311     static inline bool classof(ASTNode const *N) { return N->getValueID() == IndexExprID; }
312 
313     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
314     llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
315     const Type *GetType() const;
316     const Type *GetLValueType() const;
317     Symbol *GetBaseSymbol() const;
318     void Print() const;
319 
320     Expr *Optimize();
321     Expr *TypeCheck();
322     int EstimateCost() const;
323 
324     Expr *baseExpr, *index;
325 
326   private:
327     mutable const Type *type;
328     mutable const PointerType *lvalueType;
329 };
330 
331 /** @brief Expression representing member selection ("foo.bar").
332  *
333  *  This will also be overloaded to deal with swizzles.
334  */
335 class MemberExpr : public Expr {
336   public:
337     static MemberExpr *create(Expr *expr, const char *identifier, SourcePos pos, SourcePos identifierPos,
338                               bool derefLvalue);
339 
classof(MemberExpr const *)340     static inline bool classof(MemberExpr const *) { return true; }
classof(ASTNode const * N)341     static inline bool classof(ASTNode const *N) {
342         return ((N->getValueID() == StructMemberExprID) || (N->getValueID() == VectorMemberExprID));
343     }
344 
345     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
346     llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
347     const Type *GetType() const;
348     Symbol *GetBaseSymbol() const;
349     void Print() const;
350     Expr *Optimize();
351     Expr *TypeCheck();
352     int EstimateCost() const;
353 
354     virtual int getElementNumber() const = 0;
355     virtual const Type *getElementType() const = 0;
356     std::string getCandidateNearMatches() const;
357 
358     Expr *expr;
359     std::string identifier;
360     const SourcePos identifierPos;
361 
362     MemberExpr(Expr *expr, const char *identifier, SourcePos pos, SourcePos identifierPos, bool derefLValue,
363                unsigned scid);
364 
365     /** Indicates whether the expression should be dereferenced before the
366         member is found.  (i.e. this is true if the MemberExpr was a '->'
367         operator, and is false if it was a '.' operator. */
368     bool dereferenceExpr;
369 
370   protected:
371     mutable const Type *type, *lvalueType;
372 };
373 
374 /** @brief Expression representing a compile-time constant value.
375 
376     This class can currently represent compile-time constants of anything
377     that is an AtomicType or an EnumType; for anything more complex, we
378     don't currently have a representation of a compile-time constant that
379     can be further reasoned about.
380  */
381 class ConstExpr : public Expr {
382   public:
383     /** Create a ConstExpr from a uniform int8 value */
384     ConstExpr(const Type *t, int8_t i, SourcePos p);
385     /** Create a ConstExpr from a varying int8 value */
386     ConstExpr(const Type *t, int8_t *i, SourcePos p);
387     /** Create a ConstExpr from a uniform uint8 value */
388     ConstExpr(const Type *t, uint8_t u, SourcePos p);
389     /** Create a ConstExpr from a varying uint8 value */
390     ConstExpr(const Type *t, uint8_t *u, SourcePos p);
391 
392     /** Create a ConstExpr from a uniform int16 value */
393     ConstExpr(const Type *t, int16_t i, SourcePos p);
394     /** Create a ConstExpr from a varying int16 value */
395     ConstExpr(const Type *t, int16_t *i, SourcePos p);
396     /** Create a ConstExpr from a uniform uint16 value */
397     ConstExpr(const Type *t, uint16_t u, SourcePos p);
398     /** Create a ConstExpr from a varying uint16 value */
399     ConstExpr(const Type *t, uint16_t *u, SourcePos p);
400 
401     /** Create a ConstExpr from a uniform int32 value */
402     ConstExpr(const Type *t, int32_t i, SourcePos p);
403     /** Create a ConstExpr from a varying int32 value */
404     ConstExpr(const Type *t, int32_t *i, SourcePos p);
405     /** Create a ConstExpr from a uniform uint32 value */
406     ConstExpr(const Type *t, uint32_t u, SourcePos p);
407     /** Create a ConstExpr from a varying uint32 value */
408     ConstExpr(const Type *t, uint32_t *u, SourcePos p);
409 
410     /** Create a ConstExpr from a uniform float value */
411     ConstExpr(const Type *t, float f, SourcePos p);
412     /** Create a ConstExpr from a varying float value */
413     ConstExpr(const Type *t, float *f, SourcePos p);
414 
415     /** Create a ConstExpr from a uniform double value */
416     ConstExpr(const Type *t, double d, SourcePos p);
417     /** Create a ConstExpr from a varying double value */
418     ConstExpr(const Type *t, double *d, SourcePos p);
419 
420     /** Create a ConstExpr from a uniform int64 value */
421     ConstExpr(const Type *t, int64_t i, SourcePos p);
422     /** Create a ConstExpr from a varying int64 value */
423     ConstExpr(const Type *t, int64_t *i, SourcePos p);
424     /** Create a ConstExpr from a uniform uint64 value */
425     ConstExpr(const Type *t, uint64_t i, SourcePos p);
426     /** Create a ConstExpr from a varying uint64 value */
427     ConstExpr(const Type *t, uint64_t *i, SourcePos p);
428 
429     /** Create a ConstExpr from a uniform bool value */
430     ConstExpr(const Type *t, bool b, SourcePos p);
431     /** Create a ConstExpr from a varying bool value */
432     ConstExpr(const Type *t, bool *b, SourcePos p);
433 
434     /** Create a ConstExpr of the same type as the given old ConstExpr,
435         with values given by the "vales" parameter. */
436     ConstExpr(ConstExpr *old, double *values);
437 
438     /** Create ConstExpr with the same type and values as the given one,
439         but at the given position. */
440     ConstExpr(ConstExpr *old, SourcePos pos);
441 
classof(ConstExpr const *)442     static inline bool classof(ConstExpr const *) { return true; }
classof(ASTNode const * N)443     static inline bool classof(ASTNode const *N) { return N->getValueID() == ConstExprID; }
444 
445     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
446     const Type *GetType() const;
447     void Print() const;
448     std::pair<llvm::Constant *, bool> GetStorageConstant(const Type *type) const;
449     std::pair<llvm::Constant *, bool> GetConstant(const Type *constType) const;
450 
451     Expr *TypeCheck();
452     Expr *Optimize();
453     int EstimateCost() const;
454 
455     /** Return the ConstExpr's values as the given pointer type, doing type
456         conversion from the actual type if needed.  If forceVarying is
457         true, then type convert to 'varying' so as to always return a
458         number of values equal to the target vector width into the given
459         pointer. */
460     int GetValues(bool *, bool forceVarying = false) const;
461     int GetValues(int8_t *, bool forceVarying = false) const;
462     int GetValues(uint8_t *, bool forceVarying = false) const;
463     int GetValues(int16_t *, bool forceVarying = false) const;
464     int GetValues(uint16_t *, bool forceVarying = false) const;
465     int GetValues(int32_t *, bool forceVarying = false) const;
466     int GetValues(uint32_t *, bool forceVarying = false) const;
467     int GetValues(float *, bool forceVarying = false) const;
468     int GetValues(int64_t *, bool forceVarying = false) const;
469     int GetValues(uint64_t *, bool forceVarying = false) const;
470     int GetValues(double *, bool forceVarying = false) const;
471 
472     /** Return the number of values in the ConstExpr; should be either 1,
473         if it has uniform type, or the target's vector width if it's
474         varying. */
475     int Count() const;
476 
477   private:
478     AtomicType::BasicType getBasicType() const;
479 
480     const Type *type;
481     union {
482         int8_t int8Val[ISPC_MAX_NVEC];
483         uint8_t uint8Val[ISPC_MAX_NVEC];
484         int16_t int16Val[ISPC_MAX_NVEC];
485         uint16_t uint16Val[ISPC_MAX_NVEC];
486         int32_t int32Val[ISPC_MAX_NVEC];
487         uint32_t uint32Val[ISPC_MAX_NVEC];
488         bool boolVal[ISPC_MAX_NVEC];
489         float floatVal[ISPC_MAX_NVEC];
490         double doubleVal[ISPC_MAX_NVEC];
491         int64_t int64Val[ISPC_MAX_NVEC];
492         uint64_t uint64Val[ISPC_MAX_NVEC];
493     };
494 };
495 
496 /** @brief Expression representing a type cast of the given expression to a
497     probably-different type. */
498 class TypeCastExpr : public Expr {
499   public:
500     TypeCastExpr(const Type *t, Expr *e, SourcePos p);
501 
classof(TypeCastExpr const *)502     static inline bool classof(TypeCastExpr const *) { return true; }
classof(ASTNode const * N)503     static inline bool classof(ASTNode const *N) { return N->getValueID() == TypeCastExprID; }
504 
505     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
506     llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
507     const Type *GetType() const;
508     const Type *GetLValueType() const;
509     void Print() const;
510     Expr *TypeCheck();
511     Expr *Optimize();
512     int EstimateCost() const;
513     Symbol *GetBaseSymbol() const;
514     std::pair<llvm::Constant *, bool> GetConstant(const Type *type) const;
515     bool HasAmbiguousVariability(std::vector<const Expr *> &warn) const;
516     void PrintAmbiguousVariability() const;
517 
518     const Type *type;
519     Expr *expr;
520 };
521 
522 /** @brief Expression that represents taking a reference of a (non-reference)
523     variable. */
524 class ReferenceExpr : public Expr {
525   public:
526     ReferenceExpr(Expr *e, SourcePos p);
527 
classof(ReferenceExpr const *)528     static inline bool classof(ReferenceExpr const *) { return true; }
classof(ASTNode const * N)529     static inline bool classof(ASTNode const *N) { return N->getValueID() == ReferenceExprID; }
530 
531     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
532     const Type *GetType() const;
533     const Type *GetLValueType() const;
534     Symbol *GetBaseSymbol() const;
535     void Print() const;
536     Expr *TypeCheck();
537     Expr *Optimize();
538     int EstimateCost() const;
539 
540     Expr *expr;
541 };
542 
543 /** @brief Common base class that provides shared functionality for
544     PtrDerefExpr and RefDerefExpr. */
545 class DerefExpr : public Expr {
546   public:
547     DerefExpr(Expr *e, SourcePos p, unsigned scid = DerefExprID);
548 
classof(DerefExpr const *)549     static inline bool classof(DerefExpr const *) { return true; }
classof(ASTNode const * N)550     static inline bool classof(ASTNode const *N) {
551         return ((N->getValueID() == DerefExprID) || (N->getValueID() == PtrDerefExprID) ||
552                 (N->getValueID() == RefDerefExprID));
553     }
554 
555     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
556     llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
557     const Type *GetLValueType() const;
558     Symbol *GetBaseSymbol() const;
559     Expr *Optimize();
560 
561     Expr *expr;
562 };
563 
564 /** @brief Expression that represents dereferencing a pointer to get its
565     value. */
566 class PtrDerefExpr : public DerefExpr {
567   public:
568     PtrDerefExpr(Expr *e, SourcePos p);
569 
classof(PtrDerefExpr const *)570     static inline bool classof(PtrDerefExpr const *) { return true; }
classof(ASTNode const * N)571     static inline bool classof(ASTNode const *N) { return N->getValueID() == PtrDerefExprID; }
572 
573     const Type *GetType() const;
574     void Print() const;
575     Expr *TypeCheck();
576     int EstimateCost() const;
577 };
578 
579 /** @brief Expression that represents dereferencing a reference to get its
580     value. */
581 class RefDerefExpr : public DerefExpr {
582   public:
583     RefDerefExpr(Expr *e, SourcePos p);
584 
classof(RefDerefExpr const *)585     static inline bool classof(RefDerefExpr const *) { return true; }
classof(ASTNode const * N)586     static inline bool classof(ASTNode const *N) { return N->getValueID() == RefDerefExprID; }
587 
588     const Type *GetType() const;
589     void Print() const;
590     Expr *TypeCheck();
591     int EstimateCost() const;
592 };
593 
594 /** Expression that represents taking the address of an expression. */
595 class AddressOfExpr : public Expr {
596   public:
597     AddressOfExpr(Expr *e, SourcePos p);
598 
classof(AddressOfExpr const *)599     static inline bool classof(AddressOfExpr const *) { return true; }
classof(ASTNode const * N)600     static inline bool classof(ASTNode const *N) { return N->getValueID() == AddressOfExprID; }
601 
602     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
603     const Type *GetType() const;
604     const Type *GetLValueType() const;
605     Symbol *GetBaseSymbol() const;
606     void Print() const;
607     Expr *TypeCheck();
608     Expr *Optimize();
609     int EstimateCost() const;
610     std::pair<llvm::Constant *, bool> GetConstant(const Type *type) const;
611 
612     Expr *expr;
613 };
614 
615 /** Expression that returns the size of the given expression or type in
616     bytes. */
617 class SizeOfExpr : public Expr {
618   public:
619     SizeOfExpr(Expr *e, SourcePos p);
620     SizeOfExpr(const Type *t, SourcePos p);
621 
classof(SizeOfExpr const *)622     static inline bool classof(SizeOfExpr const *) { return true; }
classof(ASTNode const * N)623     static inline bool classof(ASTNode const *N) { return N->getValueID() == SizeOfExprID; }
624 
625     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
626     const Type *GetType() const;
627     void Print() const;
628     Expr *TypeCheck();
629     Expr *Optimize();
630     int EstimateCost() const;
631     std::pair<llvm::Constant *, bool> GetConstant(const Type *type) const;
632 
633     /* One of expr or type should be non-NULL (but not both of them).  The
634        SizeOfExpr returns the size of whichever one of them isn't NULL. */
635     Expr *expr;
636     const Type *type;
637 };
638 
639 //  Expression that allocates space in the stack frame of the caller
640 //  and returns a pointer to the beginning of the allocated space.
641 class AllocaExpr : public Expr {
642   public:
643     AllocaExpr(Expr *e, SourcePos p);
644 
classof(AllocaExpr const *)645     static inline bool classof(AllocaExpr const *) { return true; }
classof(ASTNode const * N)646     static inline bool classof(ASTNode const *N) { return N->getValueID() == AllocaExprID; }
647 
648     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
649     const Type *GetType() const;
650     void Print() const;
651     Expr *TypeCheck();
652     Expr *Optimize();
653     int EstimateCost() const;
654 
655     // The expr should have size_t type and should evaluate to size
656     // of stack memory to be allocated.
657     Expr *expr;
658 };
659 
660 /** @brief Expression representing a symbol reference in the program */
661 class SymbolExpr : public Expr {
662   public:
663     SymbolExpr(Symbol *s, SourcePos p);
664 
classof(SymbolExpr const *)665     static inline bool classof(SymbolExpr const *) { return true; }
classof(ASTNode const * N)666     static inline bool classof(ASTNode const *N) { return N->getValueID() == SymbolExprID; }
667 
668     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
669     llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
670     const Type *GetType() const;
671     const Type *GetLValueType() const;
672     Symbol *GetBaseSymbol() const;
673     Expr *TypeCheck();
674     Expr *Optimize();
675     void Print() const;
676     int EstimateCost() const;
677 
678   private:
679     Symbol *symbol;
680 };
681 
682 /** @brief Expression representing a function symbol in the program (generally
683     used for a function call).
684  */
685 class FunctionSymbolExpr : public Expr {
686   public:
687     FunctionSymbolExpr(const char *name, const std::vector<Symbol *> &candFuncs, SourcePos pos);
688 
classof(FunctionSymbolExpr const *)689     static inline bool classof(FunctionSymbolExpr const *) { return true; }
classof(ASTNode const * N)690     static inline bool classof(ASTNode const *N) { return N->getValueID() == FunctionSymbolExprID; }
691 
692     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
693     const Type *GetType() const;
694     Symbol *GetBaseSymbol() const;
695     Expr *TypeCheck();
696     Expr *Optimize();
697     void Print() const;
698     int EstimateCost() const;
699     std::pair<llvm::Constant *, bool> GetConstant(const Type *type) const;
700 
701     /** Given the types of the function arguments, in the presence of
702         function overloading, this method resolves which actual function
703         the arguments match best.  If the argCouldBeNULL parameter is
704         non-NULL, each element indicates whether the corresponding argument
705         is the number zero, indicating that it could be a NULL pointer, and
706         if argIsConstant is non-NULL, each element indicates whether the
707         corresponding argument is a compile-time constant value.  Both of
708         these parameters may be NULL (for cases where overload resolution
709         is being done just given type information without the parameter
710         argument expressions being available.  This function returns true
711         on success.
712      */
713     bool ResolveOverloads(SourcePos argPos, const std::vector<const Type *> &argTypes,
714                           const std::vector<bool> *argCouldBeNULL = NULL,
715                           const std::vector<bool> *argIsConstant = NULL);
716     Symbol *GetMatchingFunction();
717 
718   private:
719     std::vector<Symbol *> getCandidateFunctions(int argCount) const;
720     static int computeOverloadCost(const FunctionType *ftype, const std::vector<const Type *> &argTypes,
721                                    const std::vector<bool> *argCouldBeNULL, const std::vector<bool> *argIsConstant,
722                                    int *cost);
723 
724     /** Name of the function that is being called. */
725     std::string name;
726 
727     /** All of the functions with the name given in the function call;
728         there may be more then one, in which case we need to resolve which
729         overload is the best match. */
730     std::vector<Symbol *> candidateFunctions;
731 
732     /** The actual matching function found after overload resolution. */
733     Symbol *matchingFunc;
734 
735     bool triedToResolve;
736 };
737 
738 /** @brief A sync statement in the program (waits for all launched tasks before
739     proceeding). */
740 class SyncExpr : public Expr {
741   public:
SyncExpr(SourcePos p)742     SyncExpr(SourcePos p) : Expr(p, SyncExprID) {}
743 
classof(SyncExpr const *)744     static inline bool classof(SyncExpr const *) { return true; }
classof(ASTNode const * N)745     static inline bool classof(ASTNode const *N) { return N->getValueID() == SyncExprID; }
746 
747     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
748     const Type *GetType() const;
749     Expr *TypeCheck();
750     Expr *Optimize();
751     void Print() const;
752     int EstimateCost() const;
753 };
754 
755 /** @brief An expression that represents a NULL pointer. */
756 class NullPointerExpr : public Expr {
757   public:
NullPointerExpr(SourcePos p)758     NullPointerExpr(SourcePos p) : Expr(p, NullPointerExprID) {}
759 
classof(NullPointerExpr const *)760     static inline bool classof(NullPointerExpr const *) { return true; }
classof(ASTNode const * N)761     static inline bool classof(ASTNode const *N) { return N->getValueID() == NullPointerExprID; }
762 
763     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
764     const Type *GetType() const;
765     Expr *TypeCheck();
766     Expr *Optimize();
767     std::pair<llvm::Constant *, bool> GetConstant(const Type *type) const;
768     void Print() const;
769     int EstimateCost() const;
770 };
771 
772 /** An expression representing a "new" expression, used for dynamically
773     allocating memory.
774 */
775 class NewExpr : public Expr {
776   public:
777     NewExpr(int typeQual, const Type *type, Expr *initializer, Expr *count, SourcePos tqPos, SourcePos p);
778 
classof(NewExpr const *)779     static inline bool classof(NewExpr const *) { return true; }
classof(ASTNode const * N)780     static inline bool classof(ASTNode const *N) { return N->getValueID() == NewExprID; }
781 
782     llvm::Value *GetValue(FunctionEmitContext *ctx) const;
783     const Type *GetType() const;
784     Expr *TypeCheck();
785     Expr *Optimize();
786     void Print() const;
787     int EstimateCost() const;
788 
789     /** Type of object to allocate storage for. */
790     const Type *allocType;
791     /** Expression giving the number of elements to allocate, when the
792         "new Foo[expr]" form is used.  This may be NULL, in which case a
793         single element of the given type will be allocated. */
794     Expr *countExpr;
795     /** Optional initializer expression used to initialize the allocated
796         memory. */
797     Expr *initExpr;
798     /** Indicates whether this is a "varying new" or "uniform new"
799         (i.e. whether a separate allocation is performed per program
800         instance, or whether a single allocation is performed for the
801         entire gang of program instances.) */
802     bool isVarying;
803 };
804 
805 /** This function indicates whether it's legal to convert from fromType to
806     toType.  If the optional errorMsgBase and source position parameters
807     are provided, then an error message is issued if the type conversion
808     isn't possible.
809  */
810 bool CanConvertTypes(const Type *fromType, const Type *toType, const char *errorMsgBase = NULL,
811                      SourcePos pos = SourcePos());
812 
813 /** This function attempts to convert the given expression to the given
814     type, returning a pointer to a new expression that is the result.  If
815     the required type conversion is illegal, it returns NULL and prints an
816     error message using the provided string to indicate the context for
817     which type conversion was being applied (e.g. "function call
818     parameter").
819  */
820 Expr *TypeConvertExpr(Expr *expr, const Type *toType, const char *errorMsgBase);
821 
822 Expr *MakeBinaryExpr(BinaryExpr::Op o, Expr *a, Expr *b, SourcePos p);
823 
824 /** Utility routine that emits code to initialize a symbol given an
825     initializer expression.
826 
827     @param lvalue    Memory location of storage for the symbol's data
828     @param symName   Name of symbol (used in error messages)
829     @param symType   Type of variable being initialized
830     @param initExpr  Expression for the initializer
831     @param ctx       FunctionEmitContext to use for generating instructions
832     @param pos       Source file position of the variable being initialized
833 */
834 void InitSymbol(llvm::Value *lvalue, const Type *symType, Expr *initExpr, FunctionEmitContext *ctx, SourcePos pos);
835 
836 bool PossiblyResolveFunctionOverloads(Expr *expr, const Type *type);
837 } // namespace ispc
838