Compare commits
23 Commits
concept-ch
...
codegen
| Author | SHA1 | Date | |
|---|---|---|---|
| 64e1e2b008 | |||
| 192b99f21d | |||
| 871af918ad | |||
| 7bb1741b9a | |||
| aeb4c0b6f9 | |||
| 9c0f9be022 | |||
| a5306eddc1 | |||
| 0f17514eb0 | |||
| 8a1aeed55c | |||
| 05c9f63527 | |||
| c86c5097d7 | |||
| 46ed9bdb3c | |||
| 93c563e073 | |||
| b3b02df569 | |||
| 0887760de1 | |||
| 148c333943 | |||
| 98e5809d24 | |||
| 87b6ed7f4c | |||
| 259f092143 | |||
| 108c9c6fb5 | |||
| 128b40ce3c | |||
| 717aec388b | |||
| f2287d2cd7 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -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
42
ast.cpp
@@ -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
15
ast.h
@@ -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
30
ctx.cpp
@@ -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
10
ctx.h
@@ -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
106
expr.cpp
@@ -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
49
expr.h
@@ -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;
|
||||
|
||||
|
||||
69
func.cpp
69
func.cpp
@@ -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
6
func.h
@@ -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);
|
||||
|
||||
4
ispc.cpp
4
ispc.cpp
@@ -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
44
lex.ll
@@ -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} { }
|
||||
|
||||
|
||||
213
module.cpp
213
module.cpp
@@ -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)) {
|
||||
|
||||
67
parse.yy
67
parse.yy
@@ -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);
|
||||
|
||||
64
stmt.cpp
64
stmt.cpp
@@ -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 ¤tPos, 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
3
stmt.h
@@ -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
27
sym.cpp
@@ -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
17
sym.h
@@ -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
13
tests_ispcpp/Makefile
Normal 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 $<
|
||||
6
tests_ispcpp/error_0.ispc
Normal file
6
tests_ispcpp/error_0.ispc
Normal file
@@ -0,0 +1,6 @@
|
||||
//@error
|
||||
//assigning mismatched polymorphic types
|
||||
|
||||
export void foo(uniform floating$0 bar) {
|
||||
floating$1 baz = bar;
|
||||
}
|
||||
6
tests_ispcpp/error_1.ispc
Normal file
6
tests_ispcpp/error_1.ispc
Normal file
@@ -0,0 +1,6 @@
|
||||
//@error
|
||||
//assigning mismatched polymorphic types
|
||||
|
||||
export void foo(floating$0 bar) {
|
||||
floating baz = bar;
|
||||
}
|
||||
6
tests_ispcpp/error_2.ispc
Normal file
6
tests_ispcpp/error_2.ispc
Normal file
@@ -0,0 +1,6 @@
|
||||
//@error
|
||||
//assigning mismatched polymorphic types
|
||||
|
||||
export void foo(uniform floating$0 bar) {
|
||||
integer baz = bar;
|
||||
}
|
||||
6
tests_ispcpp/error_3.ispc
Normal file
6
tests_ispcpp/error_3.ispc
Normal 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
19
tests_ispcpp/error_4.ispc
Normal 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;
|
||||
}
|
||||
}
|
||||
17
tests_ispcpp/function.ispc
Normal file
17
tests_ispcpp/function.ispc
Normal 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]);
|
||||
}
|
||||
}
|
||||
@@ -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
6
tests_ispcpp/simple.ispc
Normal 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
543
type.cpp
@@ -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
89
type.h
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user