23 Commits

Author SHA1 Message Date
64e1e2b008 Generate overloaded function definitions 2017-05-10 14:21:09 -04:00
192b99f21d Translates polymorphic function to a single instance 2017-05-09 23:41:36 -04:00
871af918ad Remove trailing whitespace 2017-05-09 23:01:40 -04:00
7bb1741b9a [WIP] implement ReplacePolyType for stmts 2017-05-09 15:30:39 -04:00
aeb4c0b6f9 [WIP] replace polymorphic types from expressions 2017-05-09 01:46:36 -04:00
9c0f9be022 remove trailing whitespace 2017-05-09 01:46:33 -04:00
a5306eddc1 Merge branch 'codegen' of github.com:aarongut/ispc into codegen 2017-05-08 17:45:28 -04:00
0f17514eb0 remove trailing whitespace 2017-05-08 17:45:17 -04:00
8a1aeed55c remove trailing whitespace 2017-05-08 17:40:15 -04:00
05c9f63527 Remove trailing whitespace 2017-05-08 15:30:06 -04:00
c86c5097d7 remove trailing whitespace 2017-05-07 15:08:47 -04:00
46ed9bdb3c [WIP] Plumbing to expand polymorphic functions 2017-05-04 21:26:43 -04:00
93c563e073 Add missing NULL check in CanBeType 2017-05-02 22:26:21 -04:00
b3b02df569 [WIP] add check for polymorphic functions 2017-05-02 14:59:04 -04:00
0887760de1 [WIP] typechecking for casts to polymorphic types 2017-04-29 15:56:43 -04:00
148c333943 Merge branch 'master' into parse 2017-04-29 11:11:39 -04:00
98e5809d24 Ignore vscode and osx build stuff 2017-04-29 11:10:36 -04:00
87b6ed7f4c [WIP] slowly getting typechecking to work 2017-04-28 23:37:06 -04:00
259f092143 [WIP] Add quantifier to polymorphic types 2017-04-28 14:04:26 -04:00
108c9c6fb5 [WIP] parses polymorphic types 2017-04-27 14:17:47 -04:00
128b40ce3c Add test for polymorphic non-exported function 2017-04-26 22:33:03 -04:00
717aec388b Merge branch 'concept-check' 2017-04-26 11:39:59 -04:00
f2287d2cd7 Added tests for typechecking 2017-04-26 11:38:17 -04:00
28 changed files with 1303 additions and 189 deletions

5
.gitignore vendored
View File

@@ -1,5 +1,6 @@
*.pyc *.pyc
*~ *~
tags
depend depend
ispc ispc
ispc_test ispc_test
@@ -12,6 +13,7 @@ tests*/*cpp
tests*/*run tests*/*run
tests*/*.o tests*/*.o
tests_ispcpp/*.h tests_ispcpp/*.h
tests_ispcpp/*.out
tests_ispcpp/*pre* tests_ispcpp/*pre*
logs/ logs/
notify_log.log notify_log.log
@@ -23,5 +25,8 @@ examples/*/ref
examples/*/test examples/*/test
*.swp *.swp
check_isa.exe check_isa.exe
.vscode
configure
ispc.dSYM

40
ast.cpp
View File

@@ -42,8 +42,11 @@
#include "func.h" #include "func.h"
#include "stmt.h" #include "stmt.h"
#include "sym.h" #include "sym.h"
#include "type.h"
#include "util.h" #include "util.h"
#include <map>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// ASTNode // ASTNode
@@ -55,10 +58,21 @@ ASTNode::~ASTNode() {
// AST // AST
void void
AST::AddFunction(Symbol *sym, Stmt *code) { AST::AddFunction(Symbol *sym, Stmt *code, SymbolTable *symbolTable) {
if (sym == NULL) if (sym == NULL)
return; return;
functions.push_back(new Function(sym, code));
Function *f = new Function(sym, code);
if (f->IsPolyFunction()) {
std::vector<Function *> *expanded = f->ExpandPolyArguments(symbolTable);
for (size_t i=0; i<expanded->size(); i++) {
functions.push_back((*expanded)[i]);
}
delete expanded;
} else {
functions.push_back(f);
}
} }
@@ -508,3 +522,25 @@ SafeToRunWithMaskAllOff(ASTNode *root) {
WalkAST(root, lCheckAllOffSafety, NULL, &safe); WalkAST(root, lCheckAllOffSafety, NULL, &safe);
return safe; return safe;
} }
struct PolyData {
const PolyType *polyType;
const Type *replacement;
};
static ASTNode *
lTranslatePolyNode(ASTNode *node, void *d) {
struct PolyData *data = (struct PolyData*)d;
return node->ReplacePolyType(data->polyType, data->replacement);
}
ASTNode *
TranslatePoly(ASTNode *root, const PolyType *polyType, const Type *replacement) {
struct PolyData data;
data.polyType = polyType;
data.replacement = replacement;
return WalkAST(root, NULL, lTranslatePolyNode, &data);
}

7
ast.h
View File

@@ -39,6 +39,7 @@
#define ISPC_AST_H 1 #define ISPC_AST_H 1
#include "ispc.h" #include "ispc.h"
#include "type.h"
#include <vector> #include <vector>
/** @brief Abstract base class for nodes in the abstract syntax tree (AST). /** @brief Abstract base class for nodes in the abstract syntax tree (AST).
@@ -67,6 +68,8 @@ public:
pointer in place of the original ASTNode *. */ pointer in place of the original ASTNode *. */
virtual ASTNode *TypeCheck() = 0; virtual ASTNode *TypeCheck() = 0;
virtual ASTNode *ReplacePolyType(const PolyType *, const Type *) = 0;
/** Estimate the execution cost of the node (not including the cost of /** Estimate the execution cost of the node (not including the cost of
the children. The value returned should be based on the COST_* the children. The value returned should be based on the COST_*
enumerant values defined in ispc.h. */ enumerant values defined in ispc.h. */
@@ -145,7 +148,7 @@ class AST {
public: public:
/** Add the AST for a function described by the given declaration /** Add the AST for a function described by the given declaration
information and source code. */ information and source code. */
void AddFunction(Symbol *sym, Stmt *code); void AddFunction(Symbol *sym, Stmt *code, SymbolTable *symbolTable=NULL);
/** Generate LLVM IR for all of the functions into the current /** Generate LLVM IR for all of the functions into the current
module. */ module. */
@@ -204,6 +207,8 @@ extern Stmt *TypeCheck(Stmt *);
the given root. */ the given root. */
extern int EstimateCost(ASTNode *root); extern int EstimateCost(ASTNode *root);
extern ASTNode * TranslatePoly(ASTNode *root, const PolyType *polyType, const Type *replacement);
/** Returns true if it would be safe to run the given code with an "all /** Returns true if it would be safe to run the given code with an "all
off" mask. */ off" mask. */
extern bool SafeToRunWithMaskAllOff(ASTNode *root); extern bool SafeToRunWithMaskAllOff(ASTNode *root);

View File

@@ -112,6 +112,11 @@ Expr::GetBaseSymbol() const {
return NULL; return NULL;
} }
Expr *
Expr::ReplacePolyType(const PolyType *polyType, const Type *replacement) {
return this;
}
#if 0 #if 0
/** If a conversion from 'fromAtomicType' to 'toAtomicType' may cause lost /** If a conversion from 'fromAtomicType' to 'toAtomicType' may cause lost
@@ -276,6 +281,8 @@ lDoTypeConv(const Type *fromType, const Type *toType, Expr **expr,
const AtomicType *fromAtomicType = CastType<AtomicType>(fromType); const AtomicType *fromAtomicType = CastType<AtomicType>(fromType);
const PointerType *fromPointerType = CastType<PointerType>(fromType); const PointerType *fromPointerType = CastType<PointerType>(fromType);
const PointerType *toPointerType = CastType<PointerType>(toType); const PointerType *toPointerType = CastType<PointerType>(toType);
const PolyType *fromPolyType = CastType<PolyType>(fromType);
const PolyType *toPolyType = CastType<PolyType>(toType);
// Do this early, since for the case of a conversion like // Do this early, since for the case of a conversion like
// "float foo[10]" -> "float * uniform foo", we have what's seemingly // "float foo[10]" -> "float * uniform foo", we have what's seemingly
@@ -544,6 +551,20 @@ lDoTypeConv(const Type *fromType, const Type *toType, Expr **expr,
goto typecast_ok; goto typecast_ok;
} }
// atomic -> polymorphic
if ((fromAtomicType || fromPolyType) && toPolyType) {
if (toPolyType->CanBeType(fromType)) {
goto typecast_ok;
} else {
if (!failureOk) {
Error(pos, "Can't convert between \"%s\" and polymorphic type "
"\"%s\" for %s", fromType->GetString().c_str(),
toPolyType->GetString().c_str(), errorMsgBase);
}
}
}
// from here on out, the from type can only be atomic something or // from here on out, the from type can only be atomic something or
// other... // other...
if (fromAtomicType == NULL) { if (fromAtomicType == NULL) {
@@ -4653,6 +4674,23 @@ IndexExpr::TypeCheck() {
return this; return this;
} }
Expr *
IndexExpr::ReplacePolyType(const PolyType *from, const Type *to) {
if (index == NULL || baseExpr == NULL)
return NULL;
if (Type::EqualForReplacement(this->GetType()->GetBaseType(), from)) {
type = PolyType::ReplaceType(type, to);
}
if (Type::EqualForReplacement(this->GetLValueType()->GetBaseType(), from)) {
lvalueType = new PointerType(to, lvalueType->GetVariability(),
lvalueType->IsConstType());
}
return this;
}
int int
IndexExpr::EstimateCost() const { IndexExpr::EstimateCost() const {
@@ -5295,6 +5333,23 @@ MemberExpr::Optimize() {
return expr ? this : NULL; return expr ? this : NULL;
} }
Expr *
MemberExpr::ReplacePolyType(const PolyType *from, const Type *to) {
if (expr == NULL)
return NULL;
if (Type::EqualForReplacement(this->GetType()->GetBaseType(), from)) {
type = PolyType::ReplaceType(type, to);
}
if (Type::EqualForReplacement(this->GetLValueType()->GetBaseType(), from)) {
lvalueType = PolyType::ReplaceType(lvalueType, lvalueType);
}
return this;
}
int int
MemberExpr::EstimateCost() const { MemberExpr::EstimateCost() const {
@@ -7097,6 +7152,9 @@ TypeCastExpr::GetValue(FunctionEmitContext *ctx) const {
else { else {
const AtomicType *toAtomic = CastType<AtomicType>(toType); const AtomicType *toAtomic = CastType<AtomicType>(toType);
// typechecking should ensure this is the case // typechecking should ensure this is the case
if (!toAtomic) {
fprintf(stderr, "I want %s to be atomic\n", toType->GetString().c_str());
}
AssertPos(pos, toAtomic != NULL); AssertPos(pos, toAtomic != NULL);
return lTypeConvAtomic(ctx, exprVal, toAtomic, fromAtomic, pos); return lTypeConvAtomic(ctx, exprVal, toAtomic, fromAtomic, pos);
@@ -7326,6 +7384,18 @@ TypeCastExpr::Optimize() {
return this; return this;
} }
Expr *
TypeCastExpr::ReplacePolyType(const PolyType *from, const Type *to) {
if (type == NULL)
return NULL;
if (Type::EqualForReplacement(type->GetBaseType(), from)) {
type = PolyType::ReplaceType(type, to);
}
return this;
}
int int
TypeCastExpr::EstimateCost() const { TypeCastExpr::EstimateCost() const {
@@ -7996,6 +8066,18 @@ SymbolExpr::Optimize() {
return this; return this;
} }
Expr *
SymbolExpr::ReplacePolyType(const PolyType *from, const Type *to) {
if (!symbol)
return NULL;
if (Type::EqualForReplacement(symbol->type->GetBaseType(), from)) {
symbol->type = PolyType::ReplaceType(symbol->type, to);
}
return this;
}
int int
SymbolExpr::EstimateCost() const { SymbolExpr::EstimateCost() const {
@@ -8794,6 +8876,18 @@ NewExpr::Optimize() {
return this; return this;
} }
Expr *
NewExpr::ReplacePolyType(const PolyType *from, const Type *to) {
if (!allocType)
return this;
if (Type::EqualForReplacement(allocType->GetBaseType(), from)) {
allocType = PolyType::ReplaceType(allocType, to);
}
return this;
}
void void
NewExpr::Print() const { NewExpr::Print() const {

9
expr.h
View File

@@ -96,6 +96,10 @@ public:
encountered, NULL should be returned. */ encountered, NULL should be returned. */
virtual Expr *TypeCheck() = 0; virtual Expr *TypeCheck() = 0;
/** This method replaces a polymorphic type with a specific atomic type */
Expr *ReplacePolyType(const PolyType *polyType, const Type *replacement);
/** Prints the expression to standard output (used for debugging). */ /** Prints the expression to standard output (used for debugging). */
virtual void Print() const = 0; virtual void Print() const = 0;
}; };
@@ -324,6 +328,7 @@ public:
Expr *Optimize(); Expr *Optimize();
Expr *TypeCheck(); Expr *TypeCheck();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const; int EstimateCost() const;
Expr *baseExpr, *index; Expr *baseExpr, *index;
@@ -357,6 +362,7 @@ public:
void Print() const; void Print() const;
Expr *Optimize(); Expr *Optimize();
Expr *TypeCheck(); Expr *TypeCheck();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const; int EstimateCost() const;
virtual int getElementNumber() const = 0; virtual int getElementNumber() const = 0;
@@ -522,6 +528,7 @@ public:
void Print() const; void Print() const;
Expr *TypeCheck(); Expr *TypeCheck();
Expr *Optimize(); Expr *Optimize();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const; int EstimateCost() const;
Symbol *GetBaseSymbol() const; Symbol *GetBaseSymbol() const;
llvm::Constant *GetConstant(const Type *type) const; llvm::Constant *GetConstant(const Type *type) const;
@@ -681,6 +688,7 @@ public:
Symbol *GetBaseSymbol() const; Symbol *GetBaseSymbol() const;
Expr *TypeCheck(); Expr *TypeCheck();
Expr *Optimize(); Expr *Optimize();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
void Print() const; void Print() const;
int EstimateCost() const; int EstimateCost() const;
@@ -809,6 +817,7 @@ public:
const Type *GetType() const; const Type *GetType() const;
Expr *TypeCheck(); Expr *TypeCheck();
Expr *Optimize(); Expr *Optimize();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
void Print() const; void Print() const;
int EstimateCost() const; int EstimateCost() const;

View File

@@ -45,6 +45,7 @@
#include "sym.h" #include "sym.h"
#include "util.h" #include "util.h"
#include <stdio.h> #include <stdio.h>
#include <set>
#if ISPC_LLVM_VERSION == ISPC_LLVM_3_2 // 3.2 #if ISPC_LLVM_VERSION == ISPC_LLVM_3_2 // 3.2
#ifdef ISPC_NVPTX_ENABLED #ifdef ISPC_NVPTX_ENABLED
@@ -627,3 +628,57 @@ Function::GenerateIR() {
} }
} }
} }
const bool
Function::IsPolyFunction() const {
for (size_t i = 0; i < args.size(); i++) {
if (args[i]->type->IsPolymorphicType()) {
return true;
}
}
return false;
}
std::vector<Function *> *
Function::ExpandPolyArguments(SymbolTable *symbolTable) const {
Assert(symbolTable != NULL);
std::vector<Function *> *expanded = new std::vector<Function *>();
std::vector<Symbol *> versions = symbolTable->LookupPolyFunction(sym->name.c_str());
const FunctionType *func = CastType<FunctionType>(sym->type);
printf("%s before replacing anything:\n", sym->name.c_str());
code->Print(0);
for (size_t i=0; i<versions.size(); i++) {
const FunctionType *ft = CastType<FunctionType>(versions[i]->type);
Stmt *ncode = code;
for (int j=0; j<ft->GetNumParameters(); j++) {
if (func->GetParameterType(j)->IsPolymorphicType()) {
const PolyType *from = CastType<PolyType>(
func->GetParameterType(j)->GetBaseType());
ncode = (Stmt*)TranslatePoly(ncode, from,
ft->GetParameterType(j)->GetBaseType());
printf("%s after replacing %s with %s:\n\n",
sym->name.c_str(), from->GetString().c_str(),
ft->GetParameterType(j)->GetBaseType()->GetString().c_str());
ncode->Print(0);
printf("------------------------------------------\n\n");
}
}
Symbol *s = symbolTable->LookupFunction(versions[i]->name.c_str(), ft);
expanded->push_back(new Function(s, ncode));
}
return expanded;
}

6
func.h
View File

@@ -39,6 +39,7 @@
#define ISPC_FUNC_H 1 #define ISPC_FUNC_H 1
#include "ispc.h" #include "ispc.h"
#include "sym.h"
#include <vector> #include <vector>
class Function { class Function {
@@ -51,6 +52,11 @@ public:
/** Generate LLVM IR for the function into the current module. */ /** Generate LLVM IR for the function into the current module. */
void GenerateIR(); void GenerateIR();
/** Checks if the function has polymorphic parameters */
const bool IsPolyFunction() const;
std::vector<Function *> *ExpandPolyArguments(SymbolTable *symbolTable) const;
private: private:
void emitCode(FunctionEmitContext *ctx, llvm::Function *function, void emitCode(FunctionEmitContext *ctx, llvm::Function *function,
SourcePos firstStmtPos); SourcePos firstStmtPos);

44
lex.ll
View File

@@ -63,31 +63,28 @@ inline int isatty(int) { return 0; }
#endif // ISPC_IS_WINDOWS #endif // ISPC_IS_WINDOWS
static int allTokens[] = { static int allTokens[] = {
TOKEN_ASSERT, TOKEN_BOOL, TOKEN_BREAK, TOKEN_CASE, TOKEN_ASSERT, TOKEN_BOOL, TOKEN_BREAK, TOKEN_CASE, TOKEN_CDO, TOKEN_CFOR,
TOKEN_CDO, TOKEN_CFOR, TOKEN_CIF, TOKEN_CWHILE, TOKEN_CIF, TOKEN_CWHILE, TOKEN_CONST, TOKEN_CONTINUE, TOKEN_DEFAULT, TOKEN_DO,
TOKEN_CONST, TOKEN_CONTINUE, TOKEN_DEFAULT, TOKEN_DO, TOKEN_DELETE, TOKEN_DOUBLE, TOKEN_ELSE, TOKEN_ENUM, TOKEN_EXPORT,
TOKEN_DELETE, TOKEN_DOUBLE, TOKEN_ELSE, TOKEN_ENUM, TOKEN_EXTERN, TOKEN_FALSE, TOKEN_FLOAT, TOKEN_FLOATING, TOKEN_FOR,
TOKEN_EXPORT, TOKEN_EXTERN, TOKEN_FALSE, TOKEN_FLOAT, TOKEN_FOR,
TOKEN_FOREACH, TOKEN_FOREACH_ACTIVE, TOKEN_FOREACH_TILED, TOKEN_FOREACH, TOKEN_FOREACH_ACTIVE, TOKEN_FOREACH_TILED,
TOKEN_FOREACH_UNIQUE, TOKEN_GOTO, TOKEN_IF, TOKEN_IN, TOKEN_INLINE, TOKEN_FOREACH_UNIQUE, TOKEN_GOTO, TOKEN_IF, TOKEN_IN, TOKEN_INLINE, TOKEN_INT,
TOKEN_INT, TOKEN_INT8, TOKEN_INT16, TOKEN_INT, TOKEN_INT64, TOKEN_LAUNCH, TOKEN_INT8, TOKEN_INT16, TOKEN_INT, TOKEN_INT64, TOKEN_INTEGER, TOKEN_LAUNCH,
TOKEN_NEW, TOKEN_NULL, TOKEN_PRINT, TOKEN_RETURN, TOKEN_SOA, TOKEN_SIGNED, TOKEN_NEW, TOKEN_NULL, TOKEN_NUMBER, TOKEN_PRINT, TOKEN_RETURN, TOKEN_SOA,
TOKEN_SIZEOF, TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH, TOKEN_SYNC, TOKEN_SIGNED, TOKEN_SIZEOF, TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH,
TOKEN_TASK, TOKEN_TRUE, TOKEN_TYPEDEF, TOKEN_UNIFORM, TOKEN_UNMASKED, TOKEN_SYNC, TOKEN_TASK, TOKEN_TRUE, TOKEN_TYPEDEF, TOKEN_UNIFORM,
TOKEN_UNSIGNED, TOKEN_VARYING, TOKEN_VOID, TOKEN_WHILE, TOKEN_UNMASKED, TOKEN_UNSIGNED, TOKEN_VARYING, TOKEN_VOID, TOKEN_WHILE,
TOKEN_STRING_C_LITERAL, TOKEN_DOTDOTDOT, TOKEN_STRING_C_LITERAL, TOKEN_DOTDOTDOT, TOKEN_FLOAT_CONSTANT,
TOKEN_FLOAT_CONSTANT, TOKEN_DOUBLE_CONSTANT, TOKEN_DOUBLE_CONSTANT, TOKEN_INT8_CONSTANT, TOKEN_UINT8_CONSTANT,
TOKEN_INT8_CONSTANT, TOKEN_UINT8_CONSTANT, TOKEN_INT16_CONSTANT, TOKEN_UINT16_CONSTANT, TOKEN_INT32_CONSTANT,
TOKEN_INT16_CONSTANT, TOKEN_UINT16_CONSTANT, TOKEN_UINT32_CONSTANT, TOKEN_INT64_CONSTANT, TOKEN_UINT64_CONSTANT,
TOKEN_INT32_CONSTANT, TOKEN_UINT32_CONSTANT,
TOKEN_INT64_CONSTANT, TOKEN_UINT64_CONSTANT,
TOKEN_INC_OP, TOKEN_DEC_OP, TOKEN_LEFT_OP, TOKEN_RIGHT_OP, TOKEN_LE_OP, TOKEN_INC_OP, TOKEN_DEC_OP, TOKEN_LEFT_OP, TOKEN_RIGHT_OP, TOKEN_LE_OP,
TOKEN_GE_OP, TOKEN_EQ_OP, TOKEN_NE_OP, TOKEN_AND_OP, TOKEN_OR_OP, TOKEN_GE_OP, TOKEN_EQ_OP, TOKEN_NE_OP, TOKEN_AND_OP, TOKEN_OR_OP,
TOKEN_MUL_ASSIGN, TOKEN_DIV_ASSIGN, TOKEN_MOD_ASSIGN, TOKEN_ADD_ASSIGN, TOKEN_MUL_ASSIGN, TOKEN_DIV_ASSIGN, TOKEN_MOD_ASSIGN, TOKEN_ADD_ASSIGN,
TOKEN_SUB_ASSIGN, TOKEN_LEFT_ASSIGN, TOKEN_RIGHT_ASSIGN, TOKEN_AND_ASSIGN, TOKEN_SUB_ASSIGN, TOKEN_LEFT_ASSIGN, TOKEN_RIGHT_ASSIGN, TOKEN_AND_ASSIGN,
TOKEN_XOR_ASSIGN, TOKEN_OR_ASSIGN, TOKEN_PTR_OP, TOKEN_XOR_ASSIGN, TOKEN_OR_ASSIGN, TOKEN_PTR_OP,
';', '{', '}', ',', ':', '=', '(', ')', '[', ']', '.', '&', '!', '~', '-', ';', '{', '}', ',', ':', '=', '(', ')', '[', ']', '.', '&', '!', '~', '-',
'+', '*', '/', '%', '<', '>', '^', '|', '?', '+', '*', '/', '%', '<', '>', '^', '|', '?', '$'
}; };
std::map<int, std::string> tokenToName; std::map<int, std::string> tokenToName;
@@ -114,6 +111,7 @@ void ParserInit() {
tokenToName[TOKEN_EXTERN] = "extern"; tokenToName[TOKEN_EXTERN] = "extern";
tokenToName[TOKEN_FALSE] = "false"; tokenToName[TOKEN_FALSE] = "false";
tokenToName[TOKEN_FLOAT] = "float"; tokenToName[TOKEN_FLOAT] = "float";
tokenToName[TOKEN_FLOATING] = "floating";
tokenToName[TOKEN_FOR] = "for"; tokenToName[TOKEN_FOR] = "for";
tokenToName[TOKEN_FOREACH] = "foreach"; tokenToName[TOKEN_FOREACH] = "foreach";
tokenToName[TOKEN_FOREACH_ACTIVE] = "foreach_active"; tokenToName[TOKEN_FOREACH_ACTIVE] = "foreach_active";
@@ -127,10 +125,12 @@ void ParserInit() {
tokenToName[TOKEN_INT8] = "int8"; tokenToName[TOKEN_INT8] = "int8";
tokenToName[TOKEN_INT16] = "int16"; tokenToName[TOKEN_INT16] = "int16";
tokenToName[TOKEN_INT] = "int"; tokenToName[TOKEN_INT] = "int";
tokenToName[TOKEN_INTEGER] = "integer";
tokenToName[TOKEN_INT64] = "int64"; tokenToName[TOKEN_INT64] = "int64";
tokenToName[TOKEN_LAUNCH] = "launch"; tokenToName[TOKEN_LAUNCH] = "launch";
tokenToName[TOKEN_NEW] = "new"; tokenToName[TOKEN_NEW] = "new";
tokenToName[TOKEN_NULL] = "NULL"; tokenToName[TOKEN_NULL] = "NULL";
tokenToName[TOKEN_NUMBER] = "number";
tokenToName[TOKEN_PRINT] = "print"; tokenToName[TOKEN_PRINT] = "print";
tokenToName[TOKEN_RETURN] = "return"; tokenToName[TOKEN_RETURN] = "return";
tokenToName[TOKEN_SOA] = "soa"; tokenToName[TOKEN_SOA] = "soa";
@@ -207,6 +207,7 @@ void ParserInit() {
tokenToName['|'] = "|"; tokenToName['|'] = "|";
tokenToName['?'] = "?"; tokenToName['?'] = "?";
tokenToName[';'] = ";"; tokenToName[';'] = ";";
tokenToName['$'] = "$";
tokenNameRemap["TOKEN_ASSERT"] = "\'assert\'"; tokenNameRemap["TOKEN_ASSERT"] = "\'assert\'";
tokenNameRemap["TOKEN_BOOL"] = "\'bool\'"; tokenNameRemap["TOKEN_BOOL"] = "\'bool\'";
@@ -228,6 +229,7 @@ void ParserInit() {
tokenNameRemap["TOKEN_EXTERN"] = "\'extern\'"; tokenNameRemap["TOKEN_EXTERN"] = "\'extern\'";
tokenNameRemap["TOKEN_FALSE"] = "\'false\'"; tokenNameRemap["TOKEN_FALSE"] = "\'false\'";
tokenNameRemap["TOKEN_FLOAT"] = "\'float\'"; tokenNameRemap["TOKEN_FLOAT"] = "\'float\'";
tokenNameRemap["TOKEN_FLOATING"] = "\'floating\'";
tokenNameRemap["TOKEN_FOR"] = "\'for\'"; tokenNameRemap["TOKEN_FOR"] = "\'for\'";
tokenNameRemap["TOKEN_FOREACH"] = "\'foreach\'"; tokenNameRemap["TOKEN_FOREACH"] = "\'foreach\'";
tokenNameRemap["TOKEN_FOREACH_ACTIVE"] = "\'foreach_active\'"; tokenNameRemap["TOKEN_FOREACH_ACTIVE"] = "\'foreach_active\'";
@@ -243,9 +245,11 @@ void ParserInit() {
tokenNameRemap["TOKEN_INT16"] = "\'int16\'"; tokenNameRemap["TOKEN_INT16"] = "\'int16\'";
tokenNameRemap["TOKEN_INT"] = "\'int\'"; tokenNameRemap["TOKEN_INT"] = "\'int\'";
tokenNameRemap["TOKEN_INT64"] = "\'int64\'"; tokenNameRemap["TOKEN_INT64"] = "\'int64\'";
tokenNameRemap["TOKEN_INTEGER"] = "\'integer\'";
tokenNameRemap["TOKEN_LAUNCH"] = "\'launch\'"; tokenNameRemap["TOKEN_LAUNCH"] = "\'launch\'";
tokenNameRemap["TOKEN_NEW"] = "\'new\'"; tokenNameRemap["TOKEN_NEW"] = "\'new\'";
tokenNameRemap["TOKEN_NULL"] = "\'NULL\'"; tokenNameRemap["TOKEN_NULL"] = "\'NULL\'";
tokenNameRemap["TOKEN_NUMBER"] = "\'number\'";
tokenNameRemap["TOKEN_PRINT"] = "\'print\'"; tokenNameRemap["TOKEN_PRINT"] = "\'print\'";
tokenNameRemap["TOKEN_RETURN"] = "\'return\'"; tokenNameRemap["TOKEN_RETURN"] = "\'return\'";
tokenNameRemap["TOKEN_SOA"] = "\'soa\'"; tokenNameRemap["TOKEN_SOA"] = "\'soa\'";
@@ -381,6 +385,7 @@ export { RT; return TOKEN_EXPORT; }
extern { RT; return TOKEN_EXTERN; } extern { RT; return TOKEN_EXTERN; }
false { RT; return TOKEN_FALSE; } false { RT; return TOKEN_FALSE; }
float { RT; return TOKEN_FLOAT; } float { RT; return TOKEN_FLOAT; }
floating { RT; return TOKEN_FLOATING; }
for { RT; return TOKEN_FOR; } for { RT; return TOKEN_FOR; }
foreach { RT; return TOKEN_FOREACH; } foreach { RT; return TOKEN_FOREACH; }
foreach_active { RT; return TOKEN_FOREACH_ACTIVE; } foreach_active { RT; return TOKEN_FOREACH_ACTIVE; }
@@ -395,9 +400,11 @@ int8 { RT; return TOKEN_INT8; }
int16 { RT; return TOKEN_INT16; } int16 { RT; return TOKEN_INT16; }
int32 { RT; return TOKEN_INT; } int32 { RT; return TOKEN_INT; }
int64 { RT; return TOKEN_INT64; } int64 { RT; return TOKEN_INT64; }
integer { RT; return TOKEN_INTEGER; }
launch { RT; return TOKEN_LAUNCH; } launch { RT; return TOKEN_LAUNCH; }
new { RT; return TOKEN_NEW; } new { RT; return TOKEN_NEW; }
NULL { RT; return TOKEN_NULL; } NULL { RT; return TOKEN_NULL; }
number { RT; return TOKEN_NUMBER; }
print { RT; return TOKEN_PRINT; } print { RT; return TOKEN_PRINT; }
return { RT; return TOKEN_RETURN; } return { RT; return TOKEN_RETURN; }
soa { RT; return TOKEN_SOA; } soa { RT; return TOKEN_SOA; }
@@ -521,6 +528,7 @@ L?\"(\\.|[^\\"])*\" { lStringConst(&yylval, &yylloc); return TOKEN_STRING_LITERA
"^" { RT; return '^'; } "^" { RT; return '^'; }
"|" { RT; return '|'; } "|" { RT; return '|'; }
"?" { RT; return '?'; } "?" { RT; return '?'; }
"$" { RT; return '$'; }
{WHITESPACE} { } {WHITESPACE} { }

View File

@@ -1009,6 +1009,91 @@ Module::AddFunctionDeclaration(const std::string &name,
} }
} }
/* Handle Polymorphic functions
* a function
* int foo(number n, floating, f)
* will produce versions such as
* int foo(int n, float f)
*
* these functions will be overloaded if they are not exported, or mangled
* if exported */
std::set<const Type *, bool(*)(const Type*, const Type*)> toExpand(&PolyType::Less);
std::vector<const FunctionType *> expanded;
expanded.push_back(functionType);
for (int i=0; i<functionType->GetNumParameters(); i++) {
const Type *param = functionType->GetParameterType(i);
if (param->IsPolymorphicType() &&
!toExpand.count(param->GetBaseType())) {
toExpand.insert(param->GetBaseType());
}
}
std::vector<const FunctionType *> nextExpanded;
std::set<const Type*>::iterator iter;
for (iter = toExpand.begin(); iter != toExpand.end(); iter++) {
for (size_t j=0; j<expanded.size(); j++) {
const FunctionType *eft = expanded[j];
const PolyType *pt=CastType<PolyType>(*iter);
std::vector<AtomicType *>::iterator te;
for (te = pt->ExpandBegin(); te != pt->ExpandEnd(); te++) {
llvm::SmallVector<const Type *, 8> nargs;
llvm::SmallVector<std::string, 8> nargsn;
llvm::SmallVector<Expr *, 8> nargsd;
llvm::SmallVector<SourcePos, 8> nargsp;
for (size_t k=0; k<eft->GetNumParameters(); k++) {
if (Type::Equal(eft->GetParameterType(k)->GetBaseType(),
pt)) {
const Type *r;
r = PolyType::ReplaceType(eft->GetParameterType(k),*te);
nargs.push_back(r);
} else {
nargs.push_back(eft->GetParameterType(k));
}
nargsn.push_back(eft->GetParameterName(k));
nargsd.push_back(eft->GetParameterDefault(k));
nargsp.push_back(eft->GetParameterSourcePos(k));
}
nextExpanded.push_back(new FunctionType(eft->GetReturnType(),
nargs,
nargsn,
nargsd,
nargsp,
eft->isTask,
eft->isExported,
eft->isExternC,
eft->isUnmasked));
}
}
expanded.swap(nextExpanded);
nextExpanded.clear();
}
if (expanded.size() > 1) {
for (size_t i=0; i<expanded.size(); i++) {
std::string nname = name;
if (functionType->isExported || functionType->isExternC) {
for (int j=0; j<expanded[i]->GetNumParameters(); j++) {
nname += "_";
nname += expanded[i]->GetParameterType(j)->Mangle();
}
}
symbolTable->MapPolyFunction(name, nname, expanded[i]);
AddFunctionDeclaration(nname, expanded[i], storageClass,
isInline, pos);
}
return;
}
// Get the LLVM FunctionType // Get the LLVM FunctionType
bool disableMask = (storageClass == SC_EXTERN_C); bool disableMask = (storageClass == SC_EXTERN_C);
llvm::FunctionType *llvmFunctionType = llvm::FunctionType *llvmFunctionType =
@@ -1177,14 +1262,7 @@ Module::AddFunctionDefinition(const std::string &name, const FunctionType *type,
sym->pos = code->pos; sym->pos = code->pos;
// FIXME: because we encode the parameter names in the function type, ast->AddFunction(sym, code, symbolTable);
// we need to override the function type here in case the function had
// earlier been declared with anonymous parameter names but is now
// defined with actual names. This is yet another reason we shouldn't
// include the names in FunctionType...
sym->type = type;
ast->AddFunction(sym, code);
} }
@@ -1899,6 +1977,27 @@ lPrintFunctionDeclarations(FILE *file, const std::vector<Symbol *> &funcs,
// fprintf(file, "#ifdef __cplusplus\n} /* end extern C */\n#endif // __cplusplus\n"); // fprintf(file, "#ifdef __cplusplus\n} /* end extern C */\n#endif // __cplusplus\n");
} }
static void
lPrintPolyFunctionWrappers(FILE *file, const std::vector<std::string> &funcs) {
fprintf(file, "#if defined(__cplusplus)\n");
for (size_t i=0; i<funcs.size(); i++) {
std::vector<Symbol *> poly = m->symbolTable->LookupPolyFunction(funcs[i].c_str());
for (size_t j=0; j<poly.size(); j++) {
const FunctionType *ftype = CastType<FunctionType>(poly[j]->type);
Assert(ftype);
std::string decl = ftype->GetCDeclaration(funcs[i]);
fprintf(file, " %s {\n", decl.c_str());
std::string call = ftype->GetCCall(poly[j]->name);
fprintf(file, " return %s;\n }\n", call.c_str());
}
}
fprintf(file, "#endif // __cplusplus\n");
}
@@ -2275,8 +2374,10 @@ Module::writeHeader(const char *fn) {
// Collect single linear arrays of the exported and extern "C" // Collect single linear arrays of the exported and extern "C"
// functions // functions
std::vector<Symbol *> exportedFuncs, externCFuncs; std::vector<Symbol *> exportedFuncs, externCFuncs;
std::vector<std::string> polyFuncs;
m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs); m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
m->symbolTable->GetMatchingFunctions(lIsExternC, &externCFuncs); m->symbolTable->GetMatchingFunctions(lIsExternC, &externCFuncs);
m->symbolTable->GetPolyFunctions(&polyFuncs);
// Get all of the struct, vector, and enumerant types used as function // Get all of the struct, vector, and enumerant types used as function
// parameters. These vectors may have repeats. // parameters. These vectors may have repeats.
@@ -2313,6 +2414,16 @@ Module::writeHeader(const char *fn) {
fprintf(f, "///////////////////////////////////////////////////////////////////////////\n"); fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
lPrintFunctionDeclarations(f, exportedFuncs); lPrintFunctionDeclarations(f, exportedFuncs);
} }
// emit wrappers for polymorphic functions
if (polyFuncs.size() > 0) {
fprintf(f, "\n");
fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
fprintf(f, "// Polymorphic function wrappers\n");
fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
lPrintPolyFunctionWrappers(f, polyFuncs);
}
#if 0 #if 0
if (externCFuncs.size() > 0) { if (externCFuncs.size() > 0) {
fprintf(f, "\n"); fprintf(f, "\n");

View File

@@ -118,21 +118,20 @@ static void lFinalizeEnumeratorSymbols(std::vector<Symbol *> &enums,
const EnumType *enumType); const EnumType *enumType);
static const char *lBuiltinTokens[] = { static const char *lBuiltinTokens[] = {
"assert", "bool", "break", "case", "cdo", "assert", "bool", "break", "case", "cdo", "cfor", "cif", "cwhile", "const",
"cfor", "cif", "cwhile", "const", "continue", "default", "continue", "default", "do", "delete", "double", "else", "enum", "export",
"do", "delete", "double", "else", "enum", "export", "extern", "false", "extern", "false", "float", "floating", "for", "foreach", "foreach_active",
"float", "for", "foreach", "foreach_active", "foreach_tiled", "foreach_tiled", "foreach_unique", "goto", "if", "in", "inline", "int",
"foreach_unique", "goto", "if", "in", "inline", "int8", "int16", "int32", "int64", "integer", "launch", "new", "NULL",
"int", "int8", "int16", "int32", "int64", "launch", "new", "NULL", "number", "print", "return", "signed", "sizeof", "static", "struct",
"print", "return", "signed", "sizeof", "static", "struct", "switch", "switch", "sync", "task", "true", "typedef", "uniform", "unmasked",
"sync", "task", "true", "typedef", "uniform", "unmasked", "unsigned", "unsigned", "varying", "void", "while", NULL
"varying", "void", "while", NULL
}; };
static const char *lParamListTokens[] = { static const char *lParamListTokens[] = {
"bool", "const", "double", "enum", "false", "float", "int", "bool", "const", "double", "enum", "false", "float", "floating", "int",
"int8", "int16", "int32", "int64", "signed", "struct", "true", "int8", "int16", "int32", "int64", "integer", "number", "signed", "struct",
"uniform", "unsigned", "varying", "void", NULL "true", "uniform", "unsigned", "varying", "void", NULL
}; };
struct ForeachDimension { struct ForeachDimension {
@@ -159,6 +158,7 @@ struct ForeachDimension {
const Type *type; const Type *type;
std::vector<std::pair<const Type *, SourcePos> > *typeList; std::vector<std::pair<const Type *, SourcePos> > *typeList;
const AtomicType *atomicType; const AtomicType *atomicType;
const PolyType *polyType;
int typeQualifier; int typeQualifier;
StorageClass storageClass; StorageClass storageClass;
Stmt *stmt; Stmt *stmt;
@@ -198,6 +198,7 @@ struct ForeachDimension {
%token TOKEN_EXTERN TOKEN_EXPORT TOKEN_STATIC TOKEN_INLINE TOKEN_TASK TOKEN_DECLSPEC %token TOKEN_EXTERN TOKEN_EXPORT TOKEN_STATIC TOKEN_INLINE TOKEN_TASK TOKEN_DECLSPEC
%token TOKEN_UNIFORM TOKEN_VARYING TOKEN_TYPEDEF TOKEN_SOA TOKEN_UNMASKED %token TOKEN_UNIFORM TOKEN_VARYING TOKEN_TYPEDEF TOKEN_SOA TOKEN_UNMASKED
%token TOKEN_CHAR TOKEN_INT TOKEN_SIGNED TOKEN_UNSIGNED TOKEN_FLOAT TOKEN_DOUBLE %token TOKEN_CHAR TOKEN_INT TOKEN_SIGNED TOKEN_UNSIGNED TOKEN_FLOAT TOKEN_DOUBLE
%token TOKEN_INTEGER TOKEN_FLOATING TOKEN_NUMBER
%token TOKEN_INT8 TOKEN_INT16 TOKEN_INT64 TOKEN_CONST TOKEN_VOID TOKEN_BOOL %token TOKEN_INT8 TOKEN_INT16 TOKEN_INT64 TOKEN_CONST TOKEN_VOID TOKEN_BOOL
%token TOKEN_ENUM TOKEN_STRUCT TOKEN_TRUE TOKEN_FALSE %token TOKEN_ENUM TOKEN_STRUCT TOKEN_TRUE TOKEN_FALSE
@@ -244,6 +245,7 @@ struct ForeachDimension {
%type <type> short_vec_specifier %type <type> short_vec_specifier
%type <typeList> type_specifier_list %type <typeList> type_specifier_list
%type <atomicType> atomic_var_type_specifier %type <atomicType> atomic_var_type_specifier
%type <polyType> poly_type_specifier poly_quant_type_specifier
%type <typeQualifier> type_qualifier type_qualifier_list %type <typeQualifier> type_qualifier type_qualifier_list
%type <storageClass> storage_class_specifier %type <storageClass> storage_class_specifier
@@ -908,6 +910,7 @@ storage_class_specifier
type_specifier type_specifier
: atomic_var_type_specifier { $$ = $1; } : atomic_var_type_specifier { $$ = $1; }
| poly_quant_type_specifier { $$ = $1; }
| TOKEN_TYPE_NAME | TOKEN_TYPE_NAME
{ {
const Type *t = m->symbolTable->LookupType(yytext); const Type *t = m->symbolTable->LookupType(yytext);
@@ -950,6 +953,20 @@ atomic_var_type_specifier
| TOKEN_INT64 { $$ = AtomicType::UniformInt64->GetAsUnboundVariabilityType(); } | TOKEN_INT64 { $$ = AtomicType::UniformInt64->GetAsUnboundVariabilityType(); }
; ;
poly_type_specifier
: TOKEN_FLOATING { $$ = PolyType::UniformFloating->GetAsUnboundVariabilityType(); }
| TOKEN_INTEGER { $$ = PolyType::UniformInteger->GetAsUnboundVariabilityType(); }
| TOKEN_NUMBER { $$ = PolyType::UniformNumber->GetAsUnboundVariabilityType(); }
;
poly_quant_type_specifier
: poly_type_specifier '$' int_constant
{
$$ = $1->Quantify($3);
}
| poly_type_specifier { $$ = $1; }
;
short_vec_specifier short_vec_specifier
: atomic_var_type_specifier '<' int_constant '>' : atomic_var_type_specifier '<' int_constant '>'
{ {

View File

@@ -77,6 +77,11 @@ Stmt::Optimize() {
return this; return this;
} }
Stmt *
Stmt::ReplacePolyType(const PolyType *polyType, const Type *replacement) {
return this;
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// ExprStmt // ExprStmt
@@ -494,6 +499,18 @@ DeclStmt::TypeCheck() {
return encounteredError ? NULL : this; return encounteredError ? NULL : this;
} }
Stmt *
DeclStmt::ReplacePolyType(const PolyType *from, const Type *to) {
for (size_t i = 0; i < vars.size(); i++) {
Symbol *s = vars[i].sym;
if (Type::EqualForReplacement(s->type->GetBaseType(), from)) {
s->type = PolyType::ReplaceType(s->type, to);
}
}
return this;
}
void void
DeclStmt::Print(int indent) const { DeclStmt::Print(int indent) const {
@@ -2174,6 +2191,21 @@ ForeachStmt::TypeCheck() {
return anyErrors ? NULL : this; return anyErrors ? NULL : this;
} }
Stmt *
ForeachStmt::ReplacePolyType(const PolyType *from, const Type *to) {
if (!stmts)
return NULL;
for (size_t i=0; i<dimVariables.size(); i++) {
const Type *t = dimVariables[i]->type;
if (Type::EqualForReplacement(t->GetBaseType(), from)) {
t = PolyType::ReplaceType(t, to);
}
}
return this;
}
int int
ForeachStmt::EstimateCost() const { ForeachStmt::EstimateCost() const {

3
stmt.h
View File

@@ -70,6 +70,7 @@ public:
// Stmts don't have anything to do here. // Stmts don't have anything to do here.
virtual Stmt *Optimize(); virtual Stmt *Optimize();
virtual Stmt *TypeCheck() = 0; virtual Stmt *TypeCheck() = 0;
Stmt *ReplacePolyType(const PolyType *polyType, const Type *replacement);
}; };
@@ -117,6 +118,7 @@ public:
Stmt *Optimize(); Stmt *Optimize();
Stmt *TypeCheck(); Stmt *TypeCheck();
Stmt *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const; int EstimateCost() const;
std::vector<VariableDeclaration> vars; std::vector<VariableDeclaration> vars;
@@ -281,6 +283,7 @@ public:
void Print(int indent) const; void Print(int indent) const;
Stmt *TypeCheck(); Stmt *TypeCheck();
Stmt *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const; int EstimateCost() const;
std::vector<Symbol *> dimVariables; std::vector<Symbol *> dimVariables;

27
sym.cpp
View File

@@ -157,6 +157,14 @@ SymbolTable::AddFunction(Symbol *symbol) {
return true; return true;
} }
void
SymbolTable::MapPolyFunction(std::string name, std::string polyname,
const FunctionType *type) {
std::vector<Symbol *> &polyExpansions = polyFunctions[name];
SourcePos p;
polyExpansions.push_back(new Symbol(polyname, p, type, SC_NONE));
}
bool bool
SymbolTable::LookupFunction(const char *name, std::vector<Symbol *> *matches) { SymbolTable::LookupFunction(const char *name, std::vector<Symbol *> *matches) {
@@ -184,9 +192,28 @@ SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
return funcs[j]; return funcs[j];
} }
} }
// Try looking for a polymorphic function
if (polyFunctions[name].size() > 0) {
std::string n = name;
return new Symbol(name, polyFunctions[name][0]->pos, type);
}
return NULL; return NULL;
} }
std::vector<Symbol *>&
SymbolTable::LookupPolyFunction(const char *name) {
return polyFunctions[name];
}
void
SymbolTable::GetPolyFunctions(std::vector<std::string> *funcs) {
FunctionMapType::iterator it = polyFunctions.begin();
for (; it != polyFunctions.end(); it++) {
funcs->push_back(it->first);
}
}
bool bool
SymbolTable::AddType(const char *name, const Type *type, SourcePos pos) { SymbolTable::AddType(const char *name, const Type *type, SourcePos pos) {

15
sym.h
View File

@@ -108,6 +108,7 @@ public:
}; };
/** @brief Symbol table that holds all known symbols during parsing and compilation. /** @brief Symbol table that holds all known symbols during parsing and compilation.
A single instance of a SymbolTable is stored in the Module class A single instance of a SymbolTable is stored in the Module class
@@ -159,6 +160,14 @@ public:
already present in the symbol table. */ already present in the symbol table. */
bool AddFunction(Symbol *symbol); bool AddFunction(Symbol *symbol);
/** Adds the given function to the list of polymorphic definitions for the
given name
@param name The name of the original function
@param type The expanded FunctionType */
void MapPolyFunction(std::string name, std::string polyname,
const FunctionType *type);
/** Looks for the function or functions with the given name in the /** Looks for the function or functions with the given name in the
symbol name. If a function has been overloaded and multiple symbol name. If a function has been overloaded and multiple
definitions are present for a given function name, all of them will definitions are present for a given function name, all of them will
@@ -174,6 +183,10 @@ public:
@return pointer to matching Symbol; NULL if none is found. */ @return pointer to matching Symbol; NULL if none is found. */
Symbol *LookupFunction(const char *name, const FunctionType *type); Symbol *LookupFunction(const char *name, const FunctionType *type);
std::vector<Symbol *>& LookupPolyFunction(const char *name);
void GetPolyFunctions(std::vector<std::string> *funcs);
/** Returns all of the functions in the symbol table that match the given /** Returns all of the functions in the symbol table that match the given
predicate. predicate.
@@ -276,6 +289,8 @@ private:
typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType; typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType;
FunctionMapType functions; FunctionMapType functions;
FunctionMapType polyFunctions;
/** Type definitions can't currently be scoped. /** Type definitions can't currently be scoped.
*/ */
typedef std::map<std::string, const Type *> TypeMapType; typedef std::map<std::string, const Type *> TypeMapType;

13
tests_ispcpp/Makefile Normal file
View File

@@ -0,0 +1,13 @@
CXX=g++
CXXFLAGS=-std=c++11
ISPC=../ispc
ISPCFLAGS=--target=sse4-x2 -O2 --arch=x86-64
%.out : %.cpp %.o
$(CXX) $(CXXFLAGS) -o $@ $^
$ : $.o
%.o : %.ispc
$(ISPC) $(ISPCFLAGS) -h $*.h -o $*.o $<

View File

@@ -0,0 +1,6 @@
//@error
//assigning mismatched polymorphic types
export void foo(uniform floating$0 bar) {
floating$1 baz = bar;
}

View File

@@ -0,0 +1,6 @@
//@error
//assigning mismatched polymorphic types
export void foo(floating$0 bar) {
floating baz = bar;
}

View File

@@ -0,0 +1,6 @@
//@error
//assigning mismatched polymorphic types
export void foo(uniform floating$0 bar) {
integer baz = bar;
}

View File

@@ -0,0 +1,6 @@
//@error
//assigning mismatched polymorphic types
export void foo(number$0 bar) {
integer baz = bar;
}

19
tests_ispcpp/error_4.ispc Normal file
View File

@@ -0,0 +1,19 @@
//@error
// cannot determine return type for mult
floating mult(floating$0 x, floating$1 y) {
return x * y;
}
export void saxpy(uniform int N,
uniform floating$0 scale,
uniform floating$1 X[],
uniform floating$1 Y[],
uniform floating$2 result[])
{
foreach (i = 0 ... N) {
floating$2 tmp = mult(scale, X[i]) + Y[i];
result[i] = tmp;
}
}

View File

@@ -0,0 +1,17 @@
floating saxpy_helper(floating scale,
floating<0> x,
floating<0> y) {
return scale * x + y;
}
export void saxpy(uniform int N,
uniform floating<0> scale,
uniform floating<1> X[],
uniform floating<1> Y[],
uniform floating<2> result[])
{
foreach (i = 0 ... N) {
result[i] = saxpy_helper(scale, X[i], Y[i]);
}
}

View File

@@ -1,11 +1,11 @@
export void saxpy(uniform int N, export void saxpy(uniform int N,
uniform floating<0> scale, uniform floating$0 scale,
uniform floating<1> X[], uniform floating$1 X[],
uniform floating<1> Y[], uniform floating$1 Y[],
uniform floating<2> result[]) uniform floating$2 result[])
{ {
foreach (i = 0 ... N) { foreach (i = 0 ... N) {
floating<2> tmp = scale * X[i] + Y[i]; floating$2 tmp = scale * X[i] + Y[i];
result[i] = tmp; result[i] = tmp;
} }
} }

6
tests_ispcpp/simple.ispc Normal file
View File

@@ -0,0 +1,6 @@
export void foo(uniform int N, uniform floating$1 X[])
{
foreach (i = 0 ... N) {
X[i] = X[i] + 1.0;
}
}

527
type.cpp
View File

@@ -247,6 +247,20 @@ Type::IsVoidType() const {
return EqualIgnoringConst(this, AtomicType::Void); return EqualIgnoringConst(this, AtomicType::Void);
} }
bool
Type::IsPolymorphicType() const {
const FunctionType *ft = CastType<FunctionType>(this);
if (ft) {
for (int i=0; i<ft->GetNumParameters(); i++) {
if (ft->GetParameterType(i)->IsPolymorphicType())
return true;
}
return false;
}
return (CastType<PolyType>(GetBaseType()) != NULL);
}
bool bool
AtomicType::IsFloatType() const { AtomicType::IsFloatType() const {
return (basicType == TYPE_FLOAT || basicType == TYPE_DOUBLE); return (basicType == TYPE_FLOAT || basicType == TYPE_DOUBLE);
@@ -673,6 +687,452 @@ llvm::DIType *AtomicType::GetDIType(llvm::DIScope *scope) const {
} }
} }
///////////////////////////////////////////////////////////////////////////
// PolyType
const PolyType *PolyType::UniformInteger =
new PolyType(PolyType::TYPE_INTEGER, Variability::Uniform, false);
const PolyType *PolyType::VaryingInteger =
new PolyType(PolyType::TYPE_INTEGER, Variability::Varying, false);
const PolyType *PolyType::UniformFloating =
new PolyType(PolyType::TYPE_FLOATING, Variability::Uniform, false);
const PolyType *PolyType::VaryingFloating =
new PolyType(PolyType::TYPE_FLOATING, Variability::Varying, false);
const PolyType *PolyType::UniformNumber =
new PolyType(PolyType::TYPE_NUMBER, Variability::Uniform, false);
const PolyType *PolyType::VaryingNumber =
new PolyType(PolyType::TYPE_NUMBER, Variability::Varying, false);
const Type *
PolyType::ReplaceType(const Type *from, const Type *to) {
const Type *t = to;
if (from->IsPointerType()) {
t = new PointerType(to,
from->GetVariability(),
from->IsConstType());
} else if (from->IsArrayType()) {
t = new ArrayType(to,
CastType<ArrayType>(from)->GetElementCount());
} else if (from->IsReferenceType()) {
t = new ReferenceType(to);
}
if (from->IsVaryingType())
t = t->GetAsVaryingType();
fprintf(stderr, "Replacing type \"%s\" with \"%s\"\n",
from->GetString().c_str(),
t->GetString().c_str());
return t;
}
bool
PolyType::Less(const Type *a, const Type *b) {
const PolyType *pa = CastType<PolyType>(a->GetBaseType());
const PolyType *pb = CastType<PolyType>(b->GetBaseType());
if (!pa || !pb) {
char buf[1024];
snprintf(buf, 1024, "Calling lPolyTypeLess on non-polymorphic types"
"\"%s\" and \"%s\"\n",
a->GetString().c_str(), b->GetString().c_str());
FATAL(buf);
}
if (pa->restriction < pb->restriction)
return true;
if (pa->restriction > pb->restriction)
return false;
if (pa->GetQuant() < pb->GetQuant())
return true;
return false;
}
PolyType::PolyType(PolyRestriction r, Variability v, bool ic)
: Type(POLY_TYPE), restriction(r), variability(v), isConst(ic), quant(-1) {
asOtherConstType = NULL;
asUniformType = asVaryingType = NULL;
expandedTypes = NULL;
}
PolyType::PolyType(PolyRestriction r, Variability v, bool ic, int q)
: Type(POLY_TYPE), restriction(r), variability(v), isConst(ic), quant(q) {
asOtherConstType = NULL;
asUniformType = asVaryingType = NULL;
expandedTypes = NULL;
}
Variability
PolyType::GetVariability() const {
return variability;
}
int
PolyType::GetQuant() const {
return quant;
}
bool
PolyType::IsFloatType() const {
return (restriction == TYPE_FLOATING);
}
bool
PolyType::IsIntType() const {
return (restriction == TYPE_INTEGER);
}
bool
PolyType::IsUnsignedType() const {
return false;
}
bool
PolyType::IsBoolType() const {
return false;
}
bool
PolyType::IsConstType() const {
return isConst;
}
const PolyType *
PolyType::GetAsUnsignedType() const {
return NULL;
}
const PolyType *
PolyType::GetAsConstType() const {
if (isConst == true)
return this;
if (asOtherConstType == NULL) {
asOtherConstType = new PolyType(restriction, variability, true, quant);
asOtherConstType->asOtherConstType = this;
}
return asOtherConstType;
}
const PolyType *
PolyType::GetAsNonConstType() const {
if (isConst == false)
return this;
if (asOtherConstType == NULL) {
asOtherConstType = new PolyType(restriction, variability, false, quant);
asOtherConstType->asOtherConstType = this;
}
return asOtherConstType;
}
const PolyType *
PolyType::GetBaseType() const {
return this;
}
const PolyType *
PolyType::GetAsVaryingType() const {
if (variability == Variability::Varying)
return this;
if (asVaryingType == NULL) {
asVaryingType = new PolyType(restriction, Variability::Varying,
isConst, quant);
if (variability == Variability::Uniform)
asVaryingType->asUniformType = this;
}
return asVaryingType;
}
const PolyType *
PolyType::GetAsUniformType() const {
if (variability == Variability::Uniform)
return this;
if (asUniformType == NULL) {
asUniformType = new PolyType(restriction, Variability::Uniform,
isConst, quant);
if (variability == Variability::Varying)
asUniformType->asVaryingType = this;
}
return asUniformType;
}
const std::vector<AtomicType *>::iterator
PolyType::ExpandBegin() const {
if (expandedTypes)
return expandedTypes->begin();
expandedTypes = new std::vector<AtomicType *>();
if (restriction == TYPE_INTEGER || restriction == TYPE_NUMBER) {
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_INT8, variability, isConst));
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_UINT8, variability, isConst));
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_INT16, variability, isConst));
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_UINT16, variability, isConst));
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_INT32, variability, isConst));
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_UINT32, variability, isConst));
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_INT64, variability, isConst));
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_UINT64, variability, isConst));
}
if (restriction == TYPE_FLOATING || restriction == TYPE_NUMBER) {
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_FLOAT, variability, isConst));
expandedTypes->push_back(new AtomicType(AtomicType::TYPE_DOUBLE, variability, isConst));
}
return expandedTypes->begin();
}
const std::vector<AtomicType *>::iterator
PolyType::ExpandEnd() const {
Assert(expandedTypes != NULL);
return expandedTypes->end();
}
const PolyType *
PolyType::GetAsUnboundVariabilityType() const {
if (variability == Variability::Unbound)
return this;
return new PolyType(restriction, Variability::Unbound, isConst, quant);
}
const PolyType *
PolyType::GetAsSOAType(int width) const {
if (variability == Variability(Variability::SOA, width))
return this;
return new PolyType(restriction, Variability(Variability::SOA, width),
isConst, quant);
}
const PolyType *
PolyType::ResolveUnboundVariability(Variability v) const {
Assert(v != Variability::Unbound);
if (variability != Variability::Unbound)
return this;
return new PolyType(restriction, v, isConst, quant);
}
const PolyType *
PolyType::Quantify(int q) const {
return new PolyType(restriction, variability, isConst, q);
}
bool
PolyType::CanBeType(const Type *t) const {
const PolyType *pt = CastType<PolyType>(t);
if (pt) {
return (restriction == pt->restriction ||
restriction == TYPE_NUMBER);
}
const AtomicType *at = CastType<AtomicType>(t);
if (at) {
switch (restriction) {
case TYPE_INTEGER:
return at->IsIntType();
case TYPE_FLOATING:
return at->IsFloatType();
case TYPE_NUMBER:
return at->IsIntType() || at->IsFloatType();
default:
FATAL("Unmatched case for polymorphic restriction");
}
}
// not an atomic type or polymorphic type
return false;
}
std::string
PolyType::GetString() const {
std::string ret;
if (isConst) ret += "const ";
ret += variability.GetString();
ret += " ";
switch (restriction) {
case TYPE_INTEGER: ret += "integer"; break;
case TYPE_FLOATING: ret += "floating"; break;
case TYPE_NUMBER: ret += "number"; break;
default: FATAL("Logic error in PolyType::GetString()");
}
if (quant >= 0) {
ret += "$";
ret += std::to_string(quant);
}
return ret;
}
std::string
PolyType::Mangle() const {
std::string ret;
if (isConst) ret += "C";
ret += variability.MangleString();
switch (restriction) {
case TYPE_INTEGER: ret += "Z"; break;
case TYPE_FLOATING: ret += "Q"; break;
case TYPE_NUMBER: ret += "R"; break;
default: FATAL("Logic error in PolyType::Mangle()");
}
return ret;
}
std::string
PolyType::GetCDeclaration(const std::string &name) const {
std::string ret;
if (variability == Variability::Unbound) {
Assert(m->errorCount > 0);
return ret;
}
if (isConst) ret += "const ";
switch (restriction) {
case TYPE_INTEGER: ret += "int32_t"; break;
case TYPE_FLOATING: ret += "double"; break;
case TYPE_NUMBER: ret += "double"; break;
default: FATAL("Logic error in PolyType::GetCDeclaration()");
}
if (lShouldPrintName(name)) {
ret += " ";
ret += name;
}
if (variability == Variability::SOA) {
char buf[32];
sprintf(buf, "[%d]", variability.soaWidth);
ret += buf;
}
return ret;
}
llvm::Type *
PolyType::LLVMType(llvm::LLVMContext *ctx) const {
Assert(variability.type != Variability::Unbound);
bool isUniform = (variability == Variability::Uniform);
bool isVarying = (variability == Variability::Varying);
if (isUniform || isVarying) {
switch (restriction) {
case TYPE_INTEGER:
return isUniform ? LLVMTypes::Int32Type : LLVMTypes::Int32VectorType;
case TYPE_FLOATING:
case TYPE_NUMBER:
return isUniform ? LLVMTypes::DoubleType : LLVMTypes::DoubleVectorType;
default:
FATAL("logic error in PolyType::LLVMType");
return NULL;
}
}
else {
ArrayType at(GetAsUniformType(), variability.soaWidth);
return at.LLVMType(ctx);
}
}
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_6
llvm::DIType PolyType::GetDIType(llvm::DIDescriptor scope) const {
#else //LLVM 3.7++
llvm::DIType *PolyType::GetDIType(llvm::DIScope *scope) const {
#endif
Assert(variability.type != Variability::Unbound);
if (variability.type == Variability::Uniform) {
switch (restriction) {
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_9
case TYPE_INTEGER:
return m->diBuilder->createBasicType("int32", 32 /* size */, 32 /* align */,
llvm::dwarf::DW_ATE_signed);
break;
case TYPE_FLOATING:
case TYPE_NUMBER:
return m->diBuilder->createBasicType("double", 64 /* size */, 64 /* align */,
llvm::dwarf::DW_ATE_float);
break;
#else // LLVM 4.0+
case TYPE_INTEGER:
return m->diBuilder->createBasicType("int32", 32 /* size */,
llvm::dwarf::DW_ATE_signed);
break;
case TYPE_FLOATING:
case TYPE_NUMBER:
return m->diBuilder->createBasicType("double", 64 /* size */,
llvm::dwarf::DW_ATE_float);
break;
#endif
default:
FATAL("unhandled basic type in PolyType::GetDIType()");
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_6
return llvm::DIType();
#else //LLVM 3.7+
return NULL;
#endif
}
}
else if (variability == Variability::Varying) {
#if ISPC_LLVM_VERSION == ISPC_LLVM_3_2
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target->getVectorWidth()-1);
#elif ISPC_LLVM_VERSION > ISPC_VERSION_3_2 && ISPC_LLVM_VERSION <= ISPC_LLVM_3_5
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target->getVectorWidth());
#else // LLVM 3.6+
llvm::Metadata *sub = m->diBuilder->getOrCreateSubrange(0, g->target->getVectorWidth());
#endif
#if ISPC_LLVM_VERSION > ISPC_VERSION_3_2 && ISPC_LLVM_VERSION <= ISPC_LLVM_3_6
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub);
llvm::DIType unifType = GetAsUniformType()->GetDIType(scope);
uint64_t size = unifType.getSizeInBits() * g->target->getVectorWidth();
uint64_t align = unifType.getAlignInBits() * g->target->getVectorWidth();
#else // LLVM 3.7+
llvm::DINodeArray subArray = m->diBuilder->getOrCreateArray(sub);
llvm::DIType *unifType = GetAsUniformType()->GetDIType(scope);
//llvm::DebugNodeArray subArray = m->diBuilder->getOrCreateArray(sub);
//llvm::MDType *unifType = GetAsUniformType()->GetDIType(scope);
uint64_t size = unifType->getSizeInBits() * g->target->getVectorWidth();
uint64_t align = unifType->getAlignInBits()* g->target->getVectorWidth();
#endif
return m->diBuilder->createVectorType(size, align, unifType, subArray);
}
else {
Assert(variability == Variability::SOA);
ArrayType at(GetAsUniformType(), variability.soaWidth);
return at.GetDIType(scope);
}
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// EnumType // EnumType
@@ -3134,6 +3594,34 @@ FunctionType::GetCDeclaration(const std::string &fname) const {
return ret; return ret;
} }
std::string
FunctionType::GetCCall(const std::string &fname) const {
std::string ret;
ret += fname;
ret += "(";
for (unsigned int i = 0; i < paramTypes.size(); ++i) {
const Type *type = paramTypes[i];
// Convert pointers to arrays to unsized arrays, which are more clear
// to print out for multidimensional arrays (i.e. "float foo[][4] "
// versus "float (foo *)[4]").
const PointerType *pt = CastType<PointerType>(type);
if (pt != NULL &&
CastType<ArrayType>(pt->GetBaseType()) != NULL) {
type = new ArrayType(pt->GetBaseType(), 0);
}
if (paramNames[i] != "")
ret += paramNames[i];
else
FATAL("Exporting a polymorphic function with incomplete arguments");
if (i != paramTypes.size() - 1)
ret += ", ";
}
ret += ")";
return ret;
}
std::string std::string
FunctionType::GetCDeclarationForDispatch(const std::string &fname) const { FunctionType::GetCDeclarationForDispatch(const std::string &fname) const {
@@ -3554,6 +4042,24 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
} }
} }
const PolyType *pyt0 = CastType<PolyType>(t0);
const PolyType *pyt1 = CastType<PolyType>(t1);
if (pyt0 || pyt1) {
// one of the types is polymorphic
if (pyt0 && pyt0->CanBeType(t1)) {
return pyt0;
} else if (pyt1 && pyt1->CanBeType(t0)) {
return pyt1;
} else {
// polymorphic type cannot represent the other type
// this is most likely bad
Error(pos, "Polymorphic type incompatible for \"%s\" and \"%s\""
" for %s.", t0->GetString().c_str(),
t1->GetString().c_str(), reason);
}
}
// Now all we can do is promote atomic types... // Now all we can do is promote atomic types...
if (at0 == NULL || at1 == NULL) { if (at0 == NULL || at1 == NULL) {
Assert(reason != NULL); Assert(reason != NULL);
@@ -3592,6 +4098,14 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
(ata->GetVariability() == atb->GetVariability())); (ata->GetVariability() == atb->GetVariability()));
} }
const PolyType *pyta = CastType<PolyType>(a);
const PolyType *pytb = CastType<PolyType>(b);
if (pyta != NULL && pytb != NULL) {
return ((pyta->restriction == pytb->restriction) &&
(pyta->GetVariability() == pytb->GetVariability()) &&
(pyta->GetQuant() == pytb->GetQuant()));
}
// For all of the other types, we need to see if we have the same two // For all of the other types, we need to see if we have the same two
// general types. If so, then we dig into the details of the type and // general types. If so, then we dig into the details of the type and
// see if all of the relevant bits are equal... // see if all of the relevant bits are equal...
@@ -3688,3 +4202,16 @@ bool
Type::EqualIgnoringConst(const Type *a, const Type *b) { Type::EqualIgnoringConst(const Type *a, const Type *b) {
return lCheckTypeEquality(a, b, true); return lCheckTypeEquality(a, b, true);
} }
bool
Type::EqualForReplacement(const Type *a, const Type *b) {
const PolyType *pa = CastType<PolyType>(a);
const PolyType *pb = CastType<PolyType>(b);
if (!pa || !pb)
return false;
return pa->restriction == pb->restriction &&
pa->GetQuant() == pb->GetQuant();
}

89
type.h
View File

@@ -89,7 +89,8 @@ enum TypeId {
STRUCT_TYPE, // 5 STRUCT_TYPE, // 5
UNDEFINED_STRUCT_TYPE, // 6 UNDEFINED_STRUCT_TYPE, // 6
REFERENCE_TYPE, // 7 REFERENCE_TYPE, // 7
FUNCTION_TYPE // 8 FUNCTION_TYPE, // 8
POLY_TYPE // 9
}; };
@@ -132,6 +133,9 @@ public:
/** Returns true if the underlying type is either a pointer or an array */ /** Returns true if the underlying type is either a pointer or an array */
bool IsVoidType() const; bool IsVoidType() const;
/** Returns true if the underlying type is polymorphic */
bool IsPolymorphicType() const;
/** Returns true if this type is 'const'-qualified. */ /** Returns true if this type is 'const'-qualified. */
virtual bool IsConstType() const = 0; virtual bool IsConstType() const = 0;
@@ -240,6 +244,8 @@ public:
the same (ignoring const-ness of the type), false otherwise. */ the same (ignoring const-ness of the type), false otherwise. */
static bool EqualIgnoringConst(const Type *a, const Type *b); static bool EqualIgnoringConst(const Type *a, const Type *b);
static bool EqualForReplacement(const Type *a, const Type *b);
/** Given two types, returns the least general Type that is more general /** Given two types, returns the least general Type that is more general
than both of them. (i.e. that can represent their values without than both of them. (i.e. that can represent their values without
any loss of data.) If there is no such Type, return NULL. any loss of data.) If there is no such Type, return NULL.
@@ -356,14 +362,84 @@ public:
static const AtomicType *UniformDouble, *VaryingDouble; static const AtomicType *UniformDouble, *VaryingDouble;
static const AtomicType *Void; static const AtomicType *Void;
AtomicType(BasicType basicType, Variability v, bool isConst);
private: private:
const Variability variability; const Variability variability;
const bool isConst; const bool isConst;
AtomicType(BasicType basicType, Variability v, bool isConst);
mutable const AtomicType *asOtherConstType, *asUniformType, *asVaryingType; mutable const AtomicType *asOtherConstType, *asUniformType, *asVaryingType;
}; };
class PolyType : public Type {
public:
Variability GetVariability() const;
int GetQuant() const;
bool IsBoolType() const;
bool IsFloatType() const;
bool IsIntType() const;
bool IsUnsignedType() const;
bool IsConstType() const;
const PolyType *GetBaseType() const;
const PolyType *GetAsUniformType() const;
const PolyType *GetAsVaryingType() const;
const PolyType *GetAsUnboundVariabilityType() const;
const PolyType *GetAsSOAType(int width) const;
const PolyType *ResolveUnboundVariability(Variability v) const;
const PolyType *GetAsUnsignedType() const;
const PolyType *GetAsConstType() const;
const PolyType *GetAsNonConstType() const;
const PolyType *Quantify(int quant) const;
bool CanBeType(const Type *t) const;
std::string GetString() const;
std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const;
llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_6
llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
#else // LLVM 3.7++
llvm::DIType *GetDIType(llvm::DIScope *scope) const;
#endif
enum PolyRestriction {
TYPE_INTEGER,
TYPE_FLOATING,
TYPE_NUMBER
};
const PolyRestriction restriction;
static const Type * ReplaceType(const Type *from, const Type *to);
static bool Less(const Type *a, const Type *b);
static const PolyType *UniformInteger, *VaryingInteger;
static const PolyType *UniformFloating, *VaryingFloating;
static const PolyType *UniformNumber, *VaryingNumber;
// Returns the list of AtomicTypes that are valid instantiations of the
// polymorphic type
const std::vector<AtomicType *>::iterator ExpandBegin() const;
const std::vector<AtomicType *>::iterator ExpandEnd() const;
private:
const Variability variability;
const bool isConst;
const int quant;
PolyType(PolyRestriction type, Variability v, bool isConst);
PolyType(PolyRestriction type, Variability v, bool isConst, int quant);
mutable const PolyType *asOtherConstType, *asUniformType, *asVaryingType;
mutable std::vector<AtomicType *> *expandedTypes;
};
/** @brief Type implementation for enumerated types /** @brief Type implementation for enumerated types
*/ */
@@ -912,6 +988,7 @@ public:
std::string GetString() const; std::string GetString() const;
std::string Mangle() const; std::string Mangle() const;
std::string GetCDeclaration(const std::string &fname) const; std::string GetCDeclaration(const std::string &fname) const;
std::string GetCCall(const std::string &fname) const;
std::string GetCDeclarationForDispatch(const std::string &fname) const; std::string GetCDeclarationForDispatch(const std::string &fname) const;
llvm::Type *LLVMType(llvm::LLVMContext *ctx) const; llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
@@ -1002,6 +1079,14 @@ CastType(const Type *type) {
return NULL; return NULL;
} }
template <> inline const PolyType *
CastType(const Type *type) {
if (type != NULL && type->typeId == POLY_TYPE)
return (const PolyType *)type;
else
return NULL;
}
template <> inline const EnumType * template <> inline const EnumType *
CastType(const Type *type) { CastType(const Type *type) {
if (type != NULL && type->typeId == ENUM_TYPE) if (type != NULL && type->typeId == ENUM_TYPE)