30 Commits

Author SHA1 Message Date
5e6f06cf59 Fixed issue with aliasing local variables
ISPC++ now produces valid code, or an appropriate error message, for all
of my test cases.
2017-05-11 15:42:11 -04:00
bfe723e1b7 Actually copy the AST.
Type replacement works except for function parameters.
2017-05-11 03:09:38 -04:00
f65b3e6300 [WIP] Remove cases for ForeachStmt and SymbolExpr 2017-05-11 01:19:50 -04:00
2e28640860 Merge branch 'master' into copy_ast 2017-05-10 23:13:40 -04:00
d020107d91 Typechecking fixes, moved some printing behind debug flag 2017-05-10 23:12:48 -04:00
ab29965d75 force add cpp file for test 2017-05-10 14:25:39 -04:00
64e1e2b008 Generate overloaded function definitions 2017-05-10 14:21:09 -04:00
6a91c5d5ac Attempt to replicate AST when expanding polytypes 2017-05-10 11:11:39 -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
32 changed files with 1746 additions and 311 deletions

5
.gitignore vendored
View File

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

158
ast.cpp
View File

@@ -42,8 +42,11 @@
#include "func.h"
#include "stmt.h"
#include "sym.h"
#include "type.h"
#include "util.h"
#include <map>
///////////////////////////////////////////////////////////////////////////
// ASTNode
@@ -55,10 +58,21 @@ ASTNode::~ASTNode() {
// AST
void
AST::AddFunction(Symbol *sym, Stmt *code) {
AST::AddFunction(Symbol *sym, Stmt *code, SymbolTable *symbolTable) {
if (sym == NULL)
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);
}
}
@@ -72,7 +86,7 @@ AST::GenerateIR() {
ASTNode *
WalkAST(ASTNode *node, ASTPreCallBackFunc preFunc, ASTPostCallBackFunc postFunc,
void *data) {
void *data, ASTPostCallBackFunc preUpdate) {
if (node == NULL)
return node;
@@ -83,6 +97,10 @@ WalkAST(ASTNode *node, ASTPreCallBackFunc preFunc, ASTPostCallBackFunc postFunc,
return node;
}
if (preUpdate != NULL) {
node = preUpdate(node, data);
}
////////////////////////////////////////////////////////////////////////////
// Handle Statements
if (llvm::dyn_cast<Stmt>(node) != NULL) {
@@ -106,54 +124,54 @@ WalkAST(ASTNode *node, ASTPreCallBackFunc preFunc, ASTPostCallBackFunc postFunc,
UnmaskedStmt *ums;
if ((es = llvm::dyn_cast<ExprStmt>(node)) != NULL)
es->expr = (Expr *)WalkAST(es->expr, preFunc, postFunc, data);
es->expr = (Expr *)WalkAST(es->expr, preFunc, postFunc, data, preUpdate);
else if ((ds = llvm::dyn_cast<DeclStmt>(node)) != NULL) {
for (unsigned int i = 0; i < ds->vars.size(); ++i)
ds->vars[i].init = (Expr *)WalkAST(ds->vars[i].init, preFunc,
postFunc, data);
postFunc, data, preUpdate);
}
else if ((is = llvm::dyn_cast<IfStmt>(node)) != NULL) {
is->test = (Expr *)WalkAST(is->test, preFunc, postFunc, data);
is->test = (Expr *)WalkAST(is->test, preFunc, postFunc, data, preUpdate);
is->trueStmts = (Stmt *)WalkAST(is->trueStmts, preFunc,
postFunc, data);
postFunc, data, preUpdate);
is->falseStmts = (Stmt *)WalkAST(is->falseStmts, preFunc,
postFunc, data);
postFunc, data, preUpdate);
}
else if ((dos = llvm::dyn_cast<DoStmt>(node)) != NULL) {
dos->testExpr = (Expr *)WalkAST(dos->testExpr, preFunc,
postFunc, data);
postFunc, data, preUpdate);
dos->bodyStmts = (Stmt *)WalkAST(dos->bodyStmts, preFunc,
postFunc, data);
postFunc, data, preUpdate);
}
else if ((fs = llvm::dyn_cast<ForStmt>(node)) != NULL) {
fs->init = (Stmt *)WalkAST(fs->init, preFunc, postFunc, data);
fs->test = (Expr *)WalkAST(fs->test, preFunc, postFunc, data);
fs->step = (Stmt *)WalkAST(fs->step, preFunc, postFunc, data);
fs->stmts = (Stmt *)WalkAST(fs->stmts, preFunc, postFunc, data);
fs->init = (Stmt *)WalkAST(fs->init, preFunc, postFunc, data, preUpdate);
fs->test = (Expr *)WalkAST(fs->test, preFunc, postFunc, data, preUpdate);
fs->step = (Stmt *)WalkAST(fs->step, preFunc, postFunc, data, preUpdate);
fs->stmts = (Stmt *)WalkAST(fs->stmts, preFunc, postFunc, data, preUpdate);
}
else if ((fes = llvm::dyn_cast<ForeachStmt>(node)) != NULL) {
for (unsigned int i = 0; i < fes->startExprs.size(); ++i)
fes->startExprs[i] = (Expr *)WalkAST(fes->startExprs[i], preFunc,
postFunc, data);
postFunc, data, preUpdate);
for (unsigned int i = 0; i < fes->endExprs.size(); ++i)
fes->endExprs[i] = (Expr *)WalkAST(fes->endExprs[i], preFunc,
postFunc, data);
fes->stmts = (Stmt *)WalkAST(fes->stmts, preFunc, postFunc, data);
postFunc, data, preUpdate);
fes->stmts = (Stmt *)WalkAST(fes->stmts, preFunc, postFunc, data, preUpdate);
}
else if ((fas = llvm::dyn_cast<ForeachActiveStmt>(node)) != NULL) {
fas->stmts = (Stmt *)WalkAST(fas->stmts, preFunc, postFunc, data);
fas->stmts = (Stmt *)WalkAST(fas->stmts, preFunc, postFunc, data, preUpdate);
}
else if ((fus = llvm::dyn_cast<ForeachUniqueStmt>(node)) != NULL) {
fus->expr = (Expr *)WalkAST(fus->expr, preFunc, postFunc, data);
fus->stmts = (Stmt *)WalkAST(fus->stmts, preFunc, postFunc, data);
fus->expr = (Expr *)WalkAST(fus->expr, preFunc, postFunc, data, preUpdate);
fus->stmts = (Stmt *)WalkAST(fus->stmts, preFunc, postFunc, data, preUpdate);
}
else if ((cs = llvm::dyn_cast<CaseStmt>(node)) != NULL)
cs->stmts = (Stmt *)WalkAST(cs->stmts, preFunc, postFunc, data);
cs->stmts = (Stmt *)WalkAST(cs->stmts, preFunc, postFunc, data, preUpdate);
else if ((defs = llvm::dyn_cast<DefaultStmt>(node)) != NULL)
defs->stmts = (Stmt *)WalkAST(defs->stmts, preFunc, postFunc, data);
defs->stmts = (Stmt *)WalkAST(defs->stmts, preFunc, postFunc, data, preUpdate);
else if ((ss = llvm::dyn_cast<SwitchStmt>(node)) != NULL) {
ss->expr = (Expr *)WalkAST(ss->expr, preFunc, postFunc, data);
ss->stmts = (Stmt *)WalkAST(ss->stmts, preFunc, postFunc, data);
ss->expr = (Expr *)WalkAST(ss->expr, preFunc, postFunc, data, preUpdate);
ss->stmts = (Stmt *)WalkAST(ss->stmts, preFunc, postFunc, data, preUpdate);
}
else if (llvm::dyn_cast<BreakStmt>(node) != NULL ||
llvm::dyn_cast<ContinueStmt>(node) != NULL ||
@@ -161,22 +179,22 @@ WalkAST(ASTNode *node, ASTPreCallBackFunc preFunc, ASTPostCallBackFunc postFunc,
// nothing
}
else if ((ls = llvm::dyn_cast<LabeledStmt>(node)) != NULL)
ls->stmt = (Stmt *)WalkAST(ls->stmt, preFunc, postFunc, data);
ls->stmt = (Stmt *)WalkAST(ls->stmt, preFunc, postFunc, data, preUpdate);
else if ((rs = llvm::dyn_cast<ReturnStmt>(node)) != NULL)
rs->expr = (Expr *)WalkAST(rs->expr, preFunc, postFunc, data);
rs->expr = (Expr *)WalkAST(rs->expr, preFunc, postFunc, data, preUpdate);
else if ((sl = llvm::dyn_cast<StmtList>(node)) != NULL) {
std::vector<Stmt *> &sls = sl->stmts;
for (unsigned int i = 0; i < sls.size(); ++i)
sls[i] = (Stmt *)WalkAST(sls[i], preFunc, postFunc, data);
sls[i] = (Stmt *)WalkAST(sls[i], preFunc, postFunc, data, preUpdate);
}
else if ((ps = llvm::dyn_cast<PrintStmt>(node)) != NULL)
ps->values = (Expr *)WalkAST(ps->values, preFunc, postFunc, data);
ps->values = (Expr *)WalkAST(ps->values, preFunc, postFunc, data, preUpdate);
else if ((as = llvm::dyn_cast<AssertStmt>(node)) != NULL)
as->expr = (Expr *)WalkAST(as->expr, preFunc, postFunc, data);
as->expr = (Expr *)WalkAST(as->expr, preFunc, postFunc, data, preUpdate);
else if ((dels = llvm::dyn_cast<DeleteStmt>(node)) != NULL)
dels->expr = (Expr *)WalkAST(dels->expr, preFunc, postFunc, data);
dels->expr = (Expr *)WalkAST(dels->expr, preFunc, postFunc, data, preUpdate);
else if ((ums = llvm::dyn_cast<UnmaskedStmt>(node)) != NULL)
ums->stmts = (Stmt *)WalkAST(ums->stmts, preFunc, postFunc, data);
ums->stmts = (Stmt *)WalkAST(ums->stmts, preFunc, postFunc, data, preUpdate);
else
FATAL("Unhandled statement type in WalkAST()");
}
@@ -201,57 +219,57 @@ WalkAST(ASTNode *node, ASTPreCallBackFunc preFunc, ASTPostCallBackFunc postFunc,
NewExpr *newe;
if ((ue = llvm::dyn_cast<UnaryExpr>(node)) != NULL)
ue->expr = (Expr *)WalkAST(ue->expr, preFunc, postFunc, data);
ue->expr = (Expr *)WalkAST(ue->expr, preFunc, postFunc, data, preUpdate);
else if ((be = llvm::dyn_cast<BinaryExpr>(node)) != NULL) {
be->arg0 = (Expr *)WalkAST(be->arg0, preFunc, postFunc, data);
be->arg1 = (Expr *)WalkAST(be->arg1, preFunc, postFunc, data);
be->arg0 = (Expr *)WalkAST(be->arg0, preFunc, postFunc, data, preUpdate);
be->arg1 = (Expr *)WalkAST(be->arg1, preFunc, postFunc, data, preUpdate);
}
else if ((ae = llvm::dyn_cast<AssignExpr>(node)) != NULL) {
ae->lvalue = (Expr *)WalkAST(ae->lvalue, preFunc, postFunc, data);
ae->rvalue = (Expr *)WalkAST(ae->rvalue, preFunc, postFunc, data);
ae->lvalue = (Expr *)WalkAST(ae->lvalue, preFunc, postFunc, data, preUpdate);
ae->rvalue = (Expr *)WalkAST(ae->rvalue, preFunc, postFunc, data, preUpdate);
}
else if ((se = llvm::dyn_cast<SelectExpr>(node)) != NULL) {
se->test = (Expr *)WalkAST(se->test, preFunc, postFunc, data);
se->expr1 = (Expr *)WalkAST(se->expr1, preFunc, postFunc, data);
se->expr2 = (Expr *)WalkAST(se->expr2, preFunc, postFunc, data);
se->test = (Expr *)WalkAST(se->test, preFunc, postFunc, data, preUpdate);
se->expr1 = (Expr *)WalkAST(se->expr1, preFunc, postFunc, data, preUpdate);
se->expr2 = (Expr *)WalkAST(se->expr2, preFunc, postFunc, data, preUpdate);
}
else if ((el = llvm::dyn_cast<ExprList>(node)) != NULL) {
for (unsigned int i = 0; i < el->exprs.size(); ++i)
el->exprs[i] = (Expr *)WalkAST(el->exprs[i], preFunc,
postFunc, data);
postFunc, data, preUpdate);
}
else if ((fce = llvm::dyn_cast<FunctionCallExpr>(node)) != NULL) {
fce->func = (Expr *)WalkAST(fce->func, preFunc, postFunc, data);
fce->args = (ExprList *)WalkAST(fce->args, preFunc, postFunc, data);
fce->func = (Expr *)WalkAST(fce->func, preFunc, postFunc, data, preUpdate);
fce->args = (ExprList *)WalkAST(fce->args, preFunc, postFunc, data, preUpdate);
for (int k = 0; k < 3; k++)
fce->launchCountExpr[0] = (Expr *)WalkAST(fce->launchCountExpr[0], preFunc,
postFunc, data);
postFunc, data, preUpdate);
}
else if ((ie = llvm::dyn_cast<IndexExpr>(node)) != NULL) {
ie->baseExpr = (Expr *)WalkAST(ie->baseExpr, preFunc, postFunc, data);
ie->index = (Expr *)WalkAST(ie->index, preFunc, postFunc, data);
ie->baseExpr = (Expr *)WalkAST(ie->baseExpr, preFunc, postFunc, data, preUpdate);
ie->index = (Expr *)WalkAST(ie->index, preFunc, postFunc, data, preUpdate);
}
else if ((me = llvm::dyn_cast<MemberExpr>(node)) != NULL)
me->expr = (Expr *)WalkAST(me->expr, preFunc, postFunc, data);
me->expr = (Expr *)WalkAST(me->expr, preFunc, postFunc, data, preUpdate);
else if ((tce = llvm::dyn_cast<TypeCastExpr>(node)) != NULL)
tce->expr = (Expr *)WalkAST(tce->expr, preFunc, postFunc, data);
tce->expr = (Expr *)WalkAST(tce->expr, preFunc, postFunc, data, preUpdate);
else if ((re = llvm::dyn_cast<ReferenceExpr>(node)) != NULL)
re->expr = (Expr *)WalkAST(re->expr, preFunc, postFunc, data);
re->expr = (Expr *)WalkAST(re->expr, preFunc, postFunc, data, preUpdate);
else if ((ptrderef = llvm::dyn_cast<PtrDerefExpr>(node)) != NULL)
ptrderef->expr = (Expr *)WalkAST(ptrderef->expr, preFunc, postFunc,
data);
data, preUpdate);
else if ((refderef = llvm::dyn_cast<RefDerefExpr>(node)) != NULL)
refderef->expr = (Expr *)WalkAST(refderef->expr, preFunc, postFunc,
data);
data, preUpdate);
else if ((soe = llvm::dyn_cast<SizeOfExpr>(node)) != NULL)
soe->expr = (Expr *)WalkAST(soe->expr, preFunc, postFunc, data);
soe->expr = (Expr *)WalkAST(soe->expr, preFunc, postFunc, data, preUpdate);
else if ((aoe = llvm::dyn_cast<AddressOfExpr>(node)) != NULL)
aoe->expr = (Expr *)WalkAST(aoe->expr, preFunc, postFunc, data);
aoe->expr = (Expr *)WalkAST(aoe->expr, preFunc, postFunc, data, preUpdate);
else if ((newe = llvm::dyn_cast<NewExpr>(node)) != NULL) {
newe->countExpr = (Expr *)WalkAST(newe->countExpr, preFunc,
postFunc, data);
postFunc, data, preUpdate);
newe->initExpr = (Expr *)WalkAST(newe->initExpr, preFunc,
postFunc, data);
postFunc, data, preUpdate);
}
else if (llvm::dyn_cast<SymbolExpr>(node) != NULL ||
llvm::dyn_cast<ConstExpr>(node) != NULL ||
@@ -508,3 +526,35 @@ SafeToRunWithMaskAllOff(ASTNode *root) {
WalkAST(root, lCheckAllOffSafety, NULL, &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);
}
static ASTNode *
lCopyNode(ASTNode *node, void *) {
return node->Copy();
}
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, lCopyNode);
}
ASTNode *
CopyAST(ASTNode *root) {
return WalkAST(root, NULL, NULL, NULL, lCopyNode);
}

14
ast.h
View File

@@ -39,6 +39,7 @@
#define ISPC_AST_H 1
#include "ispc.h"
#include "type.h"
#include <vector>
/** @brief Abstract base class for nodes in the abstract syntax tree (AST).
@@ -67,6 +68,10 @@ public:
pointer in place of the original ASTNode *. */
virtual ASTNode *TypeCheck() = 0;
virtual ASTNode *Copy() = 0;
virtual ASTNode *ReplacePolyType(const PolyType *, const Type *) = 0;
/** Estimate the execution cost of the node (not including the cost of
the children. The value returned should be based on the COST_*
enumerant values defined in ispc.h. */
@@ -145,7 +150,7 @@ class AST {
public:
/** Add the AST for a function described by the given declaration
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
module. */
@@ -174,7 +179,8 @@ typedef ASTNode * (* ASTPostCallBackFunc)(ASTNode *node, void *data);
doing so, calls postFunc, at the node. The return value from the
postFunc call is ignored. */
extern ASTNode *WalkAST(ASTNode *root, ASTPreCallBackFunc preFunc,
ASTPostCallBackFunc postFunc, void *data);
ASTPostCallBackFunc postFunc, void *data,
ASTPostCallBackFunc preUpdate = NULL);
/** Perform simple optimizations on the AST or portion thereof passed to
this function, returning the resulting AST. */
@@ -204,6 +210,10 @@ extern Stmt *TypeCheck(Stmt *);
the given root. */
extern int EstimateCost(ASTNode *root);
extern ASTNode * TranslatePoly(ASTNode *root, const PolyType *polyType, const Type *replacement);
extern ASTNode * CopyAST(ASTNode *root);
/** Returns true if it would be safe to run the given code with an "all
off" mask. */
extern bool SafeToRunWithMaskAllOff(ASTNode *root);

View File

@@ -1927,6 +1927,11 @@ FunctionEmitContext::BinaryOperator(llvm::Instruction::BinaryOps inst,
return NULL;
}
if (v0->getType() != v1->getType()) {
v0->dump();
printf("\n\n");
v1->dump();
}
AssertPos(currentPos, v0->getType() == v1->getType());
llvm::Type *type = v0->getType();
int arraySize = lArrayVectorWidth(type);

248
expr.cpp
View File

@@ -112,6 +112,85 @@ Expr::GetBaseSymbol() const {
return NULL;
}
Expr *
Expr::Copy() {
Expr *copy;
switch (getValueID()) {
case AddressOfExprID:
copy = (Expr*)new AddressOfExpr(*(AddressOfExpr*)this);
break;
case AssignExprID:
copy = (Expr*)new AssignExpr(*(AssignExpr*)this);
break;
case BinaryExprID:
copy = (Expr*)new BinaryExpr(*(BinaryExpr*)this);
break;
case ConstExprID:
copy = (Expr*)new ConstExpr(*(ConstExpr*)this);
break;
case PtrDerefExprID:
copy = (Expr*)new PtrDerefExpr(*(PtrDerefExpr*)this);
break;
case RefDerefExprID:
copy = (Expr*)new RefDerefExpr(*(RefDerefExpr*)this);
break;
case ExprListID:
copy = (Expr*)new ExprList(*(ExprList*)this);
break;
case FunctionCallExprID:
copy = (Expr*)new FunctionCallExpr(*(FunctionCallExpr*)this);
break;
case FunctionSymbolExprID:
copy = (Expr*)new FunctionSymbolExpr(*(FunctionSymbolExpr*)this);
break;
case IndexExprID:
copy = (Expr*)new IndexExpr(*(IndexExpr*)this);
break;
case StructMemberExprID:
copy = (Expr*)new StructMemberExpr(*(StructMemberExpr*)this);
break;
case VectorMemberExprID:
copy = (Expr*)new VectorMemberExpr(*(VectorMemberExpr*)this);
break;
case NewExprID:
copy = (Expr*)new NewExpr(*(NewExpr*)this);
break;
case NullPointerExprID:
copy = (Expr*)new NullPointerExpr(*(NullPointerExpr*)this);
break;
case ReferenceExprID:
copy = (Expr*)new ReferenceExpr(*(ReferenceExpr*)this);
break;
case SelectExprID:
copy = (Expr*)new SelectExpr(*(SelectExpr*)this);
break;
case SizeOfExprID:
copy = (Expr*)new SizeOfExpr(*(SizeOfExpr*)this);
break;
case SymbolExprID:
copy = (Expr*)new SymbolExpr(*(SymbolExpr*)this);
break;
case SyncExprID:
copy = (Expr*)new SyncExpr(*(SyncExpr*)this);
break;
case TypeCastExprID:
copy = (Expr*)new TypeCastExpr(*(TypeCastExpr*)this);
break;
case UnaryExprID:
copy = (Expr*)new UnaryExpr(*(UnaryExpr*)this);
break;
default:
FATAL("Unmatched case in Expr::Copy");
copy = this; // just to silence the compiler
}
return copy;
}
Expr *
Expr::ReplacePolyType(const PolyType *, const Type *) {
return this;
}
#if 0
/** If a conversion from 'fromAtomicType' to 'toAtomicType' may cause lost
@@ -276,6 +355,8 @@ lDoTypeConv(const Type *fromType, const Type *toType, Expr **expr,
const AtomicType *fromAtomicType = CastType<AtomicType>(fromType);
const PointerType *fromPointerType = CastType<PointerType>(fromType);
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
// "float foo[10]" -> "float * uniform foo", we have what's seemingly
@@ -544,6 +625,21 @@ lDoTypeConv(const Type *fromType, const Type *toType, Expr **expr,
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);
}
return false;
}
}
// from here on out, the from type can only be atomic something or
// other...
if (fromAtomicType == NULL) {
@@ -4653,6 +4749,23 @@ IndexExpr::TypeCheck() {
return this;
}
Expr *
IndexExpr::ReplacePolyType(const PolyType *from, const Type *to) {
if (index == NULL || baseExpr == NULL)
return NULL;
if (Type::EqualForReplacement(GetType()->GetBaseType(), from)) {
type = PolyType::ReplaceType(type, to);
}
if (Type::EqualForReplacement(GetLValueType()->GetBaseType(), from)) {
lvalueType = new PointerType(to, lvalueType->GetVariability(),
lvalueType->IsConstType());
}
return this;
}
int
IndexExpr::EstimateCost() const {
@@ -4718,27 +4831,6 @@ lIdentifierToVectorElement(char id) {
//////////////////////////////////////////////////
// StructMemberExpr
class StructMemberExpr : public MemberExpr
{
public:
StructMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, bool derefLValue);
static inline bool classof(StructMemberExpr const*) { return true; }
static inline bool classof(ASTNode const* N) {
return N->getValueID() == StructMemberExprID;
}
const Type *GetType() const;
const Type *GetLValueType() const;
int getElementNumber() const;
const Type *getElementType() const;
private:
const StructType *getStructType() const;
};
StructMemberExpr::StructMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, bool derefLValue)
: MemberExpr(e, id, p, idpos, derefLValue, StructMemberExprID) {
@@ -4890,31 +4982,6 @@ StructMemberExpr::getStructType() const {
//////////////////////////////////////////////////
// VectorMemberExpr
class VectorMemberExpr : public MemberExpr
{
public:
VectorMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, bool derefLValue);
static inline bool classof(VectorMemberExpr const*) { return true; }
static inline bool classof(ASTNode const* N) {
return N->getValueID() == VectorMemberExprID;
}
llvm::Value *GetValue(FunctionEmitContext* ctx) const;
llvm::Value *GetLValue(FunctionEmitContext* ctx) const;
const Type *GetType() const;
const Type *GetLValueType() const;
int getElementNumber() const;
const Type *getElementType() const;
private:
const VectorType *exprVectorType;
const VectorType *memberType;
};
VectorMemberExpr::VectorMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, bool derefLValue)
: MemberExpr(e, id, p, idpos, derefLValue, VectorMemberExprID) {
@@ -5295,6 +5362,19 @@ MemberExpr::Optimize() {
return expr ? this : NULL;
}
Expr *
MemberExpr::ReplacePolyType(const PolyType *from, const Type *to) {
if (expr == NULL)
return NULL;
if (Type::EqualForReplacement(GetType()->GetBaseType(), from)) {
type = PolyType::ReplaceType(type, to);
}
return this;
}
int
MemberExpr::EstimateCost() const {
@@ -7093,10 +7173,16 @@ TypeCastExpr::GetValue(FunctionEmitContext *ctx) const {
return NULL;
return ctx->IntToPtrInst(exprVal, llvmToType, "int_to_ptr");
}
else {
} else if (CastType<PolyType>(toType)) {
Error(pos, "Unexpected polymorphic type cast to \"%s\"",
toType->GetString().c_str());
return NULL;
} else {
const AtomicType *toAtomic = CastType<AtomicType>(toType);
// 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);
return lTypeConvAtomic(ctx, exprVal, toAtomic, fromAtomic, pos);
@@ -7326,6 +7412,18 @@ TypeCastExpr::Optimize() {
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
TypeCastExpr::EstimateCost() const {
@@ -7996,6 +8094,24 @@ SymbolExpr::Optimize() {
return this;
}
Expr *
SymbolExpr::ReplacePolyType(const PolyType *from, const Type *to) {
if (!symbol)
return NULL;
Symbol *tmp = m->symbolTable->LookupVariable(symbol->name.c_str());
if (tmp) {
tmp->parentFunction = symbol->parentFunction;
symbol = tmp;
}
if (Type::EqualForReplacement(symbol->type->GetBaseType(), from)) {
symbol->type = PolyType::ReplaceType(symbol->type, to);
}
return this;
}
int
SymbolExpr::EstimateCost() const {
@@ -8065,6 +8181,14 @@ FunctionSymbolExpr::Optimize() {
return this;
}
Expr *
FunctionSymbolExpr::ReplacePolyType(const PolyType *from, const Type *to) {
// force re-evaluation of overloaded type
this->triedToResolve = false;
return this;
}
int
FunctionSymbolExpr::EstimateCost() const {
@@ -8311,6 +8435,16 @@ FunctionSymbolExpr::computeOverloadCost(const FunctionType *ftype,
cost[i] += 8 * costScale;
continue;
}
if (callTypeNC->IsPolymorphicType()) {
const PolyType *callTypeP =
CastType<PolyType>(callTypeNC->GetBaseType());
if (callTypeP->CanBeType(fargTypeNC->GetBaseType()) &&
callTypeNC->IsArrayType() == fargTypeNC->IsArrayType() &&
callTypeNC->IsPointerType() == fargTypeNC->IsPointerType()){
cost[i] += 8 * costScale;
continue;
}
}
if (fargType->IsVaryingType() && callType->IsUniformType()) {
// Here we deal with brodcasting uniform to varying.
// callType - varying and fargType - uniform is forbidden.
@@ -8437,6 +8571,12 @@ FunctionSymbolExpr::ResolveOverloads(SourcePos argPos,
return true;
}
else if (matches.size() > 1) {
for (size_t i=0; i<argTypes.size(); i++) {
if (argTypes[i]->IsPolymorphicType()) {
matchingFunc = matches[0];
return true;
}
}
// Multiple matches: ambiguous
std::string candidateMessage =
lGetOverloadCandidateMessage(matches, argTypes, argCouldBeNULL);
@@ -8794,6 +8934,18 @@ NewExpr::Optimize() {
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
NewExpr::Print() const {

56
expr.h
View File

@@ -96,6 +96,11 @@ public:
encountered, NULL should be returned. */
virtual Expr *TypeCheck() = 0;
Expr *Copy();
/** 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). */
virtual void Print() const = 0;
};
@@ -324,6 +329,7 @@ public:
Expr *Optimize();
Expr *TypeCheck();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const;
Expr *baseExpr, *index;
@@ -357,6 +363,7 @@ public:
void Print() const;
Expr *Optimize();
Expr *TypeCheck();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const;
virtual int getElementNumber() const = 0;
@@ -379,6 +386,51 @@ protected:
mutable const Type *type, *lvalueType;
};
class StructMemberExpr : public MemberExpr
{
public:
StructMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, bool derefLValue);
static inline bool classof(StructMemberExpr const*) { return true; }
static inline bool classof(ASTNode const* N) {
return N->getValueID() == StructMemberExprID;
}
const Type *GetType() const;
const Type *GetLValueType() const;
int getElementNumber() const;
const Type *getElementType() const;
private:
const StructType *getStructType() const;
};
class VectorMemberExpr : public MemberExpr
{
public:
VectorMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, bool derefLValue);
static inline bool classof(VectorMemberExpr const*) { return true; }
static inline bool classof(ASTNode const* N) {
return N->getValueID() == VectorMemberExprID;
}
llvm::Value *GetValue(FunctionEmitContext* ctx) const;
llvm::Value *GetLValue(FunctionEmitContext* ctx) const;
const Type *GetType() const;
const Type *GetLValueType() const;
int getElementNumber() const;
const Type *getElementType() const;
private:
const VectorType *exprVectorType;
const VectorType *memberType;
};
/** @brief Expression representing a compile-time constant value.
@@ -522,6 +574,7 @@ public:
void Print() const;
Expr *TypeCheck();
Expr *Optimize();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const;
Symbol *GetBaseSymbol() const;
llvm::Constant *GetConstant(const Type *type) const;
@@ -681,6 +734,7 @@ public:
Symbol *GetBaseSymbol() const;
Expr *TypeCheck();
Expr *Optimize();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
void Print() const;
int EstimateCost() const;
@@ -707,6 +761,7 @@ public:
Symbol *GetBaseSymbol() const;
Expr *TypeCheck();
Expr *Optimize();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
void Print() const;
int EstimateCost() const;
llvm::Constant *GetConstant(const Type *type) const;
@@ -809,6 +864,7 @@ public:
const Type *GetType() const;
Expr *TypeCheck();
Expr *Optimize();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
void Print() const;
int EstimateCost() const;

View File

@@ -45,6 +45,7 @@
#include "sym.h"
#include "util.h"
#include <stdio.h>
#include <set>
#if ISPC_LLVM_VERSION == ISPC_LLVM_3_2 // 3.2
#ifdef ISPC_NVPTX_ENABLED
@@ -89,7 +90,7 @@
#endif
#include <llvm/Support/ToolOutputFile.h>
Function::Function(Symbol *s, Stmt *c) {
Function::Function(Symbol *s, Stmt *c, bool typecheck) {
sym = s;
code = c;
@@ -97,6 +98,7 @@ Function::Function(Symbol *s, Stmt *c) {
Assert(maskSymbol != NULL);
if (code != NULL) {
if (typecheck) {
code = TypeCheck(code);
if (code != NULL && g->debugPrint) {
@@ -105,6 +107,7 @@ Function::Function(Symbol *s, Stmt *c) {
code->Print(0);
printf("---------------------\n");
}
}
if (code != NULL) {
code = Optimize(code);
@@ -134,6 +137,7 @@ Function::Function(Symbol *s, Stmt *c) {
args.push_back(sym);
const Type *t = type->GetParameterType(i);
if (sym != NULL && CastType<ReferenceType>(t) == NULL)
sym->parentFunction = this;
}
@@ -627,3 +631,87 @@ 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);
for (size_t i=0; i<versions.size(); i++) {
if (g->debugPrint) {
printf("%s before replacing anything:\n", sym->name.c_str());
code->Print(0);
}
const FunctionType *ft = CastType<FunctionType>(versions[i]->type);
symbolTable->PushScope();
Symbol *s = symbolTable->LookupFunction(versions[i]->name.c_str(), ft);
Stmt *ncode = (Stmt*)CopyAST(code);
Function *f = new Function(s, ncode, false);
for (size_t j=0; j<args.size(); j++) {
f->args[j] = new Symbol(*args[j]);
symbolTable->AddVariable(f->args[j], false);
}
for (int j=0; j<ft->GetNumParameters(); j++) {
if (func->GetParameterType(j)->IsPolymorphicType()) {
const PolyType *from = CastType<PolyType>(
func->GetParameterType(j)->GetBaseType());
f->code = (Stmt*)TranslatePoly(f->code, from,
ft->GetParameterType(j)->GetBaseType());
if (g->debugPrint) {
printf("%s after replacing %s with %s:\n\n",
sym->name.c_str(), from->GetString().c_str(),
ft->GetParameterType(j)->GetBaseType()->GetString().c_str());
f->code->Print(0);
printf("------------------------------------------\n\n");
}
}
}
// we didn't typecheck before, now we can
f->code = TypeCheck(f->code);
f->code = Optimize(f->code);
if (g->debugPrint) {
printf("After optimizing expanded function \"%s\":\n",
f->sym->name.c_str());
f->code->Print(0);
printf("---------------------\n");
}
symbolTable->PopScope();
expanded->push_back(f);
}
return expanded;
}

8
func.h
View File

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

44
lex.ll
View File

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

View File

@@ -1009,6 +1009,102 @@ 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;
for (auto 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));
}
const Type *ret = eft->GetReturnType();
if (Type::EqualForReplacement(ret, pt)) {
printf("Replaced return type %s\n",
ret->GetString().c_str());
ret = PolyType::ReplaceType(ret, *te);
}
nextExpanded.push_back(new FunctionType(ret,
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++) {
if (expanded[i]->GetReturnType()->IsPolymorphicType()) {
Error(pos, "Unexpected polymorphic return type \"%s\"",
expanded[i]->GetReturnType()->GetString().c_str());
return;
}
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
bool disableMask = (storageClass == SC_EXTERN_C);
llvm::FunctionType *llvmFunctionType =
@@ -1177,14 +1273,7 @@ Module::AddFunctionDefinition(const std::string &name, const FunctionType *type,
sym->pos = code->pos;
// FIXME: because we encode the parameter names in the function type,
// 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);
ast->AddFunction(sym, code, symbolTable);
}
@@ -1899,6 +1988,27 @@ lPrintFunctionDeclarations(FILE *file, const std::vector<Symbol *> &funcs,
// 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 +2385,10 @@ Module::writeHeader(const char *fn) {
// Collect single linear arrays of the exported and extern "C"
// functions
std::vector<Symbol *> exportedFuncs, externCFuncs;
std::vector<std::string> polyFuncs;
m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
m->symbolTable->GetMatchingFunctions(lIsExternC, &externCFuncs);
m->symbolTable->GetPolyFunctions(&polyFuncs);
// Get all of the struct, vector, and enumerant types used as function
// parameters. These vectors may have repeats.
@@ -2313,6 +2425,16 @@ Module::writeHeader(const char *fn) {
fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
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 (externCFuncs.size() > 0) {
fprintf(f, "\n");

View File

@@ -118,21 +118,20 @@ static void lFinalizeEnumeratorSymbols(std::vector<Symbol *> &enums,
const EnumType *enumType);
static const char *lBuiltinTokens[] = {
"assert", "bool", "break", "case", "cdo",
"cfor", "cif", "cwhile", "const", "continue", "default",
"do", "delete", "double", "else", "enum", "export", "extern", "false",
"float", "for", "foreach", "foreach_active", "foreach_tiled",
"foreach_unique", "goto", "if", "in", "inline",
"int", "int8", "int16", "int32", "int64", "launch", "new", "NULL",
"print", "return", "signed", "sizeof", "static", "struct", "switch",
"sync", "task", "true", "typedef", "uniform", "unmasked", "unsigned",
"varying", "void", "while", NULL
"assert", "bool", "break", "case", "cdo", "cfor", "cif", "cwhile", "const",
"continue", "default", "do", "delete", "double", "else", "enum", "export",
"extern", "false", "float", "floating", "for", "foreach", "foreach_active",
"foreach_tiled", "foreach_unique", "goto", "if", "in", "inline", "int",
"int8", "int16", "int32", "int64", "integer", "launch", "new", "NULL",
"number", "print", "return", "signed", "sizeof", "static", "struct",
"switch", "sync", "task", "true", "typedef", "uniform", "unmasked",
"unsigned", "varying", "void", "while", NULL
};
static const char *lParamListTokens[] = {
"bool", "const", "double", "enum", "false", "float", "int",
"int8", "int16", "int32", "int64", "signed", "struct", "true",
"uniform", "unsigned", "varying", "void", NULL
"bool", "const", "double", "enum", "false", "float", "floating", "int",
"int8", "int16", "int32", "int64", "integer", "number", "signed", "struct",
"true", "uniform", "unsigned", "varying", "void", NULL
};
struct ForeachDimension {
@@ -159,6 +158,7 @@ struct ForeachDimension {
const Type *type;
std::vector<std::pair<const Type *, SourcePos> > *typeList;
const AtomicType *atomicType;
const PolyType *polyType;
int typeQualifier;
StorageClass storageClass;
Stmt *stmt;
@@ -198,6 +198,7 @@ struct ForeachDimension {
%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_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_ENUM TOKEN_STRUCT TOKEN_TRUE TOKEN_FALSE
@@ -244,6 +245,7 @@ struct ForeachDimension {
%type <type> short_vec_specifier
%type <typeList> type_specifier_list
%type <atomicType> atomic_var_type_specifier
%type <polyType> poly_type_specifier poly_quant_type_specifier
%type <typeQualifier> type_qualifier type_qualifier_list
%type <storageClass> storage_class_specifier
@@ -908,6 +910,7 @@ storage_class_specifier
type_specifier
: atomic_var_type_specifier { $$ = $1; }
| poly_quant_type_specifier { $$ = $1; }
| TOKEN_TYPE_NAME
{
const Type *t = m->symbolTable->LookupType(yytext);
@@ -950,6 +953,20 @@ atomic_var_type_specifier
| 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
: atomic_var_type_specifier '<' int_constant '>'
{

116
stmt.cpp
View File

@@ -35,6 +35,7 @@
@brief File with definitions classes related to statements in the language
*/
#include "ast.h"
#include "stmt.h"
#include "ctx.h"
#include "util.h"
@@ -77,6 +78,85 @@ Stmt::Optimize() {
return this;
}
Stmt *
Stmt::Copy() {
Stmt *copy;
switch (getValueID()) {
case AssertStmtID:
copy = (Stmt*)new AssertStmt(*(AssertStmt*)this);
break;
case BreakStmtID:
copy = (Stmt*)new BreakStmt(*(BreakStmt*)this);
break;
case CaseStmtID:
copy = (Stmt*)new CaseStmt(*(CaseStmt*)this);
break;
case ContinueStmtID:
copy = (Stmt*)new ContinueStmt(*(ContinueStmt*)this);
break;
case DeclStmtID:
copy = (Stmt*)new DeclStmt(*(DeclStmt*)this);
break;
case DefaultStmtID:
copy = (Stmt*)new DefaultStmt(*(DefaultStmt*)this);
break;
case DeleteStmtID:
copy = (Stmt*)new DeleteStmt(*(DeleteStmt*)this);
break;
case DoStmtID:
copy = (Stmt*)new DoStmt(*(DoStmt*)this);
break;
case ExprStmtID:
copy = (Stmt*)new ExprStmt(*(ExprStmt*)this);
break;
case ForeachActiveStmtID:
copy = (Stmt*)new ForeachActiveStmt(*(ForeachActiveStmt*)this);
break;
case ForeachStmtID:
copy = (Stmt*)new ForeachStmt(*(ForeachStmt*)this);
break;
case ForeachUniqueStmtID:
copy = (Stmt*)new ForeachUniqueStmt(*(ForeachUniqueStmt*)this);
break;
case ForStmtID:
copy = (Stmt*)new ForStmt(*(ForStmt*)this);
break;
case GotoStmtID:
copy = (Stmt*)new GotoStmt(*(GotoStmt*)this);
break;
case IfStmtID:
copy = (Stmt*)new IfStmt(*(IfStmt*)this);
break;
case LabeledStmtID:
copy = (Stmt*)new LabeledStmt(*(LabeledStmt*)this);
break;
case PrintStmtID:
copy = (Stmt*)new PrintStmt(*(PrintStmt*)this);
break;
case ReturnStmtID:
copy = (Stmt*)new ReturnStmt(*(ReturnStmt*)this);
break;
case StmtListID:
copy = (Stmt*)new StmtList(*(StmtList*)this);
break;
case SwitchStmtID:
copy = (Stmt*)new SwitchStmt(*(SwitchStmt*)this);
break;
case UnmaskedStmtID:
copy = (Stmt*)new UnmaskedStmt(*(UnmaskedStmt*)this);
break;
default:
FATAL("Unmatched case in Stmt::Copy");
copy = this; // just to silence the compiler
}
return copy;
}
Stmt *
Stmt::ReplacePolyType(const PolyType *, const Type *) {
return this;
}
///////////////////////////////////////////////////////////////////////////
// ExprStmt
@@ -479,7 +559,8 @@ DeclStmt::TypeCheck() {
// an int as the constValue later...
const Type *type = vars[i].sym->type;
if (CastType<AtomicType>(type) != NULL ||
CastType<EnumType>(type) != NULL) {
CastType<EnumType>(type) != NULL ||
CastType<PolyType>(type) != NULL) {
// If it's an expr list with an atomic type, we'll later issue
// an error. Need to leave vars[i].init as is in that case so
// it is in fact caught later, though.
@@ -494,6 +575,24 @@ DeclStmt::TypeCheck() {
return encounteredError ? NULL : this;
}
Stmt *
DeclStmt::ReplacePolyType(const PolyType *from, const Type *to) {
for (size_t i = 0; i < vars.size(); i++) {
vars[i].sym = new Symbol(*vars[i].sym);
m->symbolTable->AddVariable(vars[i].sym, false);
Symbol *s = vars[i].sym;
if (Type::EqualForReplacement(s->type->GetBaseType(), from)) {
s->type = PolyType::ReplaceType(s->type, to);
// this typecast *should* be valid after typechecking
vars[i].init = TypeConvertExpr(vars[i].init, s->type,
"initializer");
}
}
return this;
}
void
DeclStmt::Print(int indent) const {
@@ -1470,6 +1569,17 @@ ForeachStmt::ForeachStmt(const std::vector<Symbol *> &lvs,
stmts(s) {
}
/*
ForeachStmt::ForeachStmt(ForeachStmt *base)
: Stmt(base->pos, ForeachStmtID) {
dimVariables = base->dimVariables;
startExprs = base->startExprs;
endExprs = base->endExprs;
isTiled = base->isTiled;
stmts = base->stmts;
}
*/
/* Given a uniform counter value in the memory location pointed to by
uniformCounterPtr, compute the corresponding set of varying counter
@@ -1713,8 +1823,10 @@ ForeachStmt::EmitCode(FunctionEmitContext *ctx) const {
// Start and end value for this loop dimension
llvm::Value *sv = startExprs[i]->GetValue(ctx);
llvm::Value *ev = endExprs[i]->GetValue(ctx);
if (sv == NULL || ev == NULL)
if (sv == NULL || ev == NULL) {
fprintf(stderr, "ev is NULL again :(\n");
return;
}
startVals.push_back(sv);
endVals.push_back(ev);

3
stmt.h
View File

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

38
sym.cpp
View File

@@ -95,14 +95,14 @@ SymbolTable::PopScope() {
bool
SymbolTable::AddVariable(Symbol *symbol) {
SymbolTable::AddVariable(Symbol *symbol, bool issueScopeWarning) {
Assert(symbol != NULL);
// Check to see if a symbol of the same name has already been declared.
for (int i = (int)variables.size() - 1; i >= 0; --i) {
SymbolMapType &sm = *(variables[i]);
if (sm.find(symbol->name) != sm.end()) {
if (i == (int)variables.size()-1) {
if (i == (int)variables.size()-1 && issueScopeWarning) {
// If a symbol of the same name was declared in the
// same scope, it's an error.
Error(symbol->pos, "Ignoring redeclaration of symbol \"%s\".",
@@ -112,9 +112,11 @@ SymbolTable::AddVariable(Symbol *symbol) {
else {
// Otherwise it's just shadowing something else, which
// is legal but dangerous..
if (issueScopeWarning) {
Warning(symbol->pos,
"Symbol \"%s\" shadows symbol declared in outer scope.",
symbol->name.c_str());
}
(*variables.back())[symbol->name] = symbol;
return true;
}
@@ -147,7 +149,7 @@ bool
SymbolTable::AddFunction(Symbol *symbol) {
const FunctionType *ft = CastType<FunctionType>(symbol->type);
Assert(ft != NULL);
if (LookupFunction(symbol->name.c_str(), ft) != NULL)
if (LookupFunction(symbol->name.c_str(), ft, true) != NULL)
// A function of the same name and type has already been added to
// the symbol table
return false;
@@ -157,6 +159,14 @@ SymbolTable::AddFunction(Symbol *symbol) {
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
SymbolTable::LookupFunction(const char *name, std::vector<Symbol *> *matches) {
@@ -175,7 +185,8 @@ SymbolTable::LookupFunction(const char *name, std::vector<Symbol *> *matches) {
Symbol *
SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
SymbolTable::LookupFunction(const char *name, const FunctionType *type,
bool ignorePoly) {
FunctionMapType::iterator iter = functions.find(name);
if (iter != functions.end()) {
std::vector<Symbol *> funcs = iter->second;
@@ -184,9 +195,28 @@ SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
return funcs[j];
}
}
// Try looking for a polymorphic function
if (!ignorePoly && polyFunctions[name].size() > 0) {
std::string n = name;
return new Symbol(name, polyFunctions[name][0]->pos, type);
}
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
SymbolTable::AddType(const char *name, const Type *type, SourcePos pos) {

20
sym.h
View File

@@ -108,6 +108,7 @@ public:
};
/** @brief Symbol table that holds all known symbols during parsing and compilation.
A single instance of a SymbolTable is stored in the Module class
@@ -140,7 +141,7 @@ public:
with a symbol defined at the same scope. (Symbols may shaodow
symbols in outer scopes; a warning is issued in this case, but this
method still returns true.) */
bool AddVariable(Symbol *symbol);
bool AddVariable(Symbol *symbol, bool issueScopeWarning=true);
/** Looks for a variable with the given name in the symbol table. This
method searches outward from the innermost scope to the outermost,
@@ -159,6 +160,14 @@ public:
already present in the symbol table. */
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
symbol name. If a function has been overloaded and multiple
definitions are present for a given function name, all of them will
@@ -172,7 +181,12 @@ public:
in the symbol table.
@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,
bool ignorePoly = false);
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
predicate.
@@ -276,6 +290,8 @@ private:
typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType;
FunctionMapType functions;
FunctionMapType polyFunctions;
/** Type definitions can't currently be scoped.
*/
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 -O2
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,7 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include "hello.ispc.h"
#include "hello.h"
int main() {
float A[100];

View File

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

20
tests_ispcpp/simple.cpp Normal file
View File

@@ -0,0 +1,20 @@
#include <stdlib.h>
#include <stdio.h>
#include "simple.h"
int main() {
double A[256];
for (int i=0; i<256; i++) {
A[i] = i / 11.;
}
ispc::foo(256, (double*)&A);
for (int i=0; i<256; i++) {
printf("%f\n", A[i]);
}
return 0;
}

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;
}
}

27
tests_ispcpp/varying.cpp Normal file
View File

@@ -0,0 +1,27 @@
#include <stdlib.h>
#include <stdio.h>
#include "varying.h"
int main() {
float A[256];
double B[256];
double outA[256];
double outB[256];
for (int i=0; i<256; i++) {
A[i] = 1. / (i+1);
B[i] = 1. / (i+1);
}
ispc::square(256, (float*)&A, (double*)&outA);
ispc::square(256, (double*)&B, (double*)&outB);
for (int i=0; i<256; i++) {
printf("float: %.16f\tdouble: %.16f\n", outA[i], outB[i]);
}
return 0;
}

14
tests_ispcpp/varying.ispc Normal file
View File

@@ -0,0 +1,14 @@
floating foo(const uniform int a, floating b) {
floating out = b;
for (int i = 1; i<a; i++) {
out *= b;
}
return out;
}
export void square(uniform int N, uniform floating b[], uniform double out[]) {
foreach (i = 0 ... N) {
out[i] = foo(2, b[i]);
}
}

532
type.cpp
View File

@@ -247,6 +247,20 @@ Type::IsVoidType() const {
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
AtomicType::IsFloatType() const {
return (basicType == TYPE_FLOAT || basicType == TYPE_DOUBLE);
@@ -673,6 +687,454 @@ 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();
if (g->debugPrint) {
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
@@ -3134,6 +3596,34 @@ FunctionType::GetCDeclaration(const std::string &fname) const {
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
FunctionType::GetCDeclarationForDispatch(const std::string &fname) const {
@@ -3554,6 +4044,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...
if (at0 == NULL || at1 == NULL) {
Assert(reason != NULL);
@@ -3572,7 +4080,8 @@ bool
Type::IsBasicType(const Type *type) {
return (CastType<AtomicType>(type) != NULL ||
CastType<EnumType>(type) != NULL ||
CastType<PointerType>(type) != NULL);
CastType<PointerType>(type) != NULL ||
CastType<PolyType>(type) != NULL);
}
@@ -3592,6 +4101,14 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
(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
// general types. If so, then we dig into the details of the type and
// see if all of the relevant bits are equal...
@@ -3688,3 +4205,16 @@ bool
Type::EqualIgnoringConst(const Type *a, const Type *b) {
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
UNDEFINED_STRUCT_TYPE, // 6
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 */
bool IsVoidType() const;
/** Returns true if the underlying type is polymorphic */
bool IsPolymorphicType() const;
/** Returns true if this type is 'const'-qualified. */
virtual bool IsConstType() const = 0;
@@ -240,6 +244,8 @@ public:
the same (ignoring const-ness of the type), false otherwise. */
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
than both of them. (i.e. that can represent their values without
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 *Void;
AtomicType(BasicType basicType, Variability v, bool isConst);
private:
const Variability variability;
const bool isConst;
AtomicType(BasicType basicType, Variability v, bool isConst);
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
*/
@@ -912,6 +988,7 @@ public:
std::string GetString() const;
std::string Mangle() 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;
llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
@@ -1002,6 +1079,14 @@ CastType(const Type *type) {
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 *
CastType(const Type *type) {
if (type != NULL && type->typeId == ENUM_TYPE)