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
*~
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

42
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);
}
}
@@ -485,7 +499,7 @@ lCheckAllOffSafety(ASTNode *node, void *data) {
}
/*
Don't allow turning if/else to straight-line-code if we
Don't allow turning if/else to straight-line-code if we
assign to a uniform.
*/
AssignExpr *ae;
@@ -508,3 +522,25 @@ 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);
}
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);
}

15
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,8 @@ public:
pointer in place of the original ASTNode *. */
virtual ASTNode *TypeCheck() = 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. */
@@ -75,8 +78,8 @@ public:
/** All AST nodes must track the file position where they are
defined. */
SourcePos pos;
/** An enumeration for keeping track of the concrete subclass of Value
/** An enumeration for keeping track of the concrete subclass of Value
that is actually instantiated.*/
enum ASTNodeTy {
/* For classes inherited from Expr */
@@ -127,9 +130,9 @@ public:
SwitchStmtID,
UnmaskedStmtID
};
/** Return an ID for the concrete type of this object. This is used to
implement the classof checks. This should not be used for any
implement the classof checks. This should not be used for any
other purpose, as the values may change as ISPC evolves */
unsigned getValueID() const {
return SubclassID;
@@ -145,7 +148,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. */
@@ -204,6 +207,8 @@ extern Stmt *TypeCheck(Stmt *);
the given 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
off" mask. */
extern bool SafeToRunWithMaskAllOff(ASTNode *root);

30
ctx.cpp
View File

@@ -631,7 +631,7 @@ FunctionEmitContext::EndIf() {
breakLanes, "|break_lanes");
}
llvm::Value *notBreakOrContinue =
llvm::Value *notBreakOrContinue =
BinaryOperator(llvm::Instruction::Xor,
bcLanes, LLVMMaskAllOn,
"!(break|continue)_lanes");
@@ -942,7 +942,7 @@ FunctionEmitContext::jumpIfAllLoopLanesAreDone(llvm::BasicBlock *target) {
finishedLanes = BinaryOperator(llvm::Instruction::Or, finishedLanes,
continued, "returned|breaked|continued");
}
finishedLanes = BinaryOperator(llvm::Instruction::And,
finishedLanes, GetFunctionMask(),
"finished&func");
@@ -1446,7 +1446,7 @@ FunctionEmitContext::None(llvm::Value *mask) {
llvm::Value *
FunctionEmitContext::LaneMask(llvm::Value *v) {
#ifdef ISPC_NVPTX_ENABLED
/* this makes mandelbrot example slower with "nvptx" target.
/* this makes mandelbrot example slower with "nvptx" target.
* Needs further investigation. */
const char *__movmsk = g->target->getISA() == Target::NVPTX ? "__movmsk_ptx" : "__movmsk";
#else
@@ -1494,7 +1494,7 @@ FunctionEmitContext::Insert(llvm::Value *vector, llvm::Value *lane, llvm::Value
std::string funcName = "__insert";
assert(lAppendInsertExtractName(vector, funcName));
assert(lane->getType() == LLVMTypes::Int32Type);
llvm::Function *func = m->module->getFunction(funcName.c_str());
assert(func != NULL);
std::vector<llvm::Value *> args;
@@ -1511,7 +1511,7 @@ FunctionEmitContext::Extract(llvm::Value *vector, llvm::Value *lane)
std::string funcName = "__extract";
assert(lAppendInsertExtractName(vector, funcName));
assert(lane->getType() == LLVMTypes::Int32Type);
llvm::Function *func = m->module->getFunction(funcName.c_str());
assert(func != NULL);
std::vector<llvm::Value *> args;
@@ -2823,7 +2823,7 @@ FunctionEmitContext::loadUniformFromSOA(llvm::Value *ptr, llvm::Value *mask,
llvm::Value *
FunctionEmitContext::LoadInst(llvm::Value *ptr, llvm::Value *mask,
const Type *ptrRefType, const char *name,
const Type *ptrRefType, const char *name,
bool one_elem) {
if (ptr == NULL) {
AssertPos(currentPos, m->errorCount > 0);
@@ -3285,8 +3285,8 @@ FunctionEmitContext::scatter(llvm::Value *value, llvm::Value *ptr,
const PointerType *pt = CastType<PointerType>(valueType);
// And everything should be a pointer or atomic (or enum) from here on out...
AssertPos(currentPos,
pt != NULL
AssertPos(currentPos,
pt != NULL
|| CastType<AtomicType>(valueType) != NULL
|| CastType<EnumType>(valueType) != NULL);
@@ -3887,7 +3887,7 @@ FunctionEmitContext::LaunchInst(llvm::Value *callee,
llvm::Function *F = llvm::dyn_cast<llvm::Function>(callee);
const unsigned int nArgs = F->arg_size();
llvm::Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
for (; I != E; ++I)
for (; I != E; ++I)
argTypes.push_back(I->getType());
llvm::Type *st = llvm::StructType::get(*g->ctx, argTypes);
llvm::StructType *argStructType = static_cast<llvm::StructType *>(st);
@@ -3908,24 +3908,24 @@ FunctionEmitContext::LaunchInst(llvm::Value *callee,
llvm::BasicBlock* if_true = CreateBasicBlock("if_true");
llvm::BasicBlock* if_false = CreateBasicBlock("if_false");
/* check if the pointer returned by ISPCAlloc is not NULL
/* check if the pointer returned by ISPCAlloc is not NULL
* --------------
* this is a workaround for not checking the value of programIndex
* this is a workaround for not checking the value of programIndex
* because ISPCAlloc will return NULL pointer for all programIndex > 0
* of course, if ISPAlloc fails to get parameter buffer, the pointer for programIndex = 0
* will also be NULL
* This check must be added, and also rewrite the code to make it less opaque
* This check must be added, and also rewrite the code to make it less opaque
*/
llvm::Value* cmp1 = CmpInst(llvm::Instruction::ICmp, llvm::CmpInst::ICMP_NE, voidi64, LLVMInt64(0), "cmp1");
BranchInst(if_true, if_false, cmp1);
/**********************/
bblock = if_true;
bblock = if_true;
// label_if_then block:
llvm::Type *pt = llvm::PointerType::getUnqual(st);
llvm::Value *argmem = BitCastInst(voidmem, pt);
for (unsigned int i = 0; i < argVals.size(); ++i)
for (unsigned int i = 0; i < argVals.size(); ++i)
{
llvm::Value *ptr = AddElementOffset(argmem, i, NULL, "funarg");
// don't need to do masked store here, I think
@@ -4027,7 +4027,7 @@ FunctionEmitContext::LaunchInst(llvm::Value *callee,
void
FunctionEmitContext::SyncInst() {
#ifdef ISPC_NVPTX_ENABLED
#ifdef ISPC_NVPTX_ENABLED
if (g->target->getISA() == Target::NVPTX)
{
llvm::Value *launchGroupHandle = LoadInst(launchGroupHandlePtr);

10
ctx.h
View File

@@ -195,10 +195,10 @@ public:
'continue' statement when going through the loop body in the
previous iteration. */
void RestoreContinuedLanes();
/** This method is called by code emitting IR for a loop. It clears
/** This method is called by code emitting IR for a loop. It clears
any lanes that contained a break since the mask has been updated to take
them into account. This is necessary as all the bail out checks for
them into account. This is necessary as all the bail out checks for
breaks are meant to only deal with lanes breaking on the current iteration.
*/
void ClearBreakLanes();
@@ -312,7 +312,7 @@ public:
llvm::Value* Insert(llvm::Value *vector, llvm::Value *lane, llvm::Value *scalar);
/** Issues a call to __extract_int8/int16/int32/int64/float/double */
llvm::Value* Extract(llvm::Value *vector, llvm::Value *lane);
#endif
#endif
/** Given a string, create an anonymous global variable to hold its
value and return the pointer to the string. */
@@ -481,7 +481,7 @@ public:
pointer values given by the lvalue. If the lvalue is not varying,
then both the mask pointer and the type pointer may be NULL. */
llvm::Value *LoadInst(llvm::Value *ptr, llvm::Value *mask,
const Type *ptrType, const char *name = NULL,
const Type *ptrType, const char *name = NULL,
bool one_elem = false);
llvm::Value *LoadInst(llvm::Value *ptr, const char *name = NULL);

106
expr.cpp
View File

@@ -112,6 +112,11 @@ Expr::GetBaseSymbol() const {
return NULL;
}
Expr *
Expr::ReplacePolyType(const PolyType *polyType, const Type *replacement) {
return this;
}
#if 0
/** 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 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 +551,20 @@ 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);
}
}
}
// from here on out, the from type can only be atomic something or
// other...
if (fromAtomicType == NULL) {
@@ -3183,7 +3204,7 @@ static llvm::Value *
lEmitVaryingSelect(FunctionEmitContext *ctx, llvm::Value *test,
llvm::Value *expr1, llvm::Value *expr2,
const Type *type) {
llvm::Value *resultPtr = ctx->AllocaInst(expr1->getType(), "selectexpr_tmp");
// Don't need to worry about masking here
ctx->StoreInst(expr2, resultPtr);
@@ -3683,7 +3704,7 @@ FunctionCallExpr::GetValue(FunctionEmitContext *ctx) const {
ctx->SetDebugPos(pos);
if (ft->isTask) {
AssertPos(pos, launchCountExpr[0] != NULL);
llvm::Value *launchCount[3] =
llvm::Value *launchCount[3] =
{ launchCountExpr[0]->GetValue(ctx),
launchCountExpr[1]->GetValue(ctx),
launchCountExpr[2]->GetValue(ctx) };
@@ -3752,7 +3773,7 @@ FunctionCallExpr::GetType() const {
const Type *
FunctionCallExpr::GetLValueType() const {
const FunctionType *ftype = lGetFunctionType(func);
if (ftype && (ftype->GetReturnType()->IsPointerType()
if (ftype && (ftype->GetReturnType()->IsPointerType()
|| ftype->GetReturnType()->IsReferenceType())) {
return ftype->GetReturnType();
}
@@ -4293,7 +4314,7 @@ IndexExpr::GetValue(FunctionEmitContext *ctx) const {
}
else {
Symbol *baseSym = GetBaseSymbol();
if (llvm::dyn_cast<FunctionCallExpr>(baseExpr) == NULL &&
if (llvm::dyn_cast<FunctionCallExpr>(baseExpr) == NULL &&
llvm::dyn_cast<BinaryExpr>(baseExpr) == NULL) {
// Don't check if we're doing a function call or pointer arith
AssertPos(pos, baseSym != NULL);
@@ -4653,6 +4674,23 @@ IndexExpr::TypeCheck() {
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
IndexExpr::EstimateCost() const {
@@ -5147,7 +5185,7 @@ MemberExpr::create(Expr *e, const char *id, SourcePos p, SourcePos idpos,
}
if (CastType<StructType>(exprType) != NULL) {
const StructType *st = CastType<StructType>(exprType);
if (st->IsDefined()) {
if (st->IsDefined()) {
return new StructMemberExpr(e, id, p, idpos, derefLValue);
}
else {
@@ -5295,6 +5333,23 @@ MemberExpr::Optimize() {
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
MemberExpr::EstimateCost() const {
@@ -7097,6 +7152,9 @@ TypeCastExpr::GetValue(FunctionEmitContext *ctx) const {
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);
@@ -7203,7 +7261,7 @@ TypeCastExpr::TypeCheck() {
// Issues #721
return this;
}
const AtomicType *fromAtomic = CastType<AtomicType>(fromType);
const AtomicType *toAtomic = CastType<AtomicType>(toType);
const EnumType *fromEnum = CastType<EnumType>(fromType);
@@ -7326,6 +7384,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 +8066,18 @@ SymbolExpr::Optimize() {
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
SymbolExpr::EstimateCost() const {
@@ -8794,6 +8876,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 {

49
expr.h
View File

@@ -96,6 +96,10 @@ public:
encountered, NULL should be returned. */
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). */
virtual void Print() const = 0;
};
@@ -162,12 +166,12 @@ public:
};
BinaryExpr(Op o, Expr *a, Expr *b, SourcePos p);
static inline bool classof(BinaryExpr const*) { return true; }
static inline bool classof(ASTNode const* N) {
return N->getValueID() == BinaryExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
const Type *GetLValueType() const;
@@ -205,7 +209,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == AssignExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
void Print() const;
@@ -231,7 +235,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == SelectExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
void Print() const;
@@ -258,7 +262,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == ExprListID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
void Print() const;
@@ -276,14 +280,14 @@ public:
class FunctionCallExpr : public Expr {
public:
FunctionCallExpr(Expr *func, ExprList *args, SourcePos p,
bool isLaunch = false,
bool isLaunch = false,
Expr *launchCountExpr[3] = NULL);
static inline bool classof(FunctionCallExpr const*) { return true; }
static inline bool classof(ASTNode const* N) {
return N->getValueID() == FunctionCallExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
@@ -314,7 +318,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == IndexExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
@@ -324,6 +328,7 @@ public:
Expr *Optimize();
Expr *TypeCheck();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
int EstimateCost() const;
Expr *baseExpr, *index;
@@ -349,7 +354,7 @@ public:
return ((N->getValueID() == StructMemberExprID) ||
(N->getValueID() == VectorMemberExprID));
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
@@ -357,6 +362,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;
@@ -452,7 +458,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == ConstExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
void Print() const;
@@ -514,7 +520,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == TypeCastExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
@@ -522,6 +528,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;
@@ -541,7 +548,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == ReferenceExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
const Type *GetLValueType() const;
@@ -567,7 +574,7 @@ public:
(N->getValueID() == PtrDerefExprID) ||
(N->getValueID() == RefDerefExprID));
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
const Type *GetLValueType() const;
@@ -588,7 +595,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == PtrDerefExprID;
}
const Type *GetType() const;
void Print() const;
Expr *TypeCheck();
@@ -606,7 +613,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == RefDerefExprID;
}
const Type *GetType() const;
void Print() const;
Expr *TypeCheck();
@@ -649,7 +656,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == SizeOfExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
void Print() const;
@@ -673,7 +680,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == SymbolExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
@@ -681,6 +688,7 @@ public:
Symbol *GetBaseSymbol() const;
Expr *TypeCheck();
Expr *Optimize();
Expr *ReplacePolyType(const PolyType *from, const Type *to);
void Print() const;
int EstimateCost() const;
@@ -701,7 +709,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == FunctionSymbolExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
Symbol *GetBaseSymbol() const;
@@ -762,7 +770,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == SyncExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
Expr *TypeCheck();
@@ -781,7 +789,7 @@ public:
static inline bool classof(ASTNode const* N) {
return N->getValueID() == NullPointerExprID;
}
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
const Type *GetType() const;
Expr *TypeCheck();
@@ -809,6 +817,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
@@ -140,7 +141,7 @@ Function::Function(Symbol *s, Stmt *c) {
if (type->isTask
#ifdef ISPC_NVPTX_ENABLED
&& (g->target->getISA() != Target::NVPTX)
&& (g->target->getISA() != Target::NVPTX)
#endif
){
threadIndexSym = m->symbolTable->LookupVariable("threadIndex");
@@ -260,8 +261,8 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function,
Assert(type != NULL);
if (type->isTask == true
#ifdef ISPC_NVPTX_ENABLED
&& (g->target->getISA() != Target::NVPTX)
#endif
&& (g->target->getISA() != Target::NVPTX)
#endif
){
// For tasks, there should always be three parameters: the
// pointer to the structure that holds all of the arguments, the
@@ -322,14 +323,14 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function,
taskCountSym->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount");
ctx->StoreInst(taskCount, taskCountSym->storagePtr);
taskIndexSym0->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex0");
ctx->StoreInst(taskIndex0, taskIndexSym0->storagePtr);
taskIndexSym1->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex1");
ctx->StoreInst(taskIndex1, taskIndexSym1->storagePtr);
taskIndexSym2->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex2");
ctx->StoreInst(taskIndex2, taskIndexSym2->storagePtr);
taskCountSym0->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount0");
ctx->StoreInst(taskCount0, taskCountSym0->storagePtr);
taskCountSym1->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount1");
@@ -570,7 +571,7 @@ Function::GenerateIR() {
av.push_back(function);
av.push_back(llvm::MDString::get(*g->ctx, "kernel"));
av.push_back(llvm::ConstantInt::get(llvm::IntegerType::get(*g->ctx,32), 1));
annotations->addOperand(llvm::MDNode::get(*g->ctx, av));
annotations->addOperand(llvm::MDNode::get(*g->ctx, av));
#endif
}
#endif /* ISPC_NVPTX_ENABLED */
@@ -611,7 +612,7 @@ Function::GenerateIR() {
av.push_back(llvm::ValueAsMetadata::get(appFunction));
av.push_back(llvm::MDString::get(*g->ctx, "kernel"));
av.push_back(llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(llvm::IntegerType::get(*g->ctx,32), 1)));
annotations->addOperand(llvm::MDNode::get(*g->ctx, llvm::ArrayRef<llvm::Metadata*>(av)));
annotations->addOperand(llvm::MDNode::get(*g->ctx, llvm::ArrayRef<llvm::Metadata*>(av)));
#else
llvm::SmallVector<llvm::Value*, 3> av;
av.push_back(appFunction);
@@ -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
#include "ispc.h"
#include "sym.h"
#include <vector>
class Function {
@@ -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);

View File

@@ -471,7 +471,7 @@ Target::Target(const char *arch, const char *cpu, const char *isa, bool pic, boo
m_is32Bit(true),
m_cpu(""),
m_attributes(""),
#if ISPC_LLVM_VERSION >= ISPC_LLVM_3_3
#if ISPC_LLVM_VERSION >= ISPC_LLVM_3_3
m_tf_attributes(NULL),
#endif
m_nativeVectorWidth(-1),
@@ -733,7 +733,7 @@ Target::Target(const char *arch, const char *cpu, const char *isa, bool pic, boo
else if (!strcasecmp(isa, "generic-16") ||
!strcasecmp(isa, "generic-x16") ||
// We treat *-generic-16 as generic-16, but with special name mangling
strstr(isa, "-generic-16") ||
strstr(isa, "-generic-16") ||
strstr(isa, "-generic-x16")) {
this->m_isa = Target::GENERIC;
if (strstr(isa, "-generic-16") ||

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

@@ -349,7 +349,7 @@ lStripUnusedDebugInfo(llvm::Module *module) {
// And now we can go and stuff it into the unit with some
// confidence...
llvm::MDNode *replNode = llvm::MDNode::get(module->getContext(),
llvm::MDNode *replNode = llvm::MDNode::get(module->getContext(),
llvm::ArrayRef<llvm::Metadata *>(usedSubprograms));
cu.replaceSubprograms(llvm::DIArray(replNode));
#else // LLVM 3.7+
@@ -589,7 +589,7 @@ Module::AddGlobalVariable(const std::string &name, const Type *type, Expr *initE
}
#ifdef ISPC_NVPTX_ENABLED
if (g->target->getISA() == Target::NVPTX &&
if (g->target->getISA() == Target::NVPTX &&
#if 0
!type->IsConstType() &&
#endif
@@ -609,7 +609,7 @@ Module::AddGlobalVariable(const std::string &name, const Type *type, Expr *initE
* or 128 threads.
* ***note-to-me***:please define these value (128threads/4warps)
* in nvptx-target definition
* instead of compile-time constants
* instead of compile-time constants
*/
nel *= at->GetElementCount();
assert (!type->IsSOAType());
@@ -830,7 +830,7 @@ lRecursiveCheckValidParamType(const Type *t, bool vectorOk) {
if (pt != NULL) {
// Only allow exported uniform pointers
// Uniform pointers to varying data, however, are ok.
if (pt->IsVaryingType())
if (pt->IsVaryingType())
return false;
else
return lRecursiveCheckValidParamType(pt->GetBaseType(), true);
@@ -838,7 +838,7 @@ lRecursiveCheckValidParamType(const Type *t, bool vectorOk) {
if (t->IsVaryingType() && !vectorOk)
return false;
else
else
return true;
}
@@ -871,7 +871,7 @@ lCheckExportedParameterTypes(const Type *type, const std::string &name,
static void
lCheckTaskParameterTypes(const Type *type, const std::string &name,
SourcePos pos) {
if (g->target->getISA() != Target::NVPTX)
if (g->target->getISA() != Target::NVPTX)
return;
if (lRecursiveCheckValidParamType(type, false) == false) {
if (CastType<VectorType>(type))
@@ -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
bool disableMask = (storageClass == SC_EXTERN_C);
llvm::FunctionType *llvmFunctionType =
@@ -1026,7 +1111,7 @@ Module::AddFunctionDeclaration(const std::string &name,
functionName += functionType->Mangle();
// If we treat generic as smth, we should have appropriate mangling
if (g->mangleFunctionsWithTarget) {
if (g->target->getISA() == Target::GENERIC &&
if (g->target->getISA() == Target::GENERIC &&
!g->target->getTreatGenericAsSmth().empty())
functionName += g->target->getTreatGenericAsSmth();
else
@@ -1177,14 +1262,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);
}
@@ -1326,7 +1404,7 @@ Module::writeOutput(OutputType outputType, const char *outFileName,
#ifdef ISPC_NVPTX_ENABLED
typedef std::vector<std::string> vecString_t;
static vecString_t
static vecString_t
lSplitString(const std::string &s)
{
std::stringstream ss(s);
@@ -1335,7 +1413,7 @@ lSplitString(const std::string &s)
return vecString_t(begin,end);
}
static void
static void
lFixAttributes(const vecString_t &src, vecString_t &dst)
{
dst.clear();
@@ -1434,7 +1512,7 @@ Module::writeBitcode(llvm::Module *module, const char *outFileName) {
#ifdef ISPC_NVPTX_ENABLED
if (g->target->getISA() == Target::NVPTX)
{
/* when using "nvptx" target, emit patched/hacked assembly
/* when using "nvptx" target, emit patched/hacked assembly
* NVPTX only accepts 3.2-style LLVM assembly, where attributes
* must be inlined, rather then referenced by #attribute_d
* As soon as NVVM support 3.3,3.4 style assembly this fix won't be needed
@@ -1506,7 +1584,7 @@ Module::writeObjectFileOrAssembly(llvm::TargetMachine *targetMachine,
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_5
std::string error;
#else // LLVM 3.6+
#else // LLVM 3.6+
std::error_code error;
#endif
@@ -1518,7 +1596,7 @@ Module::writeObjectFileOrAssembly(llvm::TargetMachine *targetMachine,
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_5
if (error.size()) {
#else // LLVM 3.6+
#else // LLVM 3.6+
if (error) {
#endif
@@ -1603,7 +1681,7 @@ static void
lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedStructs,
FILE *file, bool emitUnifs=true) {
// if we're emitting this for a generic dispatch header file and it's
// if we're emitting this for a generic dispatch header file and it's
// struct that only contains uniforms, don't bother if we're emitting uniforms
if (!emitUnifs && !lContainsPtrToVarying(st)) {
return;
@@ -1626,7 +1704,7 @@ lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedSt
// And now it's safe to declare this one
emittedStructs->push_back(st);
fprintf(file, "#ifndef __ISPC_STRUCT_%s__\n",st->GetCStructName().c_str());
fprintf(file, "#define __ISPC_STRUCT_%s__\n",st->GetCStructName().c_str());
@@ -1848,7 +1926,7 @@ lGetExportedTypes(const Type *type,
lGetExportedTypes(ftype->GetParameterType(j), exportedStructTypes,
exportedEnumTypes, exportedVectorTypes);
}
else
else
Assert(CastType<AtomicType>(type) != NULL);
}
@@ -1899,6 +1977,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 +2374,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 +2414,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");
@@ -2349,7 +2460,7 @@ struct DispatchHeaderInfo {
bool
Module::writeDispatchHeader(DispatchHeaderInfo *DHI) {
FILE *f = DHI->file;
if (DHI->EmitFrontMatter) {
fprintf(f, "//\n// %s\n// (Header automatically generated by the ispc compiler.)\n", DHI->fn);
fprintf(f, "// DO NOT EDIT THIS FILE.\n//\n\n");
@@ -2392,10 +2503,10 @@ Module::writeDispatchHeader(DispatchHeaderInfo *DHI) {
std::vector<Symbol *> exportedFuncs, externCFuncs;
m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
m->symbolTable->GetMatchingFunctions(lIsExternC, &externCFuncs);
int programCount = g->target->getVectorWidth();
if ((DHI->Emit4 && (programCount == 4)) ||
if ((DHI->Emit4 && (programCount == 4)) ||
(DHI->Emit8 && (programCount == 8)) ||
(DHI->Emit16 && (programCount == 16))) {
// Get all of the struct, vector, and enumerant types used as function
@@ -2407,7 +2518,7 @@ Module::writeDispatchHeader(DispatchHeaderInfo *DHI) {
&exportedEnumTypes, &exportedVectorTypes);
lGetExportedParamTypes(externCFuncs, &exportedStructTypes,
&exportedEnumTypes, &exportedVectorTypes);
// Go through the explicitly exported types
for (int i = 0; i < (int)exportedTypes.size(); ++i) {
if (const StructType *st = CastType<StructType>(exportedTypes[i].first))
@@ -2420,19 +2531,19 @@ Module::writeDispatchHeader(DispatchHeaderInfo *DHI) {
FATAL("Unexpected type in export list");
}
// And print them
if (DHI->EmitUnifs) {
lEmitVectorTypedefs(exportedVectorTypes, f);
lEmitEnumDecls(exportedEnumTypes, f);
}
lEmitStructDecls(exportedStructTypes, f, DHI->EmitUnifs);
// Update flags
DHI->EmitUnifs = false;
if (programCount == 4) {
DHI->Emit4 = false;
}
}
else if (programCount == 8) {
DHI->Emit8 = false;
}
@@ -2457,12 +2568,12 @@ Module::writeDispatchHeader(DispatchHeaderInfo *DHI) {
// end namespace
fprintf(f, "\n");
fprintf(f, "\n#ifdef __cplusplus\n} /* namespace */\n#endif // __cplusplus\n");
// end guard
fprintf(f, "\n#endif // %s\n", guard.c_str());
DHI->EmitBackMatter = false;
}
return true;
}
@@ -2477,17 +2588,17 @@ Module::execPreprocessor(const char *infilename, llvm::raw_string_ostream *ostre
clang::DiagnosticOptions *diagOptions = new clang::DiagnosticOptions();
clang::TextDiagnosticPrinter *diagPrinter =
new clang::TextDiagnosticPrinter(stderrRaw, diagOptions);
llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs(new clang::DiagnosticIDs);
clang::DiagnosticsEngine *diagEngine =
new clang::DiagnosticsEngine(diagIDs, diagOptions, diagPrinter);
inst.setDiagnostics(diagEngine);
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_4 // 3.2, 3.3, 3.4
clang::TargetOptions &options = inst.getTargetOpts();
#else // LLVM 3.5+
const std::shared_ptr< clang::TargetOptions > &options =
const std::shared_ptr< clang::TargetOptions > &options =
std::make_shared< clang::TargetOptions >(inst.getTargetOpts());
#endif
@@ -2654,7 +2765,7 @@ lGetTargetFileName(const char *outFileName, const char *isaString, bool forceCXX
strcpy(targetOutFileName, outFileName);
strcat(targetOutFileName, "_");
strcat(targetOutFileName, isaString);
// Append ".cpp" suffix to the original file if it is *-generic target
if (forceCXX)
strcat(targetOutFileName, ".cpp");
@@ -2760,11 +2871,11 @@ lGetVaryingDispatchType(FunctionTargetVariants &funcs) {
}
}
}
// We should've found at least one variant here
// or else something fishy is going on.
Assert(resultFuncTy);
return resultFuncTy;
}
@@ -2847,7 +2958,7 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
// dispatchNum is needed to separate generic from *-generic target
int dispatchNum = i;
if ((Target::ISA)(i == Target::GENERIC) &&
if ((Target::ISA)(i == Target::GENERIC) &&
!g->target->getTreatGenericAsSmth().empty()) {
if (g->target->getTreatGenericAsSmth() == "knl_generic")
dispatchNum = Target::KNL_AVX512;
@@ -2879,7 +2990,7 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
args.push_back(&*argIter);
}
else {
llvm::CastInst *argCast =
llvm::CastInst *argCast =
llvm::CastInst::CreatePointerCast(&*argIter, targsIter->getType(),
"dpatch_arg_bitcast", callBBlock);
args.push_back(argCast);
@@ -3053,7 +3164,7 @@ lExtractOrCheckGlobals(llvm::Module *msrc, llvm::Module *mdst, bool check) {
}
#ifdef ISPC_NVPTX_ENABLED
static std::string lCBEMangle(const std::string &S)
static std::string lCBEMangle(const std::string &S)
{
std::string Result;
@@ -3102,7 +3213,7 @@ Module::CompileAndOutput(const char *srcFile,
if (m->CompileFile() == 0) {
#ifdef ISPC_NVPTX_ENABLED
/* NVPTX:
* for PTX target replace '.' with '_' in all global variables
* for PTX target replace '.' with '_' in all global variables
* a PTX identifier name must match [a-zA-Z$_][a-zA-Z$_0-9]*
*/
if (g->target->getISA() == Target::NVPTX)
@@ -3135,7 +3246,7 @@ Module::CompileAndOutput(const char *srcFile,
}
}
else if (outputType == Asm || outputType == Object) {
if (target != NULL &&
if (target != NULL &&
(strncmp(target, "generic-", 8) == 0 || strstr(target, "-generic-") != NULL)) {
Error(SourcePos(), "When using a \"generic-*\" compilation target, "
"%s output can not be used.",
@@ -3212,7 +3323,7 @@ Module::CompileAndOutput(const char *srcFile,
std::map<std::string, FunctionTargetVariants> exportedFunctions;
int errorCount = 0;
// Handle creating a "generic" header file for multiple targets
// that use exported varyings
DispatchHeaderInfo DHI;
@@ -3234,7 +3345,7 @@ Module::CompileAndOutput(const char *srcFile,
}
// Variable is needed later for approptiate dispatch function.
// It indicates if we have *-generic target.
// It indicates if we have *-generic target.
std::string treatGenericAsSmth = "";
for (unsigned int i = 0; i < targets.size(); ++i) {
@@ -3272,9 +3383,9 @@ Module::CompileAndOutput(const char *srcFile,
if (outFileName != NULL) {
std::string targetOutFileName;
// We always generate cpp file for *-generic target during multitarget compilation
if (g->target->getISA() == Target::GENERIC &&
if (g->target->getISA() == Target::GENERIC &&
!g->target->getTreatGenericAsSmth().empty()) {
targetOutFileName = lGetTargetFileName(outFileName,
targetOutFileName = lGetTargetFileName(outFileName,
g->target->getTreatGenericAsSmth().c_str(), true);
if (!m->writeOutput(CXX, targetOutFileName.c_str(), includeFileName))
return 1;
@@ -3299,14 +3410,14 @@ Module::CompileAndOutput(const char *srcFile,
// only print backmatter on the last target.
DHI.EmitBackMatter = true;
}
const char *isaName;
if (g->target->getISA() == Target::GENERIC &&
!g->target->getTreatGenericAsSmth().empty())
isaName = g->target->getTreatGenericAsSmth().c_str();
else
else
isaName = g->target->GetISAString();
std::string targetHeaderFileName =
std::string targetHeaderFileName =
lGetTargetFileName(headerFileName, isaName, false);
// write out a header w/o target name for the first target only
if (!m->writeOutput(Module::Header, headerFileName, "", &DHI)) {

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
@@ -364,60 +366,60 @@ launch_expression
}
| TOKEN_LAUNCH '[' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
{
{
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @5);
Expr *launchCount[3] = {$3, oneExpr, oneExpr};
$$ = new FunctionCallExpr($5, $7, Union(@5,@8), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ']' postfix_expression '(' ')'
{
{
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @5);
Expr *launchCount[3] = {$3, oneExpr, oneExpr};
$$ = new FunctionCallExpr($5, new ExprList(Union(@5,@6)), Union(@5,@7), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ',' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
{
{
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @7);
Expr *launchCount[3] = {$3, $5, oneExpr};
$$ = new FunctionCallExpr($7, $9, Union(@7,@10), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ',' assignment_expression ']' postfix_expression '(' ')'
{
{
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @7);
Expr *launchCount[3] = {$3, $5, oneExpr};
$$ = new FunctionCallExpr($7, new ExprList(Union(@7,@8)), Union(@7,@9), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ']' '[' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
{
{
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @8);
Expr *launchCount[3] = {$6, $3, oneExpr};
$$ = new FunctionCallExpr($8, $10, Union(@8,@11), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ']' '[' assignment_expression ']' postfix_expression '(' ')'
{
{
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @8);
Expr *launchCount[3] = {$6, $3, oneExpr};
$$ = new FunctionCallExpr($8, new ExprList(Union(@8,@9)), Union(@8,@10), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ',' assignment_expression ',' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
{
{
Expr *launchCount[3] = {$3, $5, $7};
$$ = new FunctionCallExpr($9, $11, Union(@9,@12), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ',' assignment_expression ',' assignment_expression ']' postfix_expression '(' ')'
{
{
Expr *launchCount[3] = {$3, $5, $7};
$$ = new FunctionCallExpr($9, new ExprList(Union(@9,@10)), Union(@9,@11), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ']' '[' assignment_expression ']' '[' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
{
{
Expr *launchCount[3] = {$9, $6, $3};
$$ = new FunctionCallExpr($11, $13, Union(@11,@14), true, launchCount);
}
| TOKEN_LAUNCH '[' assignment_expression ']' '[' assignment_expression ']' '[' assignment_expression ']' postfix_expression '(' ')'
{
{
Expr *launchCount[3] = {$9, $6, $3};
$$ = new FunctionCallExpr($11, new ExprList(Union(@11,@12)), Union(@11,@13), true, launchCount);
}
@@ -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 '>'
{
@@ -2272,10 +2289,10 @@ static void lAddThreadIndexCountToSymbolTable(SourcePos pos) {
Symbol *taskIndexSym = new Symbol("taskIndex", pos, type);
m->symbolTable->AddVariable(taskIndexSym);
Symbol *taskCountSym = new Symbol("taskCount", pos, type);
m->symbolTable->AddVariable(taskCountSym);
Symbol *taskIndexSym0 = new Symbol("taskIndex0", pos, type);
m->symbolTable->AddVariable(taskIndexSym0);
Symbol *taskIndexSym1 = new Symbol("taskIndex1", pos, type);
@@ -2283,7 +2300,7 @@ static void lAddThreadIndexCountToSymbolTable(SourcePos pos) {
Symbol *taskIndexSym2 = new Symbol("taskIndex2", pos, type);
m->symbolTable->AddVariable(taskIndexSym2);
Symbol *taskCountSym0 = new Symbol("taskCount0", pos, type);
m->symbolTable->AddVariable(taskCountSym0);
Symbol *taskCountSym1 = new Symbol("taskCount1", pos, type);

View File

@@ -77,6 +77,11 @@ Stmt::Optimize() {
return this;
}
Stmt *
Stmt::ReplacePolyType(const PolyType *polyType, const Type *replacement) {
return this;
}
///////////////////////////////////////////////////////////////////////////
// ExprStmt
@@ -145,11 +150,11 @@ lHasUnsizedArrays(const Type *type) {
#ifdef ISPC_NVPTX_ENABLED
static llvm::Value* lConvertToGenericPtr(FunctionEmitContext *ctx, llvm::Value *value, const SourcePos &currentPos, const bool variable = false)
{
if (!value->getType()->isPointerTy() || g->target->getISA() != Target::NVPTX)
if (!value->getType()->isPointerTy() || g->target->getISA() != Target::NVPTX)
return value;
llvm::PointerType *pt = llvm::dyn_cast<llvm::PointerType>(value->getType());
const int addressSpace = pt->getAddressSpace();
if (addressSpace != 3 && addressSpace != 4)
if (addressSpace != 3 && addressSpace != 4)
return value;
llvm::Type *elTy = pt->getElementType();
@@ -271,17 +276,17 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
#ifdef ISPC_NVPTX_ENABLED
if (g->target->getISA() == Target::NVPTX && !sym->type->IsConstType())
{
Error(sym->pos,
Error(sym->pos,
"Non-constant static variable ""\"%s\" is not supported with ""\"nvptx\" target.",
sym->name.c_str());
return;
}
if (g->target->getISA() == Target::NVPTX && sym->type->IsVaryingType())
PerformanceWarning(sym->pos,
PerformanceWarning(sym->pos,
"\"const static varying\" variable ""\"%s\" is stored in __global address space with ""\"nvptx\" target.",
sym->name.c_str());
if (g->target->getISA() == Target::NVPTX && sym->type->IsUniformType())
PerformanceWarning(sym->pos,
PerformanceWarning(sym->pos,
"\"const static uniform\" variable ""\"%s\" is stored in __constant address space with ""\"nvptx\" target.",
sym->name.c_str());
#endif /* ISPC_NVPTX_ENABLED */
@@ -346,11 +351,11 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
#ifdef ISPC_NVPTX_ENABLED
else if ((sym->type->IsUniformType() || sym->type->IsSOAType()) &&
/* NVPTX:
* only non-constant uniform data types are stored in shared memory
* constant uniform are automatically promoted to varying
* only non-constant uniform data types are stored in shared memory
* constant uniform are automatically promoted to varying
*/
!sym->type->IsConstType() &&
#if 1
#if 1
sym->type->IsArrayType() &&
#endif
g->target->getISA() == Target::NVPTX)
@@ -370,7 +375,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
* or 128 threads.
* ***note-to-me***:please define these value (128threads/4warps)
* in nvptx-target definition
* instead of compile-time constants
* instead of compile-time constants
*/
nel *= at->GetElementCount();
if (sym->type->IsSOAType())
@@ -387,9 +392,9 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
sym->storagePtr =
new llvm::GlobalVariable(*m->module, llvmTypeUn,
sym->type->IsConstType(),
llvm::GlobalValue::InternalLinkage,
llvm::GlobalValue::InternalLinkage,
cinit,
llvm::Twine("local_") +
llvm::Twine("local_") +
llvm::Twine(sym->pos.first_line) +
llvm::Twine("_") + sym->name.c_str(),
NULL,
@@ -494,6 +499,18 @@ DeclStmt::TypeCheck() {
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
DeclStmt::Print(int indent) const {
@@ -590,7 +607,7 @@ IfStmt::EmitCode(FunctionEmitContext *ctx) const {
#if 0
if (!isUniform && g->target->getISA() == Target::NVPTX)
{
/* With "nvptx" target, SIMT hardware takes care of non-uniform
/* With "nvptx" target, SIMT hardware takes care of non-uniform
* control flow. We trick ISPC to generate uniform control flow.
*/
testValue = ctx->ExtractInst(testValue, 0);
@@ -1495,9 +1512,9 @@ lUpdateVaryingCounter(int dim, int nDims, FunctionEmitContext *ctx,
// (0,1,2,3,0,1,2,3), and for the outer dimension we want
// (0,0,0,0,1,1,1,1).
int32_t delta[ISPC_MAX_NVEC];
const int vecWidth = 32;
const int vecWidth = 32;
std::vector<llvm::Constant*> constDeltaList;
for (int i = 0; i < vecWidth; ++i)
for (int i = 0; i < vecWidth; ++i)
{
int d = i;
// First, account for the effect of any dimensions at deeper
@@ -1694,7 +1711,7 @@ ForeachStmt::EmitCode(FunctionEmitContext *ctx) const {
std::vector<int> span(nDims, 0);
#ifdef ISPC_NVPTX_ENABLED
const int vectorWidth =
const int vectorWidth =
g->target->getISA() == Target::NVPTX ? 32 : g->target->getVectorWidth();
lGetSpans(nDims-1, nDims, vectorWidth, isTiled, &span[0]);
#else /* ISPC_NVPTX_ENABLED */
@@ -2174,6 +2191,21 @@ ForeachStmt::TypeCheck() {
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
ForeachStmt::EstimateCost() const {
@@ -3338,7 +3370,7 @@ lProcessPrintArg(Expr *expr, FunctionEmitContext *ctx, std::string &argTypes) {
}
else {
if (Type::Equal(baseType, AtomicType::UniformBool)) {
// Blast bools to ints, but do it here to preserve encoding for
// Blast bools to ints, but do it here to preserve encoding for
// printing 'true' or 'false'
expr = new TypeCastExpr(type->IsUniformType() ? AtomicType::UniformInt32 :
AtomicType::VaryingInt32,

3
stmt.h
View File

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

27
sym.cpp
View File

@@ -157,6 +157,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) {
@@ -184,9 +192,28 @@ SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
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;
}
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) {

17
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
@@ -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
@@ -174,6 +183,10 @@ public:
@return pointer to matching Symbol; NULL if none is found. */
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
predicate.
@@ -219,7 +232,7 @@ public:
@return Pointer to the Type, if found; otherwise NULL is returned.
*/
const Type *LookupType(const char *name) const;
/** Look for a type given a pointer.
@return True if found, False otherwise.
@@ -276,6 +289,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
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,
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;
}
}

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

543
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,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
@@ -1218,9 +1678,9 @@ PointerType::GetCDeclaration(const std::string &name) const {
}
std::string ret = baseType->GetCDeclaration("");
bool baseIsBasicVarying = (IsBasicType(baseType)) && (baseType->IsVaryingType());
if (baseIsBasicVarying) ret += std::string("(");
ret += std::string(" *");
if (isConst) ret += " const";
@@ -2062,7 +2522,7 @@ StructType::StructType(const std::string &n, const llvm::SmallVector<const Type
}
}
const std::string
const std::string
StructType::GetCStructName() const {
// only return mangled name for varying structs for backwards
// compatibility...
@@ -3122,7 +3582,7 @@ FunctionType::GetCDeclaration(const std::string &fname) const {
CastType<ArrayType>(pt->GetBaseType()) != NULL) {
type = new ArrayType(pt->GetBaseType(), 0);
}
if (paramNames[i] != "")
ret += type->GetCDeclaration(paramNames[i]);
else
@@ -3134,6 +3594,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 {
@@ -3153,11 +3641,11 @@ FunctionType::GetCDeclarationForDispatch(const std::string &fname) const {
CastType<ArrayType>(pt->GetBaseType()) != NULL) {
type = new ArrayType(pt->GetBaseType(), 0);
}
// Change pointers to varying thingies to void *
if (pt != NULL && pt->GetBaseType()->IsVaryingType()) {
PointerType *t = PointerType::Void;
if (paramNames[i] != "")
ret += t->GetCDeclaration(paramNames[i]);
else
@@ -3289,10 +3777,10 @@ FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool removeMask) const {
llvmArgTypes.push_back(LLVMTypes::MaskType);
std::vector<llvm::Type *> callTypes;
if (isTask
if (isTask
#ifdef ISPC_NVPTX_ENABLED
&& (g->target->getISA() != Target::NVPTX)
#endif
#endif
){
// Tasks take three arguments: a pointer to a struct that holds the
// actual task arguments, the thread index, and the total number of
@@ -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...
if (at0 == NULL || at1 == NULL) {
Assert(reason != NULL);
@@ -3592,6 +4098,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 +4202,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)