Merge branch 'master' of git://github.com/ispc/ispc

Conflicts:
	decl.cpp
This commit is contained in:
Jean-Luc Duprat
2012-04-17 10:38:07 -07:00
75 changed files with 3238 additions and 1899 deletions

View File

@@ -2,6 +2,15 @@
# ispc Makefile # ispc Makefile
# #
# If you have your own special version of llvm and/or clang, change
# these variables to match.
LLVM_CONFIG=$(shell which llvm-config)
CLANG_INCLUDE=$(shell $(LLVM_CONFIG) --includedir)
# Add llvm bin to the path so any scripts run will go to the right llvm-config
LLVM_BIN= $(shell $(LLVM_CONFIG) --bindir)
export PATH:=$(LLVM_BIN):$(PATH)
ARCH_OS = $(shell uname) ARCH_OS = $(shell uname)
ifeq ($(ARCH_OS), Darwin) ifeq ($(ARCH_OS), Darwin)
ARCH_OS2 = "OSX" ARCH_OS2 = "OSX"
@@ -10,10 +19,10 @@ else
endif endif
ARCH_TYPE = $(shell arch) ARCH_TYPE = $(shell arch)
ifeq ($(shell llvm-config --version), 3.1svn) ifeq ($(shell $(LLVM_CONFIG) --version), 3.1svn)
LLVM_LIBS=-lLLVMAsmParser -lLLVMInstrumentation -lLLVMLinker \ LLVM_LIBS=-lLLVMAsmParser -lLLVMInstrumentation -lLLVMLinker \
-lLLVMArchive -lLLVMBitReader -lLLVMDebugInfo -lLLVMJIT -lLLVMipo \ -lLLVMArchive -lLLVMBitReader -lLLVMDebugInfo -lLLVMJIT -lLLVMipo \
-lLLVMBitWriter -lLLVMTableGen -lLLVMCBackendInfo \ -lLLVMBitWriter -lLLVMTableGen \
-lLLVMX86Disassembler -lLLVMX86CodeGen -lLLVMSelectionDAG \ -lLLVMX86Disassembler -lLLVMX86CodeGen -lLLVMSelectionDAG \
-lLLVMAsmPrinter -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info \ -lLLVMAsmPrinter -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info \
-lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCDisassembler -lLLVMMCParser \ -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCDisassembler -lLLVMMCParser \
@@ -22,18 +31,18 @@ ifeq ($(shell llvm-config --version), 3.1svn)
-lLLVMExecutionEngine -lLLVMTarget -lLLVMMC -lLLVMObject -lLLVMCore \ -lLLVMExecutionEngine -lLLVMTarget -lLLVMMC -lLLVMObject -lLLVMCore \
-lLLVMSupport -lLLVMSupport
else else
LLVM_LIBS=$(shell llvm-config --libs) LLVM_LIBS=$(shell $(LLVM_CONFIG) --libs)
endif endif
CLANG=clang CLANG=clang
CLANG_LIBS = -lclangFrontend -lclangDriver \ CLANG_LIBS = -lclangFrontend -lclangDriver \
-lclangSerialization -lclangParse -lclangSema \ -lclangSerialization -lclangParse -lclangSema \
-lclangAnalysis -lclangAST -lclangLex -lclangBasic -lclangAnalysis -lclangAST -lclangLex -lclangBasic
ifeq ($(shell llvm-config --version), 3.1svn) ifeq ($(shell $(LLVM_CONFIG) --version), 3.1svn)
CLANG_LIBS += -lclangEdit CLANG_LIBS += -lclangEdit
endif endif
ISPC_LIBS=$(shell llvm-config --ldflags) $(CLANG_LIBS) $(LLVM_LIBS) \ ISPC_LIBS=$(shell $(LLVM_CONFIG) --ldflags) $(CLANG_LIBS) $(LLVM_LIBS) \
-lpthread -lpthread
ifeq ($(ARCH_OS),Linux) ifeq ($(ARCH_OS),Linux)
@@ -44,8 +53,8 @@ ifeq ($(ARCH_OS2),Msys)
ISPC_LIBS += -lshlwapi -limagehlp -lpsapi ISPC_LIBS += -lshlwapi -limagehlp -lpsapi
endif endif
LLVM_CXXFLAGS=$(shell llvm-config --cppflags) LLVM_CXXFLAGS=$(shell $(LLVM_CONFIG) --cppflags)
LLVM_VERSION=LLVM_$(shell llvm-config --version | sed s/\\./_/) LLVM_VERSION=LLVM_$(shell $(LLVM_CONFIG) --version | sed s/\\./_/)
LLVM_VERSION_DEF=-D$(LLVM_VERSION) LLVM_VERSION_DEF=-D$(LLVM_VERSION)
BUILD_DATE=$(shell date +%Y%m%d) BUILD_DATE=$(shell date +%Y%m%d)
@@ -54,7 +63,8 @@ BUILD_VERSION=$(shell git log --abbrev-commit --abbrev=16 | head -1)
CXX=g++ CXX=g++
CPP=cpp CPP=cpp
OPT=-g3 OPT=-g3
CXXFLAGS=$(OPT) $(LLVM_CXXFLAGS) -I. -Iobjs/ -Wall $(LLVM_VERSION_DEF) \ CXXFLAGS=$(OPT) $(LLVM_CXXFLAGS) -I. -Iobjs/ -I$(CLANG_INCLUDE) \
-Wall $(LLVM_VERSION_DEF) \
-DBUILD_DATE="\"$(BUILD_DATE)\"" -DBUILD_VERSION="\"$(BUILD_VERSION)\"" -DBUILD_DATE="\"$(BUILD_DATE)\"" -DBUILD_VERSION="\"$(BUILD_VERSION)\""
LDFLAGS= LDFLAGS=

56
ast.cpp
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2011, Intel Corporation Copyright (c) 2011-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,10 @@
*/ */
/** @file ast.cpp /** @file ast.cpp
@brief
*/ @brief General functionality related to abstract syntax trees and
traversal of them.
*/
#include "ast.h" #include "ast.h"
#include "expr.h" #include "expr.h"
@@ -53,10 +55,10 @@ ASTNode::~ASTNode() {
// AST // AST
void void
AST::AddFunction(Symbol *sym, const std::vector<Symbol *> &args, Stmt *code) { AST::AddFunction(Symbol *sym, Stmt *code) {
if (sym == NULL) if (sym == NULL)
return; return;
functions.push_back(new Function(sym, args, code)); functions.push_back(new Function(sym, code));
} }
@@ -151,7 +153,7 @@ WalkAST(ASTNode *node, ASTPreCallBackFunc preFunc, ASTPostCallBackFunc postFunc,
else if ((ls = dynamic_cast<LabeledStmt *>(node)) != NULL) else if ((ls = dynamic_cast<LabeledStmt *>(node)) != NULL)
ls->stmt = (Stmt *)WalkAST(ls->stmt, preFunc, postFunc, data); ls->stmt = (Stmt *)WalkAST(ls->stmt, preFunc, postFunc, data);
else if ((rs = dynamic_cast<ReturnStmt *>(node)) != NULL) else if ((rs = dynamic_cast<ReturnStmt *>(node)) != NULL)
rs->val = (Expr *)WalkAST(rs->val, preFunc, postFunc, data); rs->expr = (Expr *)WalkAST(rs->expr, preFunc, postFunc, data);
else if ((sl = dynamic_cast<StmtList *>(node)) != NULL) { else if ((sl = dynamic_cast<StmtList *>(node)) != NULL) {
std::vector<Stmt *> &sls = sl->stmts; std::vector<Stmt *> &sls = sl->stmts;
for (unsigned int i = 0; i < sls.size(); ++i) for (unsigned int i = 0; i < sls.size(); ++i)
@@ -305,19 +307,39 @@ TypeCheck(Stmt *stmt) {
} }
struct CostData {
CostData() { cost = foreachDepth = 0; }
int cost;
int foreachDepth;
};
static bool static bool
lCostCallback(ASTNode *node, void *c) { lCostCallbackPre(ASTNode *node, void *d) {
int *cost = (int *)c; CostData *data = (CostData *)d;
*cost += node->EstimateCost(); if (dynamic_cast<ForeachStmt *>(node) != NULL)
++data->foreachDepth;
if (data->foreachDepth == 0)
data->cost += node->EstimateCost();
return true; return true;
} }
static ASTNode *
lCostCallbackPost(ASTNode *node, void *d) {
CostData *data = (CostData *)d;
if (dynamic_cast<ForeachStmt *>(node) != NULL)
--data->foreachDepth;
return node;
}
int int
EstimateCost(ASTNode *root) { EstimateCost(ASTNode *root) {
int cost = 0; CostData data;
WalkAST(root, lCostCallback, NULL, &cost); WalkAST(root, lCostCallbackPre, lCostCallbackPost, &data);
return cost; return data.cost;
} }
@@ -363,6 +385,16 @@ lCheckAllOffSafety(ASTNode *node, void *data) {
return false; return false;
} }
if (dynamic_cast<ForeachStmt *>(node) != NULL) {
// foreach() statements also shouldn't be run with an all-off mask.
// Since they re-establish an 'all on' mask, this would be pretty
// unintuitive. (More generally, it's possibly a little strange to
// allow foreach() in the presence of any non-uniform control
// flow...)
*okPtr = false;
return false;
}
if (g->target.allOffMaskIsSafe == true) if (g->target.allOffMaskIsSafe == true)
// Don't worry about memory accesses if we have a target that can // Don't worry about memory accesses if we have a target that can
// safely run them with the mask all off // safely run them with the mask all off

5
ast.h
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2011, Intel Corporation Copyright (c) 2011-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -84,8 +84,7 @@ class AST {
public: public:
/** Add the AST for a function described by the given declaration /** Add the AST for a function described by the given declaration
information and source code. */ information and source code. */
void AddFunction(Symbol *sym, const std::vector<Symbol *> &args, void AddFunction(Symbol *sym, Stmt *code);
Stmt *code);
/** Generate LLVM IR for all of the functions into the current /** Generate LLVM IR for all of the functions into the current
module. */ module. */

View File

@@ -291,7 +291,7 @@ lCheckModuleIntrinsics(llvm::Module *module) {
if (!strncmp(funcName.c_str(), "llvm.x86.", 9)) { if (!strncmp(funcName.c_str(), "llvm.x86.", 9)) {
llvm::Intrinsic::ID id = (llvm::Intrinsic::ID)func->getIntrinsicID(); llvm::Intrinsic::ID id = (llvm::Intrinsic::ID)func->getIntrinsicID();
Assert(id != 0); Assert(id != 0);
LLVM_TYPE_CONST llvm::Type *intrinsicType = llvm::Type *intrinsicType =
llvm::Intrinsic::getType(*g->ctx, id); llvm::Intrinsic::getType(*g->ctx, id);
intrinsicType = llvm::PointerType::get(intrinsicType, 0); intrinsicType = llvm::PointerType::get(intrinsicType, 0);
Assert(func->getType() == intrinsicType); Assert(func->getType() == intrinsicType);
@@ -411,12 +411,16 @@ lSetInternalFunctions(llvm::Module *module) {
"__extract_int64", "__extract_int64",
"__extract_int8", "__extract_int8",
"__fastmath", "__fastmath",
"__float_to_half_uniform",
"__float_to_half_varying",
"__floatbits_uniform_int32", "__floatbits_uniform_int32",
"__floatbits_varying_int32", "__floatbits_varying_int32",
"__floor_uniform_double", "__floor_uniform_double",
"__floor_uniform_float", "__floor_uniform_float",
"__floor_varying_double", "__floor_varying_double",
"__floor_varying_float", "__floor_varying_float",
"__half_to_float_uniform",
"__half_to_float_varying",
"__insert_int16", "__insert_int16",
"__insert_int32", "__insert_int32",
"__insert_int64", "__insert_int64",
@@ -616,9 +620,7 @@ AddBitcodeToModule(const unsigned char *bitcode, int length,
std::string(linkError); std::string(linkError);
if (llvm::Linker::LinkModules(module, bcModule, if (llvm::Linker::LinkModules(module, bcModule,
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::Linker::DestroySource, llvm::Linker::DestroySource,
#endif // LLVM_3_0
&linkError)) &linkError))
Error(SourcePos(), "Error linking stdlib bitcode: %s", linkError.c_str()); Error(SourcePos(), "Error linking stdlib bitcode: %s", linkError.c_str());
lSetInternalFunctions(module); lSetInternalFunctions(module);
@@ -639,7 +641,7 @@ lDefineConstantInt(const char *name, int val, llvm::Module *module,
new Symbol(name, SourcePos(), AtomicType::UniformInt32->GetAsConstType(), new Symbol(name, SourcePos(), AtomicType::UniformInt32->GetAsConstType(),
SC_STATIC); SC_STATIC);
pw->constValue = new ConstExpr(pw->type, val, SourcePos()); pw->constValue = new ConstExpr(pw->type, val, SourcePos());
LLVM_TYPE_CONST llvm::Type *ltype = LLVMTypes::Int32Type; llvm::Type *ltype = LLVMTypes::Int32Type;
llvm::Constant *linit = LLVMInt32(val); llvm::Constant *linit = LLVMInt32(val);
pw->storagePtr = new llvm::GlobalVariable(*module, ltype, true, pw->storagePtr = new llvm::GlobalVariable(*module, ltype, true,
llvm::GlobalValue::InternalLinkage, llvm::GlobalValue::InternalLinkage,
@@ -679,7 +681,7 @@ lDefineProgramIndex(llvm::Module *module, SymbolTable *symbolTable) {
pi[i] = i; pi[i] = i;
pidx->constValue = new ConstExpr(pidx->type, pi, SourcePos()); pidx->constValue = new ConstExpr(pidx->type, pi, SourcePos());
LLVM_TYPE_CONST llvm::Type *ltype = LLVMTypes::Int32VectorType; llvm::Type *ltype = LLVMTypes::Int32VectorType;
llvm::Constant *linit = LLVMInt32Vector(pi); llvm::Constant *linit = LLVMInt32Vector(pi);
pidx->storagePtr = new llvm::GlobalVariable(*module, ltype, true, pidx->storagePtr = new llvm::GlobalVariable(*module, ltype, true,
llvm::GlobalValue::InternalLinkage, linit, llvm::GlobalValue::InternalLinkage, linit,

View File

@@ -2880,11 +2880,11 @@ define <$1 x $2> @__gather_base_offsets32_$2(i8 * %ptr, <$1 x i32> %offsets, i32
%newDelta = load <$1 x i32> * %deltaPtr %newDelta = load <$1 x i32> * %deltaPtr
%ret0 = call <$1 x $2> @__gather_elt32_$2(i8 * %ptr, <$1 x i32> %newOffsets, %ret0 = call <$1 x $2> @__gather_elt32_$2(i8 * %ptr, <$1 x i32> %newOffsets,
i32 %offset_scale, <$1 x i32> %offset_delta, i32 %offset_scale, <$1 x i32> %newDelta,
<$1 x $2> undef, i32 0) <$1 x $2> undef, i32 0)
forloop(lane, 1, eval($1-1), forloop(lane, 1, eval($1-1),
`patsubst(patsubst(`%retLANE = call <$1 x $2> @__gather_elt32_$2(i8 * %ptr, `patsubst(patsubst(`%retLANE = call <$1 x $2> @__gather_elt32_$2(i8 * %ptr,
<$1 x i32> %newOffsets, i32 %offset_scale, <$1 x i32> %offset_delta, <$1 x i32> %newOffsets, i32 %offset_scale, <$1 x i32> %newDelta,
<$1 x $2> %retPREV, i32 LANE) <$1 x $2> %retPREV, i32 LANE)
', `LANE', lane), `PREV', eval(lane-1))') ', `LANE', lane), `PREV', eval(lane-1))')
ret <$1 x $2> %ret`'eval($1-1) ret <$1 x $2> %ret`'eval($1-1)

View File

@@ -12,9 +12,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifdef LLVM_2_9 #include <stdio.h>
#warning "The C++ backend isn't supported when building with LLVM 2.9"
#else
#ifndef _MSC_VER #ifndef _MSC_VER
#include <inttypes.h> #include <inttypes.h>
@@ -933,6 +931,20 @@ void CWriter::printConstantDataSequential(ConstantDataSequential *CDS,
} }
#endif // LLVM_3_1svn #endif // LLVM_3_1svn
#ifdef LLVM_3_1svn
static inline std::string ftostr(const APFloat& V) {
std::string Buf;
if (&V.getSemantics() == &APFloat::IEEEdouble) {
raw_string_ostream(Buf) << V.convertToDouble();
return Buf;
} else if (&V.getSemantics() == &APFloat::IEEEsingle) {
raw_string_ostream(Buf) << (double)V.convertToFloat();
return Buf;
}
return "<unknown format in ftostr>"; // error
}
#endif // LLVM_3_1svn
// isFPCSafeToPrint - Returns true if we may assume that CFP may be written out // isFPCSafeToPrint - Returns true if we may assume that CFP may be written out
// textually as a double (rather than as a reference to a stack-allocated // textually as a double (rather than as a reference to a stack-allocated
// variable). We decide this by converting CFP to a string and back into a // variable). We decide this by converting CFP to a string and back into a
@@ -2071,69 +2083,16 @@ bool CWriter::doInitialization(Module &M) {
Out << "#include \"" << includeName << "\"\n"; Out << "#include \"" << includeName << "\"\n";
generateCompilerSpecificCode(Out, TD); Out << "\n/* Basic Library Function Declarations */\n";
// Function declarations
Out << "\n/* Function Declarations */\n";
Out << "extern \"C\" {\n"; Out << "extern \"C\" {\n";
Out << "int puts(unsigned char *);\n"; Out << "int puts(unsigned char *);\n";
Out << "unsigned int putchar(unsigned int);\n"; Out << "unsigned int putchar(unsigned int);\n";
Out << "int fflush(void *);\n"; Out << "int fflush(void *);\n";
Out << "int printf(const unsigned char *, ...);\n"; Out << "int printf(const unsigned char *, ...);\n";
Out << "uint8_t *memcpy(uint8_t *, uint8_t *, uint64_t );\n"; Out << "uint8_t *memcpy(uint8_t *, uint8_t *, uint64_t );\n";
Out << "}\n\n";
// Store the intrinsics which will be declared/defined below. generateCompilerSpecificCode(Out, TD);
SmallVector<const Function*, 8> intrinsicsToDefine;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
// Don't print declarations for intrinsic functions.
// Store the used intrinsics, which need to be explicitly defined.
if (I->isIntrinsic()) {
switch (I->getIntrinsicID()) {
default:
break;
case Intrinsic::uadd_with_overflow:
case Intrinsic::sadd_with_overflow:
intrinsicsToDefine.push_back(I);
break;
}
continue;
}
if (I->getName() == "setjmp" || I->getName() == "abort" ||
I->getName() == "longjmp" || I->getName() == "_setjmp" ||
I->getName() == "memset" || I->getName() == "memset_pattern16" ||
I->getName() == "puts" ||
I->getName() == "printf" || I->getName() == "putchar" ||
I->getName() == "fflush" || I->getName() == "malloc" ||
I->getName() == "free")
continue;
// Don't redeclare ispc's own intrinsics
std::string name = I->getName();
if (name.size() > 2 && name[0] == '_' && name[1] == '_')
continue;
if (I->hasExternalWeakLinkage())
Out << "extern ";
printFunctionSignature(I, true);
if (I->hasWeakLinkage() || I->hasLinkOnceLinkage())
Out << " __ATTRIBUTE_WEAK__";
if (I->hasExternalWeakLinkage())
Out << " __EXTERNAL_WEAK__";
if (StaticCtors.count(I))
Out << " __ATTRIBUTE_CTOR__";
if (StaticDtors.count(I))
Out << " __ATTRIBUTE_DTOR__";
if (I->hasHiddenVisibility())
Out << " __HIDDEN__";
if (I->hasName() && I->getName()[0] == 1)
Out << " LLVM_ASM(\"" << I->getName().substr(1) << "\")";
Out << ";\n";
}
Out << "}\n";
// Provide a definition for `bool' if not compiling with a C++ compiler. // Provide a definition for `bool' if not compiling with a C++ compiler.
Out << "\n" Out << "\n"
@@ -2303,6 +2262,63 @@ bool CWriter::doInitialization(Module &M) {
} }
} }
// Function declarations
Out << "\n/* Function Declarations */\n";
Out << "extern \"C\" {\n";
// Store the intrinsics which will be declared/defined below.
SmallVector<const Function*, 8> intrinsicsToDefine;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
// Don't print declarations for intrinsic functions.
// Store the used intrinsics, which need to be explicitly defined.
if (I->isIntrinsic()) {
switch (I->getIntrinsicID()) {
default:
break;
case Intrinsic::uadd_with_overflow:
case Intrinsic::sadd_with_overflow:
intrinsicsToDefine.push_back(I);
break;
}
continue;
}
if (I->getName() == "setjmp" || I->getName() == "abort" ||
I->getName() == "longjmp" || I->getName() == "_setjmp" ||
I->getName() == "memset" || I->getName() == "memset_pattern16" ||
I->getName() == "puts" ||
I->getName() == "printf" || I->getName() == "putchar" ||
I->getName() == "fflush" || I->getName() == "malloc" ||
I->getName() == "free")
continue;
// Don't redeclare ispc's own intrinsics
std::string name = I->getName();
if (name.size() > 2 && name[0] == '_' && name[1] == '_')
continue;
if (I->hasExternalWeakLinkage())
Out << "extern ";
printFunctionSignature(I, true);
if (I->hasWeakLinkage() || I->hasLinkOnceLinkage())
Out << " __ATTRIBUTE_WEAK__";
if (I->hasExternalWeakLinkage())
Out << " __EXTERNAL_WEAK__";
if (StaticCtors.count(I))
Out << " __ATTRIBUTE_CTOR__";
if (StaticDtors.count(I))
Out << " __ATTRIBUTE_DTOR__";
if (I->hasHiddenVisibility())
Out << " __HIDDEN__";
if (I->hasName() && I->getName()[0] == 1)
Out << " LLVM_ASM(\"" << I->getName().substr(1) << "\")";
Out << ";\n";
}
Out << "}\n\n";
if (!M.empty()) if (!M.empty())
Out << "\n\n/* Function Bodies */\n"; Out << "\n\n/* Function Bodies */\n";
@@ -4442,5 +4458,3 @@ WriteCXXFile(llvm::Module *module, const char *fn, int vectorWidth,
return true; return true;
} }
#endif // LLVM_2_9

230
ctx.cpp
View File

@@ -251,7 +251,7 @@ FunctionEmitContext::FunctionEmitContext(Function *func, Symbol *funSym,
if (!returnType || Type::Equal(returnType, AtomicType::Void)) if (!returnType || Type::Equal(returnType, AtomicType::Void))
returnValuePtr = NULL; returnValuePtr = NULL;
else { else {
LLVM_TYPE_CONST llvm::Type *ftype = returnType->LLVMType(g->ctx); llvm::Type *ftype = returnType->LLVMType(g->ctx);
returnValuePtr = AllocaInst(ftype, "return_value_memory"); returnValuePtr = AllocaInst(ftype, "return_value_memory");
} }
@@ -1050,7 +1050,7 @@ FunctionEmitContext::SwitchInst(llvm::Value *expr, llvm::BasicBlock *bbDefault,
caseBlocks = new std::vector<std::pair<int, llvm::BasicBlock *> >(bbCases); caseBlocks = new std::vector<std::pair<int, llvm::BasicBlock *> >(bbCases);
nextBlocks = new std::map<llvm::BasicBlock *, llvm::BasicBlock *>(bbNext); nextBlocks = new std::map<llvm::BasicBlock *, llvm::BasicBlock *>(bbNext);
switchConditionWasUniform = switchConditionWasUniform =
(llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(expr->getType()) == false); (llvm::isa<llvm::VectorType>(expr->getType()) == false);
if (switchConditionWasUniform == true) { if (switchConditionWasUniform == true) {
// For a uniform switch condition, just wire things up to the LLVM // For a uniform switch condition, just wire things up to the LLVM
@@ -1325,12 +1325,12 @@ FunctionEmitContext::I1VecToBoolVec(llvm::Value *b) {
if (g->target.maskBitCount == 1) if (g->target.maskBitCount == 1)
return b; return b;
LLVM_TYPE_CONST llvm::ArrayType *at = llvm::ArrayType *at =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::ArrayType>(b->getType()); llvm::dyn_cast<llvm::ArrayType>(b->getType());
if (at) { if (at) {
// If we're given an array of vectors of i1s, then do the // If we're given an array of vectors of i1s, then do the
// conversion for each of the elements // conversion for each of the elements
LLVM_TYPE_CONST llvm::Type *boolArrayType = llvm::Type *boolArrayType =
llvm::ArrayType::get(LLVMTypes::BoolVectorType, at->getNumElements()); llvm::ArrayType::get(LLVMTypes::BoolVectorType, at->getNumElements());
llvm::Value *ret = llvm::UndefValue::get(boolArrayType); llvm::Value *ret = llvm::UndefValue::get(boolArrayType);
@@ -1359,13 +1359,8 @@ lGetStringAsValue(llvm::BasicBlock *bblock, const char *s) {
llvm::GlobalValue::InternalLinkage, llvm::GlobalValue::InternalLinkage,
sConstant, s); sConstant, s);
llvm::Value *indices[2] = { LLVMInt32(0), LLVMInt32(0) }; llvm::Value *indices[2] = { LLVMInt32(0), LLVMInt32(0) };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> arrayRef(&indices[0], &indices[2]); llvm::ArrayRef<llvm::Value *> arrayRef(&indices[0], &indices[2]);
return llvm::GetElementPtrInst::Create(sPtr, arrayRef, "sptr", bblock); return llvm::GetElementPtrInst::Create(sPtr, arrayRef, "sptr", bblock);
#else
return llvm::GetElementPtrInst::Create(sPtr, &indices[0], &indices[2],
"sptr", bblock);
#endif
} }
@@ -1498,16 +1493,16 @@ FunctionEmitContext::EmitFunctionParameterDebugInfo(Symbol *sym) {
Otherwise return zero. Otherwise return zero.
*/ */
static int static int
lArrayVectorWidth(LLVM_TYPE_CONST llvm::Type *t) { lArrayVectorWidth(llvm::Type *t) {
LLVM_TYPE_CONST llvm::ArrayType *arrayType = llvm::ArrayType *arrayType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::ArrayType>(t); llvm::dyn_cast<llvm::ArrayType>(t);
if (arrayType == NULL) if (arrayType == NULL)
return 0; return 0;
// We shouldn't be seeing arrays of anything but vectors being passed // We shouldn't be seeing arrays of anything but vectors being passed
// to things like FunctionEmitContext::BinaryOperator() as operands. // to things like FunctionEmitContext::BinaryOperator() as operands.
LLVM_TYPE_CONST llvm::VectorType *vectorElementType = llvm::VectorType *vectorElementType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(arrayType->getElementType()); llvm::dyn_cast<llvm::VectorType>(arrayType->getElementType());
Assert((vectorElementType != NULL && Assert((vectorElementType != NULL &&
(int)vectorElementType->getNumElements() == g->target.vectorWidth)); (int)vectorElementType->getNumElements() == g->target.vectorWidth));
@@ -1525,7 +1520,7 @@ FunctionEmitContext::BinaryOperator(llvm::Instruction::BinaryOps inst,
} }
Assert(v0->getType() == v1->getType()); Assert(v0->getType() == v1->getType());
LLVM_TYPE_CONST llvm::Type *type = v0->getType(); llvm::Type *type = v0->getType();
int arraySize = lArrayVectorWidth(type); int arraySize = lArrayVectorWidth(type);
if (arraySize == 0) { if (arraySize == 0) {
llvm::Instruction *bop = llvm::Instruction *bop =
@@ -1559,7 +1554,7 @@ FunctionEmitContext::NotOperator(llvm::Value *v, const char *name) {
// Similarly to BinaryOperator, do the operation on all the elements of // Similarly to BinaryOperator, do the operation on all the elements of
// the array if we're given an array type; otherwise just do the // the array if we're given an array type; otherwise just do the
// regular llvm operation. // regular llvm operation.
LLVM_TYPE_CONST llvm::Type *type = v->getType(); llvm::Type *type = v->getType();
int arraySize = lArrayVectorWidth(type); int arraySize = lArrayVectorWidth(type);
if (arraySize == 0) { if (arraySize == 0) {
llvm::Instruction *binst = llvm::Instruction *binst =
@@ -1584,18 +1579,18 @@ FunctionEmitContext::NotOperator(llvm::Value *v, const char *name) {
// Given the llvm Type that represents an ispc VectorType, return an // Given the llvm Type that represents an ispc VectorType, return an
// equally-shaped type with boolean elements. (This is the type that will // equally-shaped type with boolean elements. (This is the type that will
// be returned from CmpInst with ispc VectorTypes). // be returned from CmpInst with ispc VectorTypes).
static LLVM_TYPE_CONST llvm::Type * static llvm::Type *
lGetMatchingBoolVectorType(LLVM_TYPE_CONST llvm::Type *type) { lGetMatchingBoolVectorType(llvm::Type *type) {
LLVM_TYPE_CONST llvm::ArrayType *arrayType = llvm::ArrayType *arrayType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::ArrayType>(type); llvm::dyn_cast<llvm::ArrayType>(type);
Assert(arrayType != NULL); Assert(arrayType != NULL);
LLVM_TYPE_CONST llvm::VectorType *vectorElementType = llvm::VectorType *vectorElementType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(arrayType->getElementType()); llvm::dyn_cast<llvm::VectorType>(arrayType->getElementType());
Assert(vectorElementType != NULL); Assert(vectorElementType != NULL);
Assert((int)vectorElementType->getNumElements() == g->target.vectorWidth); Assert((int)vectorElementType->getNumElements() == g->target.vectorWidth);
LLVM_TYPE_CONST llvm::Type *base = llvm::Type *base =
llvm::VectorType::get(LLVMTypes::BoolType, g->target.vectorWidth); llvm::VectorType::get(LLVMTypes::BoolType, g->target.vectorWidth);
return llvm::ArrayType::get(base, arrayType->getNumElements()); return llvm::ArrayType::get(base, arrayType->getNumElements());
} }
@@ -1612,7 +1607,7 @@ FunctionEmitContext::CmpInst(llvm::Instruction::OtherOps inst,
} }
Assert(v0->getType() == v1->getType()); Assert(v0->getType() == v1->getType());
LLVM_TYPE_CONST llvm::Type *type = v0->getType(); llvm::Type *type = v0->getType();
int arraySize = lArrayVectorWidth(type); int arraySize = lArrayVectorWidth(type);
if (arraySize == 0) { if (arraySize == 0) {
llvm::Instruction *ci = llvm::Instruction *ci =
@@ -1622,7 +1617,7 @@ FunctionEmitContext::CmpInst(llvm::Instruction::OtherOps inst,
return ci; return ci;
} }
else { else {
LLVM_TYPE_CONST llvm::Type *boolType = lGetMatchingBoolVectorType(type); llvm::Type *boolType = lGetMatchingBoolVectorType(type);
llvm::Value *ret = llvm::UndefValue::get(boolType); llvm::Value *ret = llvm::UndefValue::get(boolType);
for (int i = 0; i < arraySize; ++i) { for (int i = 0; i < arraySize; ++i) {
llvm::Value *a = ExtractInst(v0, i); llvm::Value *a = ExtractInst(v0, i);
@@ -1643,10 +1638,10 @@ FunctionEmitContext::SmearUniform(llvm::Value *value, const char *name) {
} }
llvm::Value *ret = NULL; llvm::Value *ret = NULL;
LLVM_TYPE_CONST llvm::Type *eltType = value->getType(); llvm::Type *eltType = value->getType();
LLVM_TYPE_CONST llvm::PointerType *pt = llvm::PointerType *pt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(eltType); llvm::dyn_cast<llvm::PointerType>(eltType);
if (pt != NULL) { if (pt != NULL) {
// Varying pointers are represented as vectors of i32/i64s // Varying pointers are represented as vectors of i32/i64s
ret = llvm::UndefValue::get(LLVMTypes::VoidPointerVectorType); ret = llvm::UndefValue::get(LLVMTypes::VoidPointerVectorType);
@@ -1670,7 +1665,7 @@ FunctionEmitContext::SmearUniform(llvm::Value *value, const char *name) {
llvm::Value * llvm::Value *
FunctionEmitContext::BitCastInst(llvm::Value *value, FunctionEmitContext::BitCastInst(llvm::Value *value,
LLVM_TYPE_CONST llvm::Type *type, llvm::Type *type,
const char *name) { const char *name) {
if (value == NULL) { if (value == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
@@ -1691,11 +1686,11 @@ FunctionEmitContext::PtrToIntInst(llvm::Value *value, const char *name) {
return NULL; return NULL;
} }
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(value->getType())) if (llvm::isa<llvm::VectorType>(value->getType()))
// no-op for varying pointers; they're already vectors of ints // no-op for varying pointers; they're already vectors of ints
return value; return value;
LLVM_TYPE_CONST llvm::Type *type = LLVMTypes::PointerIntType; llvm::Type *type = LLVMTypes::PointerIntType;
llvm::Instruction *inst = llvm::Instruction *inst =
new llvm::PtrToIntInst(value, type, name ? name : "ptr2int", bblock); new llvm::PtrToIntInst(value, type, name ? name : "ptr2int", bblock);
AddDebugPos(inst); AddDebugPos(inst);
@@ -1705,15 +1700,15 @@ FunctionEmitContext::PtrToIntInst(llvm::Value *value, const char *name) {
llvm::Value * llvm::Value *
FunctionEmitContext::PtrToIntInst(llvm::Value *value, FunctionEmitContext::PtrToIntInst(llvm::Value *value,
LLVM_TYPE_CONST llvm::Type *toType, llvm::Type *toType,
const char *name) { const char *name) {
if (value == NULL) { if (value == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
} }
LLVM_TYPE_CONST llvm::Type *fromType = value->getType(); llvm::Type *fromType = value->getType();
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(fromType)) { if (llvm::isa<llvm::VectorType>(fromType)) {
// varying pointer // varying pointer
if (fromType == toType) if (fromType == toType)
// already the right type--done // already the right type--done
@@ -1736,15 +1731,15 @@ FunctionEmitContext::PtrToIntInst(llvm::Value *value,
llvm::Value * llvm::Value *
FunctionEmitContext::IntToPtrInst(llvm::Value *value, FunctionEmitContext::IntToPtrInst(llvm::Value *value,
LLVM_TYPE_CONST llvm::Type *toType, llvm::Type *toType,
const char *name) { const char *name) {
if (value == NULL) { if (value == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
} }
LLVM_TYPE_CONST llvm::Type *fromType = value->getType(); llvm::Type *fromType = value->getType();
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(fromType)) { if (llvm::isa<llvm::VectorType>(fromType)) {
// varying pointer // varying pointer
if (fromType == toType) if (fromType == toType)
// done // done
@@ -1766,7 +1761,7 @@ FunctionEmitContext::IntToPtrInst(llvm::Value *value,
llvm::Instruction * llvm::Instruction *
FunctionEmitContext::TruncInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, FunctionEmitContext::TruncInst(llvm::Value *value, llvm::Type *type,
const char *name) { const char *name) {
if (value == NULL) { if (value == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
@@ -1784,7 +1779,7 @@ FunctionEmitContext::TruncInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *t
llvm::Instruction * llvm::Instruction *
FunctionEmitContext::CastInst(llvm::Instruction::CastOps op, llvm::Value *value, FunctionEmitContext::CastInst(llvm::Instruction::CastOps op, llvm::Value *value,
LLVM_TYPE_CONST llvm::Type *type, const char *name) { llvm::Type *type, const char *name) {
if (value == NULL) { if (value == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
@@ -1800,7 +1795,7 @@ FunctionEmitContext::CastInst(llvm::Instruction::CastOps op, llvm::Value *value,
llvm::Instruction * llvm::Instruction *
FunctionEmitContext::FPCastInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, FunctionEmitContext::FPCastInst(llvm::Value *value, llvm::Type *type,
const char *name) { const char *name) {
if (value == NULL) { if (value == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
@@ -1817,7 +1812,7 @@ FunctionEmitContext::FPCastInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *
llvm::Instruction * llvm::Instruction *
FunctionEmitContext::SExtInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, FunctionEmitContext::SExtInst(llvm::Value *value, llvm::Type *type,
const char *name) { const char *name) {
if (value == NULL) { if (value == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
@@ -1834,7 +1829,7 @@ FunctionEmitContext::SExtInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *ty
llvm::Instruction * llvm::Instruction *
FunctionEmitContext::ZExtInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, FunctionEmitContext::ZExtInst(llvm::Value *value, llvm::Type *type,
const char *name) { const char *name) {
if (value == NULL) { if (value == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
@@ -1865,7 +1860,7 @@ FunctionEmitContext::applyVaryingGEP(llvm::Value *basePtr, llvm::Value *index,
llvm::Value *scale = g->target.SizeOf(scaleType->LLVMType(g->ctx), bblock); llvm::Value *scale = g->target.SizeOf(scaleType->LLVMType(g->ctx), bblock);
bool indexIsVarying = bool indexIsVarying =
llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(index->getType()); llvm::isa<llvm::VectorType>(index->getType());
llvm::Value *offset = NULL; llvm::Value *offset = NULL;
if (indexIsVarying == false) { if (indexIsVarying == false) {
// Truncate or sign extend the index as appropriate to a 32 or // Truncate or sign extend the index as appropriate to a 32 or
@@ -1909,7 +1904,7 @@ FunctionEmitContext::applyVaryingGEP(llvm::Value *basePtr, llvm::Value *index,
// Smear out the pointer to be varying; either the base pointer or the // Smear out the pointer to be varying; either the base pointer or the
// index must be varying for this method to be called. // index must be varying for this method to be called.
bool baseIsUniform = bool baseIsUniform =
(llvm::isa<LLVM_TYPE_CONST llvm::PointerType>(basePtr->getType())); (llvm::isa<llvm::PointerType>(basePtr->getType()));
Assert(baseIsUniform == false || indexIsVarying == true); Assert(baseIsUniform == false || indexIsVarying == true);
llvm::Value *varyingPtr = baseIsUniform ? llvm::Value *varyingPtr = baseIsUniform ?
SmearUniform(basePtr, "ptr_smear") : basePtr; SmearUniform(basePtr, "ptr_smear") : basePtr;
@@ -1921,18 +1916,18 @@ FunctionEmitContext::applyVaryingGEP(llvm::Value *basePtr, llvm::Value *index,
void void
FunctionEmitContext::MatchIntegerTypes(llvm::Value **v0, llvm::Value **v1) { FunctionEmitContext::MatchIntegerTypes(llvm::Value **v0, llvm::Value **v1) {
LLVM_TYPE_CONST llvm::Type *type0 = (*v0)->getType(); llvm::Type *type0 = (*v0)->getType();
LLVM_TYPE_CONST llvm::Type *type1 = (*v1)->getType(); llvm::Type *type1 = (*v1)->getType();
// First, promote to a vector type if one of the two values is a vector // First, promote to a vector type if one of the two values is a vector
// type // type
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(type0) && if (llvm::isa<llvm::VectorType>(type0) &&
!llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(type1)) { !llvm::isa<llvm::VectorType>(type1)) {
*v1 = SmearUniform(*v1, "smear_v1"); *v1 = SmearUniform(*v1, "smear_v1");
type1 = (*v1)->getType(); type1 = (*v1)->getType();
} }
if (!llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(type0) && if (!llvm::isa<llvm::VectorType>(type0) &&
llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(type1)) { llvm::isa<llvm::VectorType>(type1)) {
*v0 = SmearUniform(*v0, "smear_v0"); *v0 = SmearUniform(*v0, "smear_v0");
type0 = (*v0)->getType(); type0 = (*v0)->getType();
} }
@@ -1969,7 +1964,7 @@ lComputeSliceIndex(FunctionEmitContext *ctx, int soaWidth,
ctx->MatchIntegerTypes(&indexValue, &ptrSliceOffset); ctx->MatchIntegerTypes(&indexValue, &ptrSliceOffset);
LLVM_TYPE_CONST llvm::Type *indexType = indexValue->getType(); llvm::Type *indexType = indexValue->getType();
llvm::Value *shift = LLVMIntAsType(logWidth, indexType); llvm::Value *shift = LLVMIntAsType(logWidth, indexType);
llvm::Value *mask = LLVMIntAsType(soaWidth-1, indexType); llvm::Value *mask = LLVMIntAsType(soaWidth-1, indexType);
@@ -1997,10 +1992,10 @@ FunctionEmitContext::MakeSlicePointer(llvm::Value *ptr, llvm::Value *offset) {
// Create a small struct where the first element is the type of the // Create a small struct where the first element is the type of the
// given pointer and the second element is the type of the offset // given pointer and the second element is the type of the offset
// value. // value.
std::vector<LLVM_TYPE_CONST llvm::Type *> eltTypes; std::vector<llvm::Type *> eltTypes;
eltTypes.push_back(ptr->getType()); eltTypes.push_back(ptr->getType());
eltTypes.push_back(offset->getType()); eltTypes.push_back(offset->getType());
LLVM_TYPE_CONST llvm::StructType *st = llvm::StructType *st =
llvm::StructType::get(*g->ctx, eltTypes); llvm::StructType::get(*g->ctx, eltTypes);
llvm::Value *ret = llvm::UndefValue::get(st); llvm::Value *ret = llvm::UndefValue::get(st);
@@ -2028,7 +2023,7 @@ FunctionEmitContext::GetElementPtrInst(llvm::Value *basePtr, llvm::Value *index,
} }
if (ptrType->IsSlice()) { if (ptrType->IsSlice()) {
Assert(llvm::isa<LLVM_TYPE_CONST llvm::StructType>(basePtr->getType())); Assert(llvm::isa<llvm::StructType>(basePtr->getType()));
llvm::Value *ptrSliceOffset = ExtractInst(basePtr, 1); llvm::Value *ptrSliceOffset = ExtractInst(basePtr, 1);
if (ptrType->IsFrozenSlice() == false) { if (ptrType->IsFrozenSlice() == false) {
@@ -2056,27 +2051,21 @@ FunctionEmitContext::GetElementPtrInst(llvm::Value *basePtr, llvm::Value *index,
// Double-check consistency between the given pointer type and its LLVM // Double-check consistency between the given pointer type and its LLVM
// type. // type.
if (ptrType->IsUniformType()) if (ptrType->IsUniformType())
Assert(llvm::isa<LLVM_TYPE_CONST llvm::PointerType>(basePtr->getType())); Assert(llvm::isa<llvm::PointerType>(basePtr->getType()));
else if (ptrType->IsVaryingType()) else if (ptrType->IsVaryingType())
Assert(llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(basePtr->getType())); Assert(llvm::isa<llvm::VectorType>(basePtr->getType()));
bool indexIsVaryingType = bool indexIsVaryingType =
llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(index->getType()); llvm::isa<llvm::VectorType>(index->getType());
if (indexIsVaryingType == false && ptrType->IsUniformType() == true) { if (indexIsVaryingType == false && ptrType->IsUniformType() == true) {
// The easy case: both the base pointer and the indices are // The easy case: both the base pointer and the indices are
// uniform, so just emit the regular LLVM GEP instruction // uniform, so just emit the regular LLVM GEP instruction
llvm::Value *ind[1] = { index }; llvm::Value *ind[1] = { index };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> arrayRef(&ind[0], &ind[1]); llvm::ArrayRef<llvm::Value *> arrayRef(&ind[0], &ind[1]);
llvm::Instruction *inst = llvm::Instruction *inst =
llvm::GetElementPtrInst::Create(basePtr, arrayRef, llvm::GetElementPtrInst::Create(basePtr, arrayRef,
name ? name : "gep", bblock); name ? name : "gep", bblock);
#else
llvm::Instruction *inst =
llvm::GetElementPtrInst::Create(basePtr, &ind[0], &ind[1],
name ? name : "gep", bblock);
#endif
AddDebugPos(inst); AddDebugPos(inst);
return inst; return inst;
} }
@@ -2107,7 +2096,7 @@ FunctionEmitContext::GetElementPtrInst(llvm::Value *basePtr, llvm::Value *index0
// Similar to the 1D GEP implementation above, for non-frozen slice // Similar to the 1D GEP implementation above, for non-frozen slice
// pointers we do the two-step indexing calculation and then pass // pointers we do the two-step indexing calculation and then pass
// the new major index on to a recursive GEP call. // the new major index on to a recursive GEP call.
Assert(llvm::isa<LLVM_TYPE_CONST llvm::StructType>(basePtr->getType())); Assert(llvm::isa<llvm::StructType>(basePtr->getType()));
llvm::Value *ptrSliceOffset = ExtractInst(basePtr, 1); llvm::Value *ptrSliceOffset = ExtractInst(basePtr, 1);
if (ptrType->IsFrozenSlice() == false) { if (ptrType->IsFrozenSlice() == false) {
llvm::Value *newSliceOffset; llvm::Value *newSliceOffset;
@@ -2124,25 +2113,19 @@ FunctionEmitContext::GetElementPtrInst(llvm::Value *basePtr, llvm::Value *index0
} }
bool index0IsVaryingType = bool index0IsVaryingType =
llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(index0->getType()); llvm::isa<llvm::VectorType>(index0->getType());
bool index1IsVaryingType = bool index1IsVaryingType =
llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(index1->getType()); llvm::isa<llvm::VectorType>(index1->getType());
if (index0IsVaryingType == false && index1IsVaryingType == false && if (index0IsVaryingType == false && index1IsVaryingType == false &&
ptrType->IsUniformType() == true) { ptrType->IsUniformType() == true) {
// The easy case: both the base pointer and the indices are // The easy case: both the base pointer and the indices are
// uniform, so just emit the regular LLVM GEP instruction // uniform, so just emit the regular LLVM GEP instruction
llvm::Value *indices[2] = { index0, index1 }; llvm::Value *indices[2] = { index0, index1 };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> arrayRef(&indices[0], &indices[2]); llvm::ArrayRef<llvm::Value *> arrayRef(&indices[0], &indices[2]);
llvm::Instruction *inst = llvm::Instruction *inst =
llvm::GetElementPtrInst::Create(basePtr, arrayRef, llvm::GetElementPtrInst::Create(basePtr, arrayRef,
name ? name : "gep", bblock); name ? name : "gep", bblock);
#else
llvm::Instruction *inst =
llvm::GetElementPtrInst::Create(basePtr, &indices[0], &indices[2],
name ? name : "gep", bblock);
#endif
AddDebugPos(inst); AddDebugPos(inst);
return inst; return inst;
} }
@@ -2157,7 +2140,7 @@ FunctionEmitContext::GetElementPtrInst(llvm::Value *basePtr, llvm::Value *index0
Assert(st != NULL); Assert(st != NULL);
bool ptr0IsUniform = bool ptr0IsUniform =
llvm::isa<LLVM_TYPE_CONST llvm::PointerType>(ptr0->getType()); llvm::isa<llvm::PointerType>(ptr0->getType());
const Type *ptr0BaseType = st->GetElementType(); const Type *ptr0BaseType = st->GetElementType();
const Type *ptr0Type = ptr0IsUniform ? const Type *ptr0Type = ptr0IsUniform ?
PointerType::GetUniform(ptr0BaseType) : PointerType::GetUniform(ptr0BaseType) :
@@ -2192,7 +2175,7 @@ FunctionEmitContext::AddElementOffset(llvm::Value *fullBasePtr, int elementNum,
// unfortunate... // unfortunate...
llvm::Value *basePtr = fullBasePtr; llvm::Value *basePtr = fullBasePtr;
bool baseIsSlicePtr = bool baseIsSlicePtr =
llvm::isa<LLVM_TYPE_CONST llvm::StructType>(fullBasePtr->getType()); llvm::isa<llvm::StructType>(fullBasePtr->getType());
const PointerType *rpt; const PointerType *rpt;
if (baseIsSlicePtr) { if (baseIsSlicePtr) {
Assert(ptrType != NULL); Assert(ptrType != NULL);
@@ -2222,16 +2205,10 @@ FunctionEmitContext::AddElementOffset(llvm::Value *fullBasePtr, int elementNum,
if (ptrType == NULL || ptrType->IsUniformType()) { if (ptrType == NULL || ptrType->IsUniformType()) {
// If the pointer is uniform, we can use the regular LLVM GEP. // If the pointer is uniform, we can use the regular LLVM GEP.
llvm::Value *offsets[2] = { LLVMInt32(0), LLVMInt32(elementNum) }; llvm::Value *offsets[2] = { LLVMInt32(0), LLVMInt32(elementNum) };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> arrayRef(&offsets[0], &offsets[2]); llvm::ArrayRef<llvm::Value *> arrayRef(&offsets[0], &offsets[2]);
resultPtr = resultPtr =
llvm::GetElementPtrInst::Create(basePtr, arrayRef, llvm::GetElementPtrInst::Create(basePtr, arrayRef,
name ? name : "struct_offset", bblock); name ? name : "struct_offset", bblock);
#else
resultPtr =
llvm::GetElementPtrInst::Create(basePtr, &offsets[0], &offsets[2],
name ? name : "struct_offset", bblock);
#endif
} }
else { else {
// Otherwise do the math to find the offset and add it to the given // Otherwise do the math to find the offset and add it to the given
@@ -2286,8 +2263,8 @@ FunctionEmitContext::LoadInst(llvm::Value *ptr, const char *name) {
return NULL; return NULL;
} }
LLVM_TYPE_CONST llvm::PointerType *pt = llvm::PointerType *pt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(ptr->getType()); llvm::dyn_cast<llvm::PointerType>(ptr->getType());
Assert(pt != NULL); Assert(pt != NULL);
// FIXME: it's not clear to me that we generate unaligned vector loads // FIXME: it's not clear to me that we generate unaligned vector loads
@@ -2295,7 +2272,7 @@ FunctionEmitContext::LoadInst(llvm::Value *ptr, const char *name) {
// optimization passes that lower gathers to vector loads, I think..) // optimization passes that lower gathers to vector loads, I think..)
// So remove this?? // So remove this??
int align = 0; int align = 0;
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(pt->getElementType())) if (llvm::isa<llvm::VectorType>(pt->getElementType()))
align = 1; align = 1;
llvm::Instruction *inst = new llvm::LoadInst(ptr, name ? name : "load", llvm::Instruction *inst = new llvm::LoadInst(ptr, name ? name : "load",
false /* not volatile */, false /* not volatile */,
@@ -2355,7 +2332,7 @@ FunctionEmitContext::loadUniformFromSOA(llvm::Value *ptr, llvm::Value *mask,
// If we have a struct/array, we need to decompose it into // If we have a struct/array, we need to decompose it into
// individual element loads to fill in the result structure since // individual element loads to fill in the result structure since
// the SOA slice of values we need isn't contiguous in memory... // the SOA slice of values we need isn't contiguous in memory...
LLVM_TYPE_CONST llvm::Type *llvmReturnType = unifType->LLVMType(g->ctx); llvm::Type *llvmReturnType = unifType->LLVMType(g->ctx);
llvm::Value *retValue = llvm::UndefValue::get(llvmReturnType); llvm::Value *retValue = llvm::UndefValue::get(llvmReturnType);
for (int i = 0; i < ct->GetElementCount(); ++i) { for (int i = 0; i < ct->GetElementCount(); ++i) {
@@ -2439,7 +2416,7 @@ FunctionEmitContext::gather(llvm::Value *ptr, const PointerType *ptrType,
Assert(ptrType->IsVaryingType()); Assert(ptrType->IsVaryingType());
const Type *returnType = ptrType->GetBaseType()->GetAsVaryingType(); const Type *returnType = ptrType->GetBaseType()->GetAsVaryingType();
LLVM_TYPE_CONST llvm::Type *llvmReturnType = returnType->LLVMType(g->ctx); llvm::Type *llvmReturnType = returnType->LLVMType(g->ctx);
const CollectionType *collectionType = const CollectionType *collectionType =
dynamic_cast<const CollectionType *>(ptrType->GetBaseType()); dynamic_cast<const CollectionType *>(ptrType->GetBaseType());
@@ -2547,7 +2524,7 @@ FunctionEmitContext::addGSMetadata(llvm::Value *v, SourcePos pos) {
llvm::Value * llvm::Value *
FunctionEmitContext::AllocaInst(LLVM_TYPE_CONST llvm::Type *llvmType, FunctionEmitContext::AllocaInst(llvm::Type *llvmType,
const char *name, int align, const char *name, int align,
bool atEntryBlock) { bool atEntryBlock) {
if (llvmType == NULL) { if (llvmType == NULL) {
@@ -2573,10 +2550,10 @@ FunctionEmitContext::AllocaInst(LLVM_TYPE_CONST llvm::Type *llvmType,
// unlikely that this array will be loaded into varying variables with // unlikely that this array will be loaded into varying variables with
// what will be aligned accesses if the uniform -> varying load is done // what will be aligned accesses if the uniform -> varying load is done
// in regular chunks. // in regular chunks.
LLVM_TYPE_CONST llvm::ArrayType *arrayType = llvm::ArrayType *arrayType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::ArrayType>(llvmType); llvm::dyn_cast<llvm::ArrayType>(llvmType);
if (align == 0 && arrayType != NULL && if (align == 0 && arrayType != NULL &&
!llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(arrayType->getElementType())) !llvm::isa<llvm::VectorType>(arrayType->getElementType()))
align = 4 * g->target.nativeVectorWidth; align = 4 * g->target.nativeVectorWidth;
if (align != 0) if (align != 0)
@@ -2632,14 +2609,22 @@ FunctionEmitContext::maskedStore(llvm::Value *value, llvm::Value *ptr,
const PointerType *pt = dynamic_cast<const PointerType *>(valueType); const PointerType *pt = dynamic_cast<const PointerType *>(valueType);
if (pt != NULL) { if (pt != NULL) {
if (pt->IsSlice()) { if (pt->IsSlice()) {
// For masked stores of (varying) slice pointers to memory, we // Masked store of (varying) slice pointer.
// grab the equivalent StructType and make a recursive call to Assert(pt->IsVaryingType());
// maskedStore, giving it that type for the pointer type; that
// in turn will lead to the base pointer and offset index being // First, extract the pointer from the slice struct and masked
// mask stored to memory.. // store that.
const StructType *sliceStructType = pt->GetSliceStructType(); llvm::Value *v0 = ExtractInst(value, 0);
ptrType = PointerType::GetUniform(sliceStructType); llvm::Value *p0 = AddElementOffset(ptr, 0, ptrType);
maskedStore(value, ptr, ptrType, mask); maskedStore(v0, p0, PointerType::GetUniform(pt->GetAsNonSlice()),
mask);
// And then do same for the integer offset
llvm::Value *v1 = ExtractInst(value, 1);
llvm::Value *p1 = AddElementOffset(ptr, 1, ptrType);
const Type *offsetType = AtomicType::VaryingInt32;
maskedStore(v1, p1, PointerType::GetUniform(offsetType), mask);
return; return;
} }
@@ -2783,7 +2768,7 @@ FunctionEmitContext::scatter(llvm::Value *value, llvm::Value *ptr,
Assert(pt != NULL || Assert(pt != NULL ||
dynamic_cast<const AtomicType *>(valueType) != NULL); dynamic_cast<const AtomicType *>(valueType) != NULL);
LLVM_TYPE_CONST llvm::Type *type = value->getType(); llvm::Type *type = value->getType();
const char *funcName = NULL; const char *funcName = NULL;
if (pt != NULL) if (pt != NULL)
funcName = g->target.is32Bit ? "__pseudo_scatter32_32" : funcName = g->target.is32Bit ? "__pseudo_scatter32_32" :
@@ -2980,7 +2965,7 @@ FunctionEmitContext::ExtractInst(llvm::Value *v, int elt, const char *name) {
} }
llvm::Instruction *ei = NULL; llvm::Instruction *ei = NULL;
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(v->getType())) if (llvm::isa<llvm::VectorType>(v->getType()))
ei = llvm::ExtractElementInst::Create(v, LLVMInt32(elt), ei = llvm::ExtractElementInst::Create(v, LLVMInt32(elt),
name ? name : "extract", bblock); name ? name : "extract", bblock);
else else
@@ -3000,7 +2985,7 @@ FunctionEmitContext::InsertInst(llvm::Value *v, llvm::Value *eltVal, int elt,
} }
llvm::Instruction *ii = NULL; llvm::Instruction *ii = NULL;
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(v->getType())) if (llvm::isa<llvm::VectorType>(v->getType()))
ii = llvm::InsertElementInst::Create(v, eltVal, LLVMInt32(elt), ii = llvm::InsertElementInst::Create(v, eltVal, LLVMInt32(elt),
name ? name : "insert", bblock); name ? name : "insert", bblock);
else else
@@ -3012,12 +2997,9 @@ FunctionEmitContext::InsertInst(llvm::Value *v, llvm::Value *eltVal, int elt,
llvm::PHINode * llvm::PHINode *
FunctionEmitContext::PhiNode(LLVM_TYPE_CONST llvm::Type *type, int count, FunctionEmitContext::PhiNode(llvm::Type *type, int count,
const char *name) { const char *name) {
llvm::PHINode *pn = llvm::PHINode::Create(type, llvm::PHINode *pn = llvm::PHINode::Create(type, count,
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
count,
#endif // LLVM_3_0
name ? name : "phi", bblock); name ? name : "phi", bblock);
AddDebugPos(pn); AddDebugPos(pn);
return pn; return pn;
@@ -3045,18 +3027,18 @@ FunctionEmitContext::SelectInst(llvm::Value *test, llvm::Value *val0,
function has. */ function has. */
static unsigned int static unsigned int
lCalleeArgCount(llvm::Value *callee, const FunctionType *funcType) { lCalleeArgCount(llvm::Value *callee, const FunctionType *funcType) {
LLVM_TYPE_CONST llvm::FunctionType *ft = llvm::FunctionType *ft =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::FunctionType>(callee->getType()); llvm::dyn_cast<llvm::FunctionType>(callee->getType());
if (ft == NULL) { if (ft == NULL) {
LLVM_TYPE_CONST llvm::PointerType *pt = llvm::PointerType *pt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(callee->getType()); llvm::dyn_cast<llvm::PointerType>(callee->getType());
if (pt == NULL) { if (pt == NULL) {
// varying--in this case, it must be the version of the // varying--in this case, it must be the version of the
// function that takes a mask // function that takes a mask
return funcType->GetNumParameters() + 1; return funcType->GetNumParameters() + 1;
} }
ft = llvm::dyn_cast<LLVM_TYPE_CONST llvm::FunctionType>(pt->getElementType()); ft = llvm::dyn_cast<llvm::FunctionType>(pt->getElementType());
} }
Assert(ft != NULL); Assert(ft != NULL);
@@ -3083,17 +3065,11 @@ FunctionEmitContext::CallInst(llvm::Value *func, const FunctionType *funcType,
if (argVals.size() + 1 == calleeArgCount) if (argVals.size() + 1 == calleeArgCount)
argVals.push_back(GetFullMask()); argVals.push_back(GetFullMask());
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(func->getType()) == false) { if (llvm::isa<llvm::VectorType>(func->getType()) == false) {
// Regular 'uniform' function call--just one function or function // Regular 'uniform' function call--just one function or function
// pointer, so just emit the IR directly. // pointer, so just emit the IR directly.
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::Instruction *ci = llvm::Instruction *ci =
llvm::CallInst::Create(func, argVals, name ? name : "", bblock); llvm::CallInst::Create(func, argVals, name ? name : "", bblock);
#else
llvm::Instruction *ci =
llvm::CallInst::Create(func, argVals.begin(), argVals.end(),
name ? name : "", bblock);
#endif
AddDebugPos(ci); AddDebugPos(ci);
return ci; return ci;
} }
@@ -3117,7 +3093,7 @@ FunctionEmitContext::CallInst(llvm::Value *func, const FunctionType *funcType,
// First allocate memory to accumulate the various program // First allocate memory to accumulate the various program
// instances' return values... // instances' return values...
const Type *returnType = funcType->GetReturnType(); const Type *returnType = funcType->GetReturnType();
LLVM_TYPE_CONST llvm::Type *llvmReturnType = returnType->LLVMType(g->ctx); llvm::Type *llvmReturnType = returnType->LLVMType(g->ctx);
llvm::Value *resultPtr = NULL; llvm::Value *resultPtr = NULL;
if (llvmReturnType->isVoidTy() == false) if (llvmReturnType->isVoidTy() == false)
resultPtr = AllocaInst(llvmReturnType); resultPtr = AllocaInst(llvmReturnType);
@@ -3184,9 +3160,9 @@ FunctionEmitContext::CallInst(llvm::Value *func, const FunctionType *funcType,
// bitcast the i32/64 function pointer to the actual function // bitcast the i32/64 function pointer to the actual function
// pointer type (the variant that includes a mask). // pointer type (the variant that includes a mask).
LLVM_TYPE_CONST llvm::Type *llvmFuncType = llvm::Type *llvmFuncType =
funcType->LLVMFunctionType(g->ctx, true); funcType->LLVMFunctionType(g->ctx, true);
LLVM_TYPE_CONST llvm::Type *llvmFPtrType = llvm::Type *llvmFPtrType =
llvm::PointerType::get(llvmFuncType, 0); llvm::PointerType::get(llvmFuncType, 0);
llvm::Value *fptrCast = IntToPtrInst(fptr, llvmFPtrType); llvm::Value *fptrCast = IntToPtrInst(fptr, llvmFPtrType);
@@ -3283,14 +3259,14 @@ FunctionEmitContext::LaunchInst(llvm::Value *callee,
launchedTasks = true; launchedTasks = true;
Assert(llvm::isa<llvm::Function>(callee)); Assert(llvm::isa<llvm::Function>(callee));
LLVM_TYPE_CONST llvm::Type *argType = llvm::Type *argType =
(llvm::dyn_cast<llvm::Function>(callee))->arg_begin()->getType(); (llvm::dyn_cast<llvm::Function>(callee))->arg_begin()->getType();
Assert(llvm::PointerType::classof(argType)); Assert(llvm::PointerType::classof(argType));
LLVM_TYPE_CONST llvm::PointerType *pt = llvm::PointerType *pt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(argType); llvm::dyn_cast<llvm::PointerType>(argType);
Assert(llvm::StructType::classof(pt->getElementType())); Assert(llvm::StructType::classof(pt->getElementType()));
LLVM_TYPE_CONST llvm::StructType *argStructType = llvm::StructType *argStructType =
static_cast<LLVM_TYPE_CONST llvm::StructType *>(pt->getElementType()); static_cast<llvm::StructType *>(pt->getElementType());
Assert(argStructType->getNumElements() == argVals.size() + 1); Assert(argStructType->getNumElements() == argVals.size() + 1);
llvm::Function *falloc = m->module->getFunction("ISPCAlloc"); llvm::Function *falloc = m->module->getFunction("ISPCAlloc");
@@ -3388,7 +3364,7 @@ FunctionEmitContext::addVaryingOffsetsIfNeeded(llvm::Value *ptr,
return ptr; return ptr;
// Find the size of a uniform element of the varying type // Find the size of a uniform element of the varying type
LLVM_TYPE_CONST llvm::Type *llvmBaseUniformType = llvm::Type *llvmBaseUniformType =
baseType->GetAsUniformType()->LLVMType(g->ctx); baseType->GetAsUniformType()->LLVMType(g->ctx);
llvm::Value *unifSize = g->target.SizeOf(llvmBaseUniformType, bblock); llvm::Value *unifSize = g->target.SizeOf(llvmBaseUniformType, bblock);
unifSize = SmearUniform(unifSize); unifSize = SmearUniform(unifSize);

22
ctx.h
View File

@@ -380,23 +380,23 @@ public:
array, for pointer types). */ array, for pointer types). */
llvm::Value *SmearUniform(llvm::Value *value, const char *name = NULL); llvm::Value *SmearUniform(llvm::Value *value, const char *name = NULL);
llvm::Value *BitCastInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, llvm::Value *BitCastInst(llvm::Value *value, llvm::Type *type,
const char *name = NULL); const char *name = NULL);
llvm::Value *PtrToIntInst(llvm::Value *value, const char *name = NULL); llvm::Value *PtrToIntInst(llvm::Value *value, const char *name = NULL);
llvm::Value *PtrToIntInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, llvm::Value *PtrToIntInst(llvm::Value *value, llvm::Type *type,
const char *name = NULL); const char *name = NULL);
llvm::Value *IntToPtrInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, llvm::Value *IntToPtrInst(llvm::Value *value, llvm::Type *type,
const char *name = NULL); const char *name = NULL);
llvm::Instruction *TruncInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *TruncInst(llvm::Value *value, llvm::Type *type,
const char *name = NULL); const char *name = NULL);
llvm::Instruction *CastInst(llvm::Instruction::CastOps op, llvm::Value *value, llvm::Instruction *CastInst(llvm::Instruction::CastOps op, llvm::Value *value,
LLVM_TYPE_CONST llvm::Type *type, const char *name = NULL); llvm::Type *type, const char *name = NULL);
llvm::Instruction *FPCastInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *FPCastInst(llvm::Value *value, llvm::Type *type,
const char *name = NULL); const char *name = NULL);
llvm::Instruction *SExtInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *SExtInst(llvm::Value *value, llvm::Type *type,
const char *name = NULL); const char *name = NULL);
llvm::Instruction *ZExtInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *ZExtInst(llvm::Value *value, llvm::Type *type,
const char *name = NULL); const char *name = NULL);
/** Given two integer-typed values (but possibly one vector and the /** Given two integer-typed values (but possibly one vector and the
@@ -448,7 +448,7 @@ public:
instruction is added at the start of the function in the entry instruction is added at the start of the function in the entry
basic block; if it should be added to the current basic block, then basic block; if it should be added to the current basic block, then
the atEntryBlock parameter should be false. */ the atEntryBlock parameter should be false. */
llvm::Value *AllocaInst(LLVM_TYPE_CONST llvm::Type *llvmType, llvm::Value *AllocaInst(llvm::Type *llvmType,
const char *name = NULL, int align = 0, const char *name = NULL, int align = 0,
bool atEntryBlock = true); bool atEntryBlock = true);
@@ -485,7 +485,7 @@ public:
llvm::Value *InsertInst(llvm::Value *v, llvm::Value *eltVal, int elt, llvm::Value *InsertInst(llvm::Value *v, llvm::Value *eltVal, int elt,
const char *name = NULL); const char *name = NULL);
llvm::PHINode *PhiNode(LLVM_TYPE_CONST llvm::Type *type, int count, llvm::PHINode *PhiNode(llvm::Type *type, int count,
const char *name = NULL); const char *name = NULL);
llvm::Instruction *SelectInst(llvm::Value *test, llvm::Value *val0, llvm::Instruction *SelectInst(llvm::Value *test, llvm::Value *val0,
llvm::Value *val1, const char *name = NULL); llvm::Value *val1, const char *name = NULL);
@@ -632,7 +632,7 @@ private:
std::vector<CFInfo *> controlFlowInfo; std::vector<CFInfo *> controlFlowInfo;
/** DIFile object corresponding to the source file where the current /** DIFile object corresponding to the source file where the current
function was defined (used for debugging info0. */ function was defined (used for debugging info). */
llvm::DIFile diFile; llvm::DIFile diFile;
/** DISubprogram corresponding to this function (used for debugging /** DISubprogram corresponding to this function (used for debugging

408
decl.cpp
View File

@@ -33,7 +33,7 @@
/** @file decl.cpp /** @file decl.cpp
@brief Implementations of classes related to turning declarations into @brief Implementations of classes related to turning declarations into
symbols and types. symbol names and types.
*/ */
#include "decl.h" #include "decl.h"
@@ -44,6 +44,7 @@
#include "stmt.h" #include "stmt.h"
#include "expr.h" #include "expr.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <set> #include <set>
static void static void
@@ -55,6 +56,7 @@ lPrintTypeQualifiers(int typeQualifiers) {
if (typeQualifiers & TYPEQUAL_TASK) printf("task "); if (typeQualifiers & TYPEQUAL_TASK) printf("task ");
if (typeQualifiers & TYPEQUAL_SIGNED) printf("signed "); if (typeQualifiers & TYPEQUAL_SIGNED) printf("signed ");
if (typeQualifiers & TYPEQUAL_UNSIGNED) printf("unsigned "); if (typeQualifiers & TYPEQUAL_UNSIGNED) printf("unsigned ");
if (typeQualifiers & TYPEQUAL_EXPORT) printf("export ");
} }
@@ -188,7 +190,6 @@ lGetStorageClassName(StorageClass storageClass) {
case SC_NONE: return ""; case SC_NONE: return "";
case SC_EXTERN: return "extern"; case SC_EXTERN: return "extern";
case SC_EXTERN_C: return "extern \"C\""; case SC_EXTERN_C: return "extern \"C\"";
case SC_EXPORT: return "export";
case SC_STATIC: return "static"; case SC_STATIC: return "static";
case SC_TYPEDEF: return "typedef"; case SC_TYPEDEF: return "typedef";
default: FATAL("Unhandled storage class in lGetStorageClassName"); default: FATAL("Unhandled storage class in lGetStorageClassName");
@@ -217,50 +218,44 @@ Declarator::Declarator(DeclaratorKind dk, SourcePos p)
: pos(p), kind(dk) { : pos(p), kind(dk) {
child = NULL; child = NULL;
typeQualifiers = 0; typeQualifiers = 0;
storageClass = SC_NONE;
arraySize = -1; arraySize = -1;
sym = NULL; type = NULL;
initExpr = NULL; initExpr = NULL;
} }
void void
Declarator::InitFromDeclSpecs(DeclSpecs *ds) { Declarator::InitFromDeclSpecs(DeclSpecs *ds) {
const Type *t = GetType(ds); const Type *baseType = ds->GetBaseType(pos);
if (t == NULL) { InitFromType(baseType, ds);
if (type == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return; return;
} }
Symbol *sym = GetSymbol(); storageClass = ds->storageClass;
if (sym != NULL) {
sym->type = t; if (ds->declSpecList.size() > 0 &&
sym->storageClass = ds->storageClass; dynamic_cast<const FunctionType *>(type) == NULL) {
Error(pos, "__declspec specifiers for non-function type \"%s\" are "
"not used.", type->GetString().c_str());
} }
} }
Symbol *
Declarator::GetSymbol() const {
// The symbol lives at the last child in the chain, so walk down there
// and return the one there.
const Declarator *d = this;
while (d->child != NULL)
d = d->child;
return d->sym;
}
void void
Declarator::Print(int indent) const { Declarator::Print(int indent) const {
printf("%*cdeclarator: [", indent, ' '); printf("%*cdeclarator: [", indent, ' ');
pos.Print(); pos.Print();
lPrintTypeQualifiers(typeQualifiers); lPrintTypeQualifiers(typeQualifiers);
Symbol *sym = GetSymbol(); printf("%s ", lGetStorageClassName(storageClass));
if (sym != NULL) if (name.size() > 0)
printf("%s", sym->name.c_str()); printf("%s", name.c_str());
else else
printf("(null symbol)"); printf("(unnamed)");
printf(", array size = %d", arraySize); printf(", array size = %d", arraySize);
@@ -294,66 +289,26 @@ Declarator::Print(int indent) const {
} }
Symbol * void
Declarator::GetFunctionInfo(DeclSpecs *ds, std::vector<Symbol *> *funArgs) { Declarator::InitFromType(const Type *baseType, DeclSpecs *ds) {
const FunctionType *type =
dynamic_cast<const FunctionType *>(GetType(ds));
if (type == NULL)
return NULL;
Symbol *declSym = GetSymbol();
Assert(declSym != NULL);
// Get the symbol for the function from the symbol table. (It should
// already have been added to the symbol table by AddGlobal() by the
// time we get here.)
Symbol *funSym = m->symbolTable->LookupFunction(declSym->name.c_str(), type);
if (funSym == NULL)
// May be NULL due to error earlier in compilation
Assert(m->errorCount > 0);
else
funSym->pos = pos;
// Walk down to the declarator for the function. (We have to get past
// the stuff that specifies the function's return type before we get to
// the function's declarator.)
Declarator *d = this;
while (d != NULL && d->kind != DK_FUNCTION)
d = d->child;
Assert(d != NULL);
for (unsigned int i = 0; i < d->functionParams.size(); ++i) {
Symbol *sym = d->GetSymbolForFunctionParameter(i);
if (sym->type == NULL) {
Assert(m->errorCount > 0);
continue;
}
else
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
funArgs->push_back(sym);
}
if (funSym != NULL)
funSym->type = funSym->type->ResolveUnboundVariability(Variability::Varying);
return funSym;
}
const Type *
Declarator::GetType(const Type *base, DeclSpecs *ds) const {
bool hasUniformQual = ((typeQualifiers & TYPEQUAL_UNIFORM) != 0); bool hasUniformQual = ((typeQualifiers & TYPEQUAL_UNIFORM) != 0);
bool hasVaryingQual = ((typeQualifiers & TYPEQUAL_VARYING) != 0); bool hasVaryingQual = ((typeQualifiers & TYPEQUAL_VARYING) != 0);
bool isTask = ((typeQualifiers & TYPEQUAL_TASK) != 0); bool isTask = ((typeQualifiers & TYPEQUAL_TASK) != 0);
bool isExported = ((typeQualifiers & TYPEQUAL_EXPORT) != 0);
bool isConst = ((typeQualifiers & TYPEQUAL_CONST) != 0); bool isConst = ((typeQualifiers & TYPEQUAL_CONST) != 0);
if (hasUniformQual && hasVaryingQual) { if (hasUniformQual && hasVaryingQual) {
Error(pos, "Can't provide both \"uniform\" and \"varying\" qualifiers."); Error(pos, "Can't provide both \"uniform\" and \"varying\" qualifiers.");
return NULL; return;
} }
if (kind != DK_FUNCTION && isTask) if (kind != DK_FUNCTION && isTask) {
Error(pos, "\"task\" qualifier illegal in variable declaration."); Error(pos, "\"task\" qualifier illegal in variable declaration.");
return;
}
if (kind != DK_FUNCTION && isExported) {
Error(pos, "\"export\" qualifier illegal in variable declaration.");
return;
}
Variability variability(Variability::Unbound); Variability variability(Variability::Unbound);
if (hasUniformQual) if (hasUniformQual)
@@ -361,69 +316,79 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
else if (hasVaryingQual) else if (hasVaryingQual)
variability = Variability::Varying; variability = Variability::Varying;
const Type *type = base; if (kind == DK_BASE) {
switch (kind) {
case DK_BASE:
// All of the type qualifiers should be in the DeclSpecs for the // All of the type qualifiers should be in the DeclSpecs for the
// base declarator // base declarator
Assert(typeQualifiers == 0); Assert(typeQualifiers == 0);
Assert(child == NULL); Assert(child == NULL);
return type; type = baseType;
}
case DK_POINTER: else if (kind == DK_POINTER) {
/* For now, any pointer to an SOA type gets the slice property; if /* For now, any pointer to an SOA type gets the slice property; if
we add the capability to declare pointers as slices or not, we add the capability to declare pointers as slices or not,
we'll want to set this based on a type qualifier here. */ we'll want to set this based on a type qualifier here. */
type = new PointerType(type, variability, isConst, type->IsSOAType()); const Type *ptrType = new PointerType(baseType, variability, isConst,
if (child != NULL) baseType->IsSOAType());
return child->GetType(type, ds); if (child != NULL) {
child->InitFromType(ptrType, ds);
type = child->type;
name = child->name;
}
else else
return type; type = ptrType;
break; }
else if (kind == DK_REFERENCE) {
case DK_REFERENCE: if (hasUniformQual) {
if (hasUniformQual)
Error(pos, "\"uniform\" qualifier is illegal to apply to references."); Error(pos, "\"uniform\" qualifier is illegal to apply to references.");
if (hasVaryingQual) return;
}
if (hasVaryingQual) {
Error(pos, "\"varying\" qualifier is illegal to apply to references."); Error(pos, "\"varying\" qualifier is illegal to apply to references.");
if (isConst) return;
}
if (isConst) {
Error(pos, "\"const\" qualifier is to illegal apply to references."); Error(pos, "\"const\" qualifier is to illegal apply to references.");
return;
}
// The parser should disallow this already, but double check. // The parser should disallow this already, but double check.
if (dynamic_cast<const ReferenceType *>(type) != NULL) { if (dynamic_cast<const ReferenceType *>(baseType) != NULL) {
Error(pos, "References to references are illegal."); Error(pos, "References to references are illegal.");
return NULL; return;
} }
type = new ReferenceType(type); const Type *refType = new ReferenceType(baseType);
if (child != NULL) if (child != NULL) {
return child->GetType(type, ds); child->InitFromType(refType, ds);
type = child->type;
name = child->name;
}
else else
return type; type = refType;
break; }
else if (kind == DK_ARRAY) {
case DK_ARRAY: if (Type::Equal(baseType, AtomicType::Void)) {
if (Type::Equal(type, AtomicType::Void)) {
Error(pos, "Arrays of \"void\" type are illegal."); Error(pos, "Arrays of \"void\" type are illegal.");
return NULL; return;
} }
if (dynamic_cast<const ReferenceType *>(type)) { if (dynamic_cast<const ReferenceType *>(baseType)) {
Error(pos, "Arrays of references (type \"%s\") are illegal.", Error(pos, "Arrays of references (type \"%s\") are illegal.",
type->GetString().c_str()); baseType->GetString().c_str());
return NULL; return;
} }
type = new ArrayType(type, arraySize); const Type *arrayType = new ArrayType(baseType, arraySize);
if (child) if (child != NULL) {
return child->GetType(type, ds); child->InitFromType(arrayType, ds);
type = child->type;
name = child->name;
}
else else
return type; type = arrayType;
break; }
else if (kind == DK_FUNCTION) {
case DK_FUNCTION: {
std::vector<const Type *> args; std::vector<const Type *> args;
std::vector<std::string> argNames; std::vector<std::string> argNames;
std::vector<ConstExpr *> argDefaults; std::vector<Expr *> argDefaults;
std::vector<SourcePos> argPos; std::vector<SourcePos> argPos;
// Loop over the function arguments and store the names, types, // Loop over the function arguments and store the names, types,
@@ -432,20 +397,44 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
for (unsigned int i = 0; i < functionParams.size(); ++i) { for (unsigned int i = 0; i < functionParams.size(); ++i) {
Declaration *d = functionParams[i]; Declaration *d = functionParams[i];
Symbol *sym = GetSymbolForFunctionParameter(i); if (d == NULL) {
Assert(m->errorCount > 0);
if (d->declSpecs->storageClass != SC_NONE) continue;
Error(sym->pos, "Storage class \"%s\" is illegal in " }
"function parameter declaration for parameter \"%s\".", if (d->declarators.size() == 0) {
lGetStorageClassName(d->declSpecs->storageClass), // function declaration like foo(float), w/o a name for the
sym->name.c_str()); // parameter; wire up a placeholder Declarator for it
if (Type::Equal(sym->type, AtomicType::Void)) { d->declarators.push_back(new Declarator(DK_BASE, pos));
Error(sym->pos, "Parameter with type \"void\" illegal in function " d->declarators[0]->InitFromDeclSpecs(d->declSpecs);
"parameter list.");
sym->type = NULL;
} }
const ArrayType *at = dynamic_cast<const ArrayType *>(sym->type); Assert(d->declarators.size() == 1);
Declarator *decl = d->declarators[0];
if (decl == NULL || decl->type == NULL) {
Assert(m->errorCount > 0);
continue;
}
if (decl->name == "") {
// Give a name to any anonymous parameter declarations
char buf[32];
sprintf(buf, "__anon_parameter_%d", i);
decl->name = buf;
}
decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
if (d->declSpecs->storageClass != SC_NONE)
Error(decl->pos, "Storage class \"%s\" is illegal in "
"function parameter declaration for parameter \"%s\".",
lGetStorageClassName(d->declSpecs->storageClass),
decl->name.c_str());
if (Type::Equal(decl->type, AtomicType::Void)) {
Error(decl->pos, "Parameter with type \"void\" illegal in function "
"parameter list.");
decl->type = NULL;
}
const ArrayType *at = dynamic_cast<const ArrayType *>(decl->type);
if (at != NULL) { if (at != NULL) {
// As in C, arrays are passed to functions as pointers to // As in C, arrays are passed to functions as pointers to
// their element type. We'll just immediately make this // their element type. We'll just immediately make this
@@ -455,93 +444,94 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
// report this differently than it was originally declared // report this differently than it was originally declared
// in the function, but it's not clear that this is a // in the function, but it's not clear that this is a
// significant problem.) // significant problem.)
if (at->GetElementType() == NULL) { const Type *targetType = at->GetElementType();
if (targetType == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return;
} }
const Type *targetType = at->GetElementType(); decl->type = PointerType::GetUniform(targetType);
targetType =
targetType->ResolveUnboundVariability(Variability::Varying);
sym->type = PointerType::GetUniform(targetType);
// Make sure there are no unsized arrays (other than the // Make sure there are no unsized arrays (other than the
// first dimension) in function parameter lists. // first dimension) in function parameter lists.
at = dynamic_cast<const ArrayType *>(at->GetElementType()); at = dynamic_cast<const ArrayType *>(targetType);
while (at != NULL) { while (at != NULL) {
if (at->GetElementCount() == 0) if (at->GetElementCount() == 0)
Error(sym->pos, "Arrays with unsized dimensions in " Error(decl->pos, "Arrays with unsized dimensions in "
"dimensions after the first one are illegal in " "dimensions after the first one are illegal in "
"function parameter lists."); "function parameter lists.");
at = dynamic_cast<const ArrayType *>(at->GetElementType()); at = dynamic_cast<const ArrayType *>(at->GetElementType());
} }
} }
args.push_back(sym->type); args.push_back(decl->type);
argNames.push_back(sym->name); argNames.push_back(decl->name);
argPos.push_back(sym->pos); argPos.push_back(decl->pos);
ConstExpr *init = NULL; Expr *init = NULL;
if (d->declarators.size()) { // Try to find an initializer expression.
// Try to find an initializer expression; if there is one, while (decl != NULL) {
// it lives down to the base declarator. if (decl->initExpr != NULL) {
Declarator *decl = d->declarators[0]; decl->initExpr = TypeCheck(decl->initExpr);
while (decl->child != NULL) { decl->initExpr = Optimize(decl->initExpr);
Assert(decl->initExpr == NULL); if (decl->initExpr != NULL) {
init = dynamic_cast<ConstExpr *>(decl->initExpr);
if (init == NULL)
init = dynamic_cast<NullPointerExpr *>(decl->initExpr);
if (init == NULL)
Error(decl->initExpr->pos, "Default value for parameter "
"\"%s\" must be a compile-time constant.",
decl->name.c_str());
}
break;
}
else
decl = decl->child; decl = decl->child;
}
if (decl->initExpr != NULL &&
(decl->initExpr = TypeCheck(decl->initExpr)) != NULL &&
(decl->initExpr = Optimize(decl->initExpr)) != NULL &&
(init = dynamic_cast<ConstExpr *>(decl->initExpr)) == NULL) {
Error(decl->initExpr->pos, "Default value for parameter "
"\"%s\" must be a compile-time constant.",
sym->name.c_str());
}
} }
argDefaults.push_back(init); argDefaults.push_back(init);
} }
const Type *returnType = type; const Type *returnType = baseType;
if (returnType == NULL) { if (returnType == NULL) {
Error(pos, "No return type provided in function declaration."); Error(pos, "No return type provided in function declaration.");
return NULL; return;
} }
if (dynamic_cast<const FunctionType *>(returnType) != NULL) { if (dynamic_cast<const FunctionType *>(returnType) != NULL) {
Error(pos, "Illegal to return function type from function."); Error(pos, "Illegal to return function type from function.");
return NULL; return;
} }
bool isExported = ds && (ds->storageClass == SC_EXPORT); returnType = returnType->ResolveUnboundVariability(Variability::Varying);
bool isExternC = ds && (ds->storageClass == SC_EXTERN_C); bool isExternC = ds && (ds->storageClass == SC_EXTERN_C);
bool isExported = ds && ((ds->typeQualifiers & TYPEQUAL_EXPORT) != 0);
bool isTask = ds && ((ds->typeQualifiers & TYPEQUAL_TASK) != 0); bool isTask = ds && ((ds->typeQualifiers & TYPEQUAL_TASK) != 0);
if (isExported && isTask) { if (isExported && isTask) {
Error(pos, "Function can't have both \"task\" and \"export\" " Error(pos, "Function can't have both \"task\" and \"export\" "
"qualifiers"); "qualifiers");
return NULL; return;
} }
if (isExternC && isTask) { if (isExternC && isTask) {
Error(pos, "Function can't have both \"extern \"C\"\" and \"task\" " Error(pos, "Function can't have both \"extern \"C\"\" and \"task\" "
"qualifiers"); "qualifiers");
return NULL; return;
} }
if (isExternC && isExported) { if (isExternC && isExported) {
Error(pos, "Function can't have both \"extern \"C\"\" and \"export\" " Error(pos, "Function can't have both \"extern \"C\"\" and \"export\" "
"qualifiers"); "qualifiers");
return NULL; return;
} }
if (child == NULL) { if (child == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return;
} }
const FunctionType *functionType = const FunctionType *functionType =
new FunctionType(returnType, args, argNames, argDefaults, new FunctionType(returnType, args, argNames, argDefaults,
argPos, isTask, isExported, isExternC); argPos, isTask, isExported, isExternC);
functionType = functionType->ResolveUnboundVariability(Variability::Varying);
// handle any explicit __declspecs on the function // handle any explicit __declspecs on the function
if (ds != NULL) { if (ds != NULL) {
@@ -563,11 +553,9 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
} }
} }
return child->GetType(functionType, ds); child->InitFromType(functionType, ds);
} type = child->type;
default: name = child->name;
FATAL("Unexpected decl kind");
return NULL;
} }
} }
@@ -646,27 +634,23 @@ Declaration::GetVariableDeclarations() const {
for (unsigned int i = 0; i < declarators.size(); ++i) { for (unsigned int i = 0; i < declarators.size(); ++i) {
Declarator *decl = declarators[i]; Declarator *decl = declarators[i];
if (decl == NULL) { if (decl == NULL || decl->type == NULL) {
// Ignore earlier errors // Ignore earlier errors
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
continue; continue;
} }
Symbol *sym = decl->GetSymbol(); if (Type::Equal(decl->type, AtomicType::Void))
if (sym == NULL || sym->type == NULL) { Error(decl->pos, "\"void\" type variable illegal in declaration.");
// Ignore errors else if (dynamic_cast<const FunctionType *>(decl->type) == NULL) {
Assert(m->errorCount > 0); decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
continue; Symbol *sym = new Symbol(decl->name, decl->pos, decl->type,
} decl->storageClass);
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
if (Type::Equal(sym->type, AtomicType::Void))
Error(sym->pos, "\"void\" type variable illegal in declaration.");
else if (dynamic_cast<const FunctionType *>(sym->type) == NULL) {
m->symbolTable->AddVariable(sym); m->symbolTable->AddVariable(sym);
vars.push_back(VariableDeclaration(sym, decl->initExpr)); vars.push_back(VariableDeclaration(sym, decl->initExpr));
} }
} }
return vars; return vars;
} }
@@ -677,25 +661,20 @@ Declaration::DeclareFunctions() {
for (unsigned int i = 0; i < declarators.size(); ++i) { for (unsigned int i = 0; i < declarators.size(); ++i) {
Declarator *decl = declarators[i]; Declarator *decl = declarators[i];
if (decl == NULL) { if (decl == NULL || decl->type == NULL) {
// Ignore earlier errors // Ignore earlier errors
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
continue; continue;
} }
Symbol *sym = decl->GetSymbol(); const FunctionType *ftype =
if (sym == NULL || sym->type == NULL) { dynamic_cast<const FunctionType *>(decl->type);
// Ignore errors if (ftype == NULL)
Assert(m->errorCount > 0);
continue;
}
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
if (dynamic_cast<const FunctionType *>(sym->type) == NULL)
continue; continue;
bool isInline = (declSpecs->typeQualifiers & TYPEQUAL_INLINE); bool isInline = (declSpecs->typeQualifiers & TYPEQUAL_INLINE);
m->AddFunctionDeclaration(sym, isInline); m->AddFunctionDeclaration(decl->name, ftype, decl->storageClass,
isInline, decl->pos);
} }
} }
@@ -709,6 +688,7 @@ Declaration::Print(int indent) const {
declarators[i]->Print(indent+4); declarators[i]->Print(indent+4);
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
void void
@@ -725,38 +705,42 @@ GetStructTypesNamesPositions(const std::vector<StructDeclaration *> &sd,
// FIXME: making this fake little DeclSpecs here is really // FIXME: making this fake little DeclSpecs here is really
// disgusting // disgusting
DeclSpecs ds(type); DeclSpecs ds(type);
if (type->IsUniformType()) if (Type::Equal(type, AtomicType::Void) == false) {
ds.typeQualifiers |= TYPEQUAL_UNIFORM; if (type->IsUniformType())
else if (type->IsVaryingType()) ds.typeQualifiers |= TYPEQUAL_UNIFORM;
ds.typeQualifiers |= TYPEQUAL_VARYING; else if (type->IsVaryingType())
ds.typeQualifiers |= TYPEQUAL_VARYING;
else if (type->GetSOAWidth() != 0)
ds.soaWidth = type->GetSOAWidth();
// FIXME: ds.vectorSize?
}
for (unsigned int j = 0; j < sd[i]->declarators->size(); ++j) { for (unsigned int j = 0; j < sd[i]->declarators->size(); ++j) {
Declarator *d = (*sd[i]->declarators)[j]; Declarator *d = (*sd[i]->declarators)[j];
d->InitFromDeclSpecs(&ds); d->InitFromDeclSpecs(&ds);
Symbol *sym = d->GetSymbol(); if (Type::Equal(d->type, AtomicType::Void))
if (Type::Equal(sym->type, AtomicType::Void))
Error(d->pos, "\"void\" type illegal for struct member."); Error(d->pos, "\"void\" type illegal for struct member.");
const ArrayType *arrayType = elementTypes->push_back(d->type);
dynamic_cast<const ArrayType *>(sym->type);
if (arrayType != NULL && arrayType->GetElementCount() == 0) {
Error(d->pos, "Unsized arrays aren't allowed in struct "
"definitions.");
elementTypes->push_back(NULL);
}
else
elementTypes->push_back(sym->type);
if (seenNames.find(sym->name) != seenNames.end()) if (seenNames.find(d->name) != seenNames.end())
Error(d->pos, "Struct member \"%s\" has same name as a " Error(d->pos, "Struct member \"%s\" has same name as a "
"previously-declared member.", sym->name.c_str()); "previously-declared member.", d->name.c_str());
else else
seenNames.insert(sym->name); seenNames.insert(d->name);
elementNames->push_back(sym->name); elementNames->push_back(d->name);
elementPositions->push_back(sym->pos); elementPositions->push_back(d->pos);
} }
} }
for (int i = 0; i < (int)elementTypes->size() - 1; ++i) {
const ArrayType *arrayType =
dynamic_cast<const ArrayType *>((*elementTypes)[i]);
if (arrayType != NULL && arrayType->GetElementCount() == 0)
Error((*elementPositions)[i], "Unsized arrays aren't allowed except "
"for the last member in a struct definition.");
}
} }

47
decl.h
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,8 @@
variables--here, that the declaration has the 'static' and 'uniform' variables--here, that the declaration has the 'static' and 'uniform'
qualifiers, and that it's basic type is 'int'. Then for each variable qualifiers, and that it's basic type is 'int'. Then for each variable
declaration, the Declaraiton class holds an instance of a Declarator, declaration, the Declaraiton class holds an instance of a Declarator,
which in turn records the per-variable information like the symbol which in turn records the per-variable information like the name, array
name, array size (if any), initializer expression, etc. size (if any), initializer expression, etc.
*/ */
#ifndef ISPC_DECL_H #ifndef ISPC_DECL_H
@@ -61,16 +61,6 @@ struct VariableDeclaration;
class Declaration; class Declaration;
class Declarator; class Declarator;
enum StorageClass {
SC_NONE,
SC_EXTERN,
SC_EXPORT,
SC_STATIC,
SC_TYPEDEF,
SC_EXTERN_C
};
/* Multiple qualifiers can be provided with types in declarations; /* Multiple qualifiers can be provided with types in declarations;
therefore, they are set up so that they can be ANDed together into an therefore, they are set up so that they can be ANDed together into an
int. */ int. */
@@ -82,6 +72,7 @@ enum StorageClass {
#define TYPEQUAL_SIGNED (1<<4) #define TYPEQUAL_SIGNED (1<<4)
#define TYPEQUAL_UNSIGNED (1<<5) #define TYPEQUAL_UNSIGNED (1<<5)
#define TYPEQUAL_INLINE (1<<6) #define TYPEQUAL_INLINE (1<<6)
#define TYPEQUAL_EXPORT (1<<7)
/** @brief Representation of the declaration specifiers in a declaration. /** @brief Representation of the declaration specifiers in a declaration.
@@ -141,25 +132,11 @@ public:
Declarator(DeclaratorKind dk, SourcePos p); Declarator(DeclaratorKind dk, SourcePos p);
/** Once a DeclSpecs instance is available, this method completes the /** Once a DeclSpecs instance is available, this method completes the
initialization of the Symbol, setting its Type accordingly. initialization of the type member.
*/ */
void InitFromDeclSpecs(DeclSpecs *ds); void InitFromDeclSpecs(DeclSpecs *ds);
/** Get the actual type of the combination of Declarator and the given void InitFromType(const Type *base, DeclSpecs *ds);
DeclSpecs. If an explicit base type is provided, the declarator is
applied to that type; otherwise the base type from the DeclSpecs is
used. */
const Type *GetType(DeclSpecs *ds) const;
const Type *GetType(const Type *base, DeclSpecs *ds) const;
/** Returns the symbol corresponding to the function declared by this
declarator and symbols for its arguments in *args. */
Symbol *GetFunctionInfo(DeclSpecs *ds, std::vector<Symbol *> *args);
Symbol *GetSymbolForFunctionParameter(int paramNum) const;
/** Returns the symbol associated with the declarator. */
Symbol *GetSymbol() const;
void Print(int indent) const; void Print(int indent) const;
@@ -180,18 +157,24 @@ public:
/** Type qualifiers provided with the declarator. */ /** Type qualifiers provided with the declarator. */
int typeQualifiers; int typeQualifiers;
StorageClass storageClass;
/** For array declarators, this gives the declared size of the array. /** For array declarators, this gives the declared size of the array.
Unsized arrays have arraySize == 0. */ Unsized arrays have arraySize == 0. */
int arraySize; int arraySize;
/** Symbol associated with the declarator. */ /** Name associated with the declarator. */
Symbol *sym; std::string name;
/** Initialization expression for the variable. May be NULL. */ /** Initialization expression for the variable. May be NULL. */
Expr *initExpr; Expr *initExpr;
/** Type of the declarator. This is NULL until InitFromDeclSpecs() or
InitFromType() is called. */
const Type *type;
/** For function declarations, this holds the Declaration *s for the /** For function declarations, this holds the Declaration *s for the
funciton's parameters. */ function's parameters. */
std::vector<Declaration *> functionParams; std::vector<Declaration *> functionParams;
}; };

View File

@@ -1,3 +1,47 @@
=== v1.2.1 === (6 April 2012)
This release contains only minor new functionality and is mostly for many
small bugfixes and improvements to error handling and error reporting.
The new functionality that is present is:
* Significantly more efficient versions of the float / half conversion
routines are now available in the standard library, thanks to Fabian
Giesen.
* The last member of a struct can now be a zero-length array; this allows
the trick of dynamically allocating enough storage for the struct and
some number of array elements at the end of it.
Significant bugs fixed include:
* Issue #205: When a target ISA isn't specified, use the host system's
capabilities to choose a target for which it will be able to run the
generated code.
* Issues #215 and #217: Don't allocate storage for global variables that
are declared "extern".
* Issue #197: Allow NULL as a default argument value in a function
declaration.
* Issue #223: Fix bugs where taking the address of a function wouldn't work
as expected.
* Issue #224: When there are overloaded variants of a function that take
both reference and const reference parameters, give the non-const
reference preference when matching values of that underlying type.
* Issue #225: An error is issed when a varying lvalue is assigned to a
reference type (rather than crashing).
* Issue #193: Permit conversions from array types to void *, not just the
pointer type of the underlying array element.
* Issue #199: Still evaluate expressions that are cast to (void).
The documentation has also been improved, with FAQs added to clarify some
aspects of the ispc pointer model.
=== v1.2.0 === (20 March 2012) === v1.2.0 === (20 March 2012)
This is a major new release of ispc, with a number of significant This is a major new release of ispc, with a number of significant

View File

@@ -14,12 +14,19 @@ distribution.
+ `Why are there multiple versions of exported ispc functions in the assembly output?`_ + `Why are there multiple versions of exported ispc functions in the assembly output?`_
+ `How can I more easily see gathers and scatters in generated assembly?`_ + `How can I more easily see gathers and scatters in generated assembly?`_
* Language Details
+ `What is the difference between "int *foo" and "int foo[]"?`_
+ `Why are pointed-to types "uniform" by default?`_
+ `What am I getting an error about assigning a varying lvalue to a reference type?`_
* Interoperability * Interoperability
+ `How can I supply an initial execution mask in the call from the application?`_ + `How can I supply an initial execution mask in the call from the application?`_
+ `How can I generate a single binary executable with support for multiple instruction sets?`_ + `How can I generate a single binary executable with support for multiple instruction sets?`_
+ `How can I determine at run-time which vector instruction set's instructions were selected to execute?`_ + `How can I determine at run-time which vector instruction set's instructions were selected to execute?`_
+ `Is it possible to inline ispc functions in C/C++ code?`_ + `Is it possible to inline ispc functions in C/C++ code?`_
+ `Why is it illegal to pass "varying" values from C/C++ to ispc functions?`_
* Programming Techniques * Programming Techniques
@@ -213,6 +220,125 @@ easier to understand:
jmp ___pseudo_scatter_base_offsets32_32 ## TAILCALL jmp ___pseudo_scatter_base_offsets32_32 ## TAILCALL
Language Details
================
What is the difference between "int \*foo" and "int foo[]"?
-----------------------------------------------------------
In C and C++, declaring a function to take a parameter ``int *foo`` and
``int foo[]`` results in the same type for the parameter. Both are
pointers to integers. In ``ispc``, these are different types. The first
one is a varying pointer to a uniform integer value in memory, while the
second results in a uniform pointer to the start of an array of varying
integer values in memory.
To understand why the first is a varying pointer to a uniform integer,
first recall that types without explicit rate qualifiers (``uniform``,
``varying``, or ``soa<>``) are ``varying`` by default. Second, recall from
the `discussion of pointer types in the ispc User's Guide`_ that pointed-to
types without rate qualifiers are ``uniform`` by default. (This second
rule is discussed further below, in `Why are pointed-to types "uniform" by
default?`_.) The type of ``int *foo`` follows from these.
.. _discussion of pointer types in the ispc User's Guide: ispc.html#pointer-types
Conversely, in a function body, ``int foo[10]`` represents a declaration of
a 10-element array of varying ``int`` values. In that we'd certainly like
to be able to pass such an array to a function that takes a ``int []``
parameter, the natural type for an ``int []`` parameter is a uniform
pointer to varying integer values.
In terms of compatibility with C/C++, it's unfortunate that this
distinction exists, though any other set of rules seems to introduce more
awkwardness than this one. (Though we're interested to hear ideas to
improve these rules!).
Why are pointed-to types "uniform" by default?
----------------------------------------------
In ``ispc``, types without rate qualifiers are "varying" by default, but
types pointed to by pointers without rate qualifiers are "uniform" by
default. Why this difference?
::
int foo; // no rate qualifier, "varying int".
uniform int *foo; // pointer type has no rate qualifier, pointed-to does.
// "varying pointer to uniform int".
int *foo; // neither pointer type nor pointed-to type ("int") have
// rate qualifiers. Pointer type is varying by default,
// pointed-to is uniform. "varying pointer to uniform int".
varying int *foo; // varying pointer to varying int
The first rule, having types without rate qualifiers be varying by default,
is a default that keeps the number of "uniform" or "varying" qualifiers in
``ispc`` programs low. Most ``ispc`` programs use mostly "varying"
variables, so this rule allows most variables to be declared without also
requiring rate qualifiers.
On a related note, this rule allows many C/C++ functions to be used to
define equivalent functions in the SPMD execution model that ``ispc``
provides with little or no modification:
::
// scalar add in C/C++, SPMD/vector add in ispc
int add(int a, int b) { return a + b; }
This motivation also explains why ``uniform int *foo`` represents a varying
pointer; having pointers be varying by default if they don't have rate
qualifiers similarly helps with porting code from C/C++ to ``ispc``.
The tricker issue is why pointed-to types are "uniform" by default. In our
experience, data in memory that is accessed via pointers is most often
uniform; this generally includes all data that has been allocated and
initialized by the C/C++ application code. In practice, "varying" types are
more generally (but not exclusively) used for local data in ``ispc``
functions. Thus, making the pointed-to type uniform by default leads to
more concise code for the most common cases.
What am I getting an error about assigning a varying lvalue to a reference type?
--------------------------------------------------------------------------------
Given code like the following:
::
uniform float a[...];
int index = ...;
float &r = a[index];
``ispc`` issues the error "Initializer for reference-type variable "r" must
have a uniform lvalue type.". The underlying issue stems from how
references are represented in the code generated by ``ispc``. Recall that
``ispc`` supports both uniform and varying pointer types--a uniform pointer
points to the same location in memory for all program instances in the
gang, while a varying pointer allows each program instance to have its own
pointer value.
References are represented a pointer in the code generated by ``ispc``,
though this is generally opaque to the user; in ``ispc``, they are
specifically uniform pointers. This design decision was made so that given
code like this:
::
extern void func(float &val);
float foo = ...;
func(foo);
Then the reference would be handled efficiently as a single pointer, rather
than unnecessarily being turned into a gang-size of pointers.
However, an implication of this decision is that it's not possible for
references to refer to completely different things for each of the program
instances. (And hence the error that is issued). In cases where a unique
per-program-instance pointer is needed, a varying pointer should be used
instead of a reference.
Interoperability Interoperability
================ ================
@@ -391,6 +517,48 @@ linking your applicaiton.
``-mattr=+avx`` flag to ``llc``.) ``-mattr=+avx`` flag to ``llc``.)
Why is it illegal to pass "varying" values from C/C++ to ispc functions?
------------------------------------------------------------------------
If any of the types in the parameter list to an exported function is
"varying" (including recursively, and members of structure types, etc.),
then ``ispc`` will issue an error and refuse to compile the function:
::
% echo "export int add(int x) { return ++x; }" | ispc
<stdin>:1:12: Error: Illegal to return a "varying" type from exported function "foo"
<stdin>:1:20: Error: Varying parameter "x" is illegal in an exported function.
While there's no fundamental reason why this isn't possible, recall the
definition of "varying" variables: they have one value for each program
instance in the gang. As such, the number of values and amount of storage
required to represent a varying variable depends on the gang size
(i.e. ``programCount``), which can have different values depending on the
compilation target.
``ispc`` therefore prohibits passing "varying" values between the
application and the ``ispc`` program in order to prevent the
application-side code from depending on a particular gang size, in order to
encourage portability to different gang sizes. (A generally desirable
programming practice.)
For cases where the size of data is actually fixed from the application
side, the value can be passed via a pointer to a short ``uniform`` array,
as follows:
::
export void add4(uniform int ptr[4]) {
foreach (i = 0 ... 4)
ptr[i]++;
}
On the 4-wide SSE instruction set, this compiles to a single vector add
instruction (and associated move instructions), while it still also
efficiently computes the correct result on 8-wide AVX targets.
Programming Techniques Programming Techniques
====================== ======================

View File

@@ -121,10 +121,14 @@ Contents:
* `The ISPC Standard Library`_ * `The ISPC Standard Library`_
+ `Basic Operations On Data`_
* `Logical and Selection Operations`_
* `Bit Operations`_
+ `Math Functions`_ + `Math Functions`_
* `Basic Math Functions`_ * `Basic Math Functions`_
* `Bit-Level Operations`_
* `Transcendental Functions`_ * `Transcendental Functions`_
* `Pseudo-Random Numbers`_ * `Pseudo-Random Numbers`_
@@ -538,7 +542,7 @@ preprocessor runs:
* - ISPC * - ISPC
- 1 - 1
- Detecting that the ``ispc`` compiler is processing the file - Detecting that the ``ispc`` compiler is processing the file
* - ISPC_TARGET_{SSE2,SSE4,AVX} * - ISPC_TARGET_{SSE2,SSE4,AVX,AVX2}
- 1 - 1
- One of these will be set, depending on the compilation target. - One of these will be set, depending on the compilation target.
* - ISPC_POINTER_SIZE * - ISPC_POINTER_SIZE
@@ -1390,8 +1394,8 @@ Types
Basic Types and Type Qualifiers Basic Types and Type Qualifiers
------------------------------- -------------------------------
``ispc`` is a statically-typed language. It supports a variety of basic ``ispc`` is a statically-typed language. It supports a variety of core
types. basic types:
* ``void``: "empty" type representing no value. * ``void``: "empty" type representing no value.
* ``bool``: boolean value; may be assigned ``true``, ``false``, or the * ``bool``: boolean value; may be assigned ``true``, ``false``, or the
@@ -1408,6 +1412,15 @@ types.
* ``unsigned int64``: 64-bit unsigned integer. * ``unsigned int64``: 64-bit unsigned integer.
* ``double``: 64-bit double-precision floating point value. * ``double``: 64-bit double-precision floating point value.
There are also a few built-in types related to pointers and memory:
* ``size_t``: the maximum size of any object (structure or array)
* ``ptrdiff_t``: an integer type large enough to represent the difference
between two pointers
* ``intptr_t``: signed integer type that is large enough to represent
a pointer value
* ``uintptr_t``: unsigned integer type large enough to represent a pointer
Implicit type conversion between values of different types is done Implicit type conversion between values of different types is done
automatically by the ``ispc`` compiler. Thus, a value of ``float`` type automatically by the ``ispc`` compiler. Thus, a value of ``float`` type
can be assigned to a variable of ``int`` type directly. In binary can be assigned to a variable of ``int`` type directly. In binary
@@ -2150,6 +2163,12 @@ greater than or equal to ``NUM_ITEMS``.
// ... // ...
} }
Short-circuiting may impose some overhead in the generated code; for cases
where short-circuiting is undesirable due to performance impact, see
the section `Logical and Selection Operations`_, which introduces helper
functions in the standard library that provide these operations without
short-circuiting.
Dynamic Memory Allocation Dynamic Memory Allocation
------------------------- -------------------------
@@ -2827,6 +2846,123 @@ The ISPC Standard Library
compiling ``ispc`` programs. (To disable the standard library, pass the compiling ``ispc`` programs. (To disable the standard library, pass the
``--nostdlib`` command-line flag to the compiler.) ``--nostdlib`` command-line flag to the compiler.)
Basic Operations On Data
------------------------
Logical and Selection Operations
--------------------------------
Recall from `Expressions`_ that ``ispc`` short-circuits the evaluation of
logical and selection operators: given an expression like ``(index < count
&& array[index] == 0)``, then ``array[index] == 0`` is only evaluated if
``index < count`` is true. This property is useful for writing expressions
like the preceeding one, where the second expression may not be safe to
evaluate in some cases.
This short-circuiting can impose overhead in the generated code; additional
operations are required to test the first value and to conditionally jump
over the code that evaluates the second value. The ``ispc`` compiler does
try to mitigate this cost by detecting cases where it is both safe and
inexpensive to evaluate both expressions, and skips short-circuiting in the
generated code in this case (without there being any programmer-visible
change in program behavior.)
For cases where the compiler can't detect this case but the programmer
wants to avoid short-circuiting behavior, the standard library provides a
few helper functions. First, ``and()`` and ``or()`` provide
non-short-circuiting logical AND and OR operations.
::
bool and(bool a, bool b)
bool or(bool a, bool b)
uniform bool and(uniform bool a, uniform bool b)
uniform bool or(uniform bool a, uniform bool b)
And there are three variants of ``select()`` that select between two values
based on a boolean condition. These are the variants of ``select()`` for
the ``int8`` type:
::
int8 select(bool v, int8 a, int8 b)
int8 select(uniform bool v, int8 a, int8 b)
uniform int8 select(uniform bool v, uniform int8 a, uniform int8 b)
There are also variants for ``int16``, ``int32``, ``int64``, ``float``, and
``double`` types.
Bit Operations
--------------
The various variants of ``popcnt()`` return the population count--the
number of bits set in the given value.
::
uniform int popcnt(uniform int v)
int popcnt(int v)
uniform int popcnt(bool v)
A few functions determine how many leading bits in the given value are zero
and how many of the trailing bits are zero; there are also ``unsigned``
variants of these functions and variants that take ``int64`` and ``unsigned
int64`` types.
::
int32 count_leading_zeros(int32 v)
uniform int32 count_leading_zeros(uniform int32 v)
int32 count_trailing_zeros(int32 v)
uniform int32 count_trailing_zeros(uniform int32 v)
Sometimes it's useful to convert a ``bool`` value to an integer using sign
extension so that the integer's bits are all on if the ``bool`` has the
value ``true`` (rather than just having the value one). The
``sign_extend()`` functions provide this functionality:
::
int sign_extend(bool value)
uniform int sign_extend(uniform bool value)
The ``intbits()`` and ``floatbits()`` functions can be used to implement
low-level floating-point bit twiddling. For example, ``intbits()`` returns
an ``unsigned int`` that is a bit-for-bit copy of the given ``float``
value. (Note: it is **not** the same as ``(int)a``, but corresponds to
something like ``*((int *)&a)`` in C.
::
float floatbits(unsigned int a);
uniform float floatbits(uniform unsigned int a);
unsigned int intbits(float a);
uniform unsigned int intbits(uniform float a);
The ``intbits()`` and ``floatbits()`` functions have no cost at runtime;
they just let the compiler know how to interpret the bits of the given
value. They make it possible to efficiently write functions that take
advantage of the low-level bit representation of floating-point values.
For example, the ``abs()`` function in the standard library is implemented
as follows:
::
float abs(float a) {
unsigned int i = intbits(a);
i &= 0x7fffffff;
return floatbits(i);
}
This code directly clears the high order bit to ensure that the given
floating-point value is positive. This compiles down to a single ``andps``
instruction when used with an Intel® SSE target, for example.
Math Functions Math Functions
-------------- --------------
@@ -2919,77 +3055,6 @@ quite efficient.)
uniform unsigned int low, uniform unsigned int low,
uniform unsigned int high) uniform unsigned int high)
Bit-Level Operations
--------------------
The various variants of ``popcnt()`` return the population count--the
number of bits set in the given value.
::
uniform int popcnt(uniform int v)
int popcnt(int v)
uniform int popcnt(bool v)
A few functions determine how many leading bits in the given value are zero
and how many of the trailing bits are zero; there are also ``unsigned``
variants of these functions and variants that take ``int64`` and ``unsigned
int64`` types.
::
int32 count_leading_zeros(int32 v)
uniform int32 count_leading_zeros(uniform int32 v)
int32 count_trailing_zeros(int32 v)
uniform int32 count_trailing_zeros(uniform int32 v)
Sometimes it's useful to convert a ``bool`` value to an integer using sign
extension so that the integer's bits are all on if the ``bool`` has the
value ``true`` (rather than just having the value one). The
``sign_extend()`` functions provide this functionality:
::
int sign_extend(bool value)
uniform int sign_extend(uniform bool value)
The ``intbits()`` and ``floatbits()`` functions can be used to implement
low-level floating-point bit twiddling. For example, ``intbits()`` returns
an ``unsigned int`` that is a bit-for-bit copy of the given ``float``
value. (Note: it is **not** the same as ``(int)a``, but corresponds to
something like ``*((int *)&a)`` in C.
::
float floatbits(unsigned int a);
uniform float floatbits(uniform unsigned int a);
unsigned int intbits(float a);
uniform unsigned int intbits(uniform float a);
The ``intbits()`` and ``floatbits()`` functions have no cost at runtime;
they just let the compiler know how to interpret the bits of the given
value. They make it possible to efficiently write functions that take
advantage of the low-level bit representation of floating-point values.
For example, the ``abs()`` function in the standard library is implemented
as follows:
::
float abs(float a) {
unsigned int i = intbits(a);
i &= 0x7fffffff;
return floatbits(i);
}
This code directly clears the high order bit to ensure that the given
floating-point value is positive. This compiles down to a single ``andps``
instruction when used with an Intel® SSE target, for example.
Transcendental Functions Transcendental Functions
------------------------ ------------------------
@@ -3027,8 +3092,8 @@ The corresponding inverse functions are also available:
uniform float acos(uniform float x) uniform float acos(uniform float x)
float atan(float x) float atan(float x)
uniform float atan(uniform float x) uniform float atan(uniform float x)
float atan2(float x, float y) float atan2(float y, float x)
uniform float atan2(uniform float x, uniform float y) uniform float atan2(uniform float y, uniform float x)
If both sine and cosine are needed, then the ``sincos()`` call computes If both sine and cosine are needed, then the ``sincos()`` call computes
both more efficiently than two calls to the respective individual both more efficiently than two calls to the respective individual
@@ -3732,6 +3797,13 @@ For global atomics, only atomic swap is available for these types:
float atomic_swap_global(uniform float * uniform ptr, float value) float atomic_swap_global(uniform float * uniform ptr, float value)
double atomic_swap_global(uniform double * uniform ptr, double value) double atomic_swap_global(uniform double * uniform ptr, double value)
Finally, "swap" (but none of these other atomics) is available for pointer
types:
::
void *atomic_swap_{local,global}(void * * uniform ptr, void * value)
There are also variants of the atomic that take ``uniform`` values for the There are also variants of the atomic that take ``uniform`` values for the
operand and return a ``uniform`` result. These correspond to a single operand and return a ``uniform`` result. These correspond to a single
atomic operation being performed for the entire gang of program instances, atomic operation being performed for the entire gang of program instances,
@@ -3756,6 +3828,13 @@ rather than one per program instance.
uniform int32 atomic_swap_{local,global}(uniform int32 * uniform ptr, uniform int32 atomic_swap_{local,global}(uniform int32 * uniform ptr,
uniform int32 newval) uniform int32 newval)
And similarly for pointers:
::
uniform void *atomic_swap_{local,global}(void * * uniform ptr,
void *newval)
Be careful that you use the atomic function that you mean to; consider the Be careful that you use the atomic function that you mean to; consider the
following code: following code:
@@ -3797,12 +3876,18 @@ the same location in memory!)
int32 atomic_xor_{local,global}(uniform int32 * varying ptr, int32 value) int32 atomic_xor_{local,global}(uniform int32 * varying ptr, int32 value)
int32 atomic_swap_{local,global}(uniform int32 * varying ptr, int32 value) int32 atomic_swap_{local,global}(uniform int32 * varying ptr, int32 value)
And:
::
void *atomic_swap_{local,global}(void * * ptr, void *value)
There are also atomic "compare and exchange" functions. Compare and There are also atomic "compare and exchange" functions. Compare and
exchange atomically compares the value in "val" to "compare"--if they exchange atomically compares the value in "val" to "compare"--if they
match, it assigns "newval" to "val". In either case, the old value of match, it assigns "newval" to "val". In either case, the old value of
"val" is returned. (As with the other atomic operations, there are also "val" is returned. (As with the other atomic operations, there are also
``unsigned`` and 64-bit variants of this function. Furthermore, there are ``unsigned`` and 64-bit variants of this function. Furthermore, there are
``float`` and ``double`` variants as well.) ``float``, ``double``, and ``void *`` variants as well.)
:: ::
@@ -3824,6 +3909,11 @@ code.
void memory_barrier(); void memory_barrier();
Note that this barrier is *not* needed for coordinating reads and writes
among the program instances in a gang; it's only needed for coordinating
between multiple hardware threads running on different cores. See the
section `Data Races Within a Gang`_ for the guarantees provided about
memory read/write ordering across a gang.
Prefetches Prefetches
---------- ----------

View File

@@ -2,6 +2,24 @@
ispc News ispc News
========= =========
ispc 1.2.1 is Released
----------------------
This is a bugfix release, fixing approximately 20 bugs in the system and
improving error handling and error reporting. New functionality includes
very efficient float/half conversion routines thanks to Fabian
Giesen. See the `1.2.1 release notes`_ for details.
.. _1.2.1 release notes: https://github.com/ispc/ispc/tree/master/docs/ReleaseNotes.txt
ispc 1.2.0 is Released
-----------------------
A new major release was posted on March 20, 2012. This release includes
significant new functionality for cleanly handling "structure of arrays"
(SoA) data layout and a new model for how uniform and varying are handled
with structure types.
Paper on ispc To Appear in InPar 2012 Paper on ispc To Appear in InPar 2012
------------------------------------- -------------------------------------

View File

@@ -31,7 +31,7 @@ PROJECT_NAME = "Intel SPMD Program Compiler"
# This could be handy for archiving the generated documentation or # This could be handy for archiving the generated documentation or
# if some version control system is used. # if some version control system is used.
PROJECT_NUMBER = 1.2.0 PROJECT_NUMBER = 1.2.1
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put. # base path where the generated documentation will be put.

848
expr.cpp

File diff suppressed because it is too large Load Diff

23
expr.h
View File

@@ -584,6 +584,7 @@ public:
Expr *TypeCheck(); Expr *TypeCheck();
Expr *Optimize(); Expr *Optimize();
int EstimateCost() const; int EstimateCost() const;
llvm::Constant *GetConstant(const Type *type) const;
Expr *expr; Expr *expr;
}; };
@@ -651,20 +652,26 @@ public:
function overloading, this method resolves which actual function function overloading, this method resolves which actual function
the arguments match best. If the argCouldBeNULL parameter is the arguments match best. If the argCouldBeNULL parameter is
non-NULL, each element indicates whether the corresponding argument non-NULL, each element indicates whether the corresponding argument
is the number zero, indicating that it could be a NULL pointer. is the number zero, indicating that it could be a NULL pointer, and
This parameter may be NULL (for cases where overload resolution is if argIsConstant is non-NULL, each element indicates whether the
being done just given type information without the parameter corresponding argument is a compile-time constant value. Both of
argument expressions being available. It returns true on success. these parameters may be NULL (for cases where overload resolution
is being done just given type information without the parameter
argument expressions being available. This function returns true
on success.
*/ */
bool ResolveOverloads(SourcePos argPos, bool ResolveOverloads(SourcePos argPos,
const std::vector<const Type *> &argTypes, const std::vector<const Type *> &argTypes,
const std::vector<bool> *argCouldBeNULL = NULL); const std::vector<bool> *argCouldBeNULL = NULL,
const std::vector<bool> *argIsConstant = NULL);
Symbol *GetMatchingFunction(); Symbol *GetMatchingFunction();
private: private:
bool tryResolve(int (*matchFunc)(const Type *, const Type *), std::vector<Symbol *> getCandidateFunctions(int argCount) const;
SourcePos argPos, const std::vector<const Type *> &argTypes, static int computeOverloadCost(const FunctionType *ftype,
const std::vector<bool> *argCouldBeNULL); const std::vector<const Type *> &argTypes,
const std::vector<bool> *argCouldBeNULL,
const std::vector<bool> *argIsConstant);
/** Name of the function that is being called. */ /** Name of the function that is being called. */
std::string name; std::string name;

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2011, Intel Corporation Copyright (c) 2011-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -66,9 +66,8 @@
#include <llvm/Support/ToolOutputFile.h> #include <llvm/Support/ToolOutputFile.h>
#include <llvm/Assembly/PrintModulePass.h> #include <llvm/Assembly/PrintModulePass.h>
Function::Function(Symbol *s, const std::vector<Symbol *> &a, Stmt *c) { Function::Function(Symbol *s, Stmt *c) {
sym = s; sym = s;
args = a;
code = c; code = c;
maskSymbol = m->symbolTable->LookupVariable("__mask"); maskSymbol = m->symbolTable->LookupVariable("__mask");
@@ -104,9 +103,17 @@ Function::Function(Symbol *s, const std::vector<Symbol *> &a, Stmt *c) {
const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type); const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type);
Assert(type != NULL); Assert(type != NULL);
for (unsigned int i = 0; i < args.size(); ++i) for (int i = 0; i < type->GetNumParameters(); ++i) {
if (dynamic_cast<const ReferenceType *>(args[i]->type) == NULL) const char *paramName = type->GetParameterName(i).c_str();
args[i]->parentFunction = this; Symbol *sym = m->symbolTable->LookupVariable(paramName);
if (sym == NULL)
Assert(strncmp(paramName, "__anon_parameter_", 17) == 0);
args.push_back(sym);
const Type *t = type->GetParameterType(i);
if (sym != NULL && dynamic_cast<const ReferenceType *>(t) == NULL)
sym->parentFunction = this;
}
if (type->isTask) { if (type->isTask) {
threadIndexSym = m->symbolTable->LookupVariable("threadIndex"); threadIndexSym = m->symbolTable->LookupVariable("threadIndex");
@@ -145,7 +152,8 @@ Function::GetType() const {
'mem2reg' pass will in turn promote to SSA registers.. 'mem2reg' pass will in turn promote to SSA registers..
*/ */
static void static void
lCopyInTaskParameter(int i, llvm::Value *structArgPtr, const std::vector<Symbol *> &args, lCopyInTaskParameter(int i, llvm::Value *structArgPtr, const
std::vector<Symbol *> &args,
FunctionEmitContext *ctx) { FunctionEmitContext *ctx) {
// We expect the argument structure to come in as a poitner to a // We expect the argument structure to come in as a poitner to a
// structure. Confirm and figure out its type here. // structure. Confirm and figure out its type here.
@@ -157,9 +165,13 @@ lCopyInTaskParameter(int i, llvm::Value *structArgPtr, const std::vector<Symbol
llvm::dyn_cast<const llvm::StructType>(pt->getElementType()); llvm::dyn_cast<const llvm::StructType>(pt->getElementType());
// Get the type of the argument we're copying in and its Symbol pointer // Get the type of the argument we're copying in and its Symbol pointer
LLVM_TYPE_CONST llvm::Type *argType = argStructType->getElementType(i); llvm::Type *argType = argStructType->getElementType(i);
Symbol *sym = args[i]; Symbol *sym = args[i];
if (sym == NULL)
// anonymous parameter, so don't worry about it
return;
// allocate space to copy the parameter in to // allocate space to copy the parameter in to
sym->storagePtr = ctx->AllocaInst(argType, sym->name.c_str()); sym->storagePtr = ctx->AllocaInst(argType, sym->name.c_str());
@@ -240,6 +252,10 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function,
llvm::Function::arg_iterator argIter = function->arg_begin(); llvm::Function::arg_iterator argIter = function->arg_begin();
for (unsigned int i = 0; i < args.size(); ++i, ++argIter) { for (unsigned int i = 0; i < args.size(); ++i, ++argIter) {
Symbol *sym = args[i]; Symbol *sym = args[i];
if (sym == NULL)
// anonymous function parameter
continue;
argIter->setName(sym->name.c_str()); argIter->setName(sym->name.c_str());
// Allocate stack storage for the parameter and emit code // Allocate stack storage for the parameter and emit code
@@ -419,7 +435,7 @@ Function::GenerateIR() {
Assert(type != NULL); Assert(type != NULL);
if (type->isExported) { if (type->isExported) {
if (!type->isTask) { if (!type->isTask) {
LLVM_TYPE_CONST llvm::FunctionType *ftype = llvm::FunctionType *ftype =
type->LLVMFunctionType(g->ctx); type->LLVMFunctionType(g->ctx);
llvm::GlobalValue::LinkageTypes linkage = llvm::GlobalValue::ExternalLinkage; llvm::GlobalValue::LinkageTypes linkage = llvm::GlobalValue::ExternalLinkage;
std::string functionName = sym->name; std::string functionName = sym->name;

4
func.h
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2011, Intel Corporation Copyright (c) 2011-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
class Function { class Function {
public: public:
Function(Symbol *sym, const std::vector<Symbol *> &args, Stmt *code); Function(Symbol *sym, Stmt *code);
const Type *GetReturnType() const; const Type *GetReturnType() const;
const FunctionType *GetType() const; const FunctionType *GetType() const;

166
ispc.cpp
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -70,9 +70,88 @@ Module *m;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Target // Target
#ifndef ISPC_IS_WINDOWS
static void __cpuid(int info[4], int infoType) {
__asm__ __volatile__ ("cpuid"
: "=a" (info[0]), "=b" (info[1]), "=c" (info[2]), "=d" (info[3])
: "0" (infoType));
}
/* Save %ebx in case it's the PIC register */
static void __cpuidex(int info[4], int level, int count) {
__asm__ __volatile__ ("xchg{l}\t{%%}ebx, %1\n\t"
"cpuid\n\t"
"xchg{l}\t{%%}ebx, %1\n\t"
: "=a" (info[0]), "=r" (info[1]), "=c" (info[2]), "=d" (info[3])
: "0" (level), "2" (count));
}
#endif // ISPC_IS_WINDOWS
static const char *
lGetSystemISA() {
int info[4];
__cpuid(info, 1);
if ((info[2] & (1 << 28)) != 0) {
// AVX1 for sure. Do we have AVX2?
// Call cpuid with eax=7, ecx=0
__cpuidex(info, 7, 0);
if ((info[1] & (1 << 5)) != 0)
return "avx2";
else
return "avx";
}
else if ((info[2] & (1 << 19)) != 0)
return "sse4";
else if ((info[3] & (1 << 26)) != 0)
return "sse2";
else {
fprintf(stderr, "Unable to detect supported SSE/AVX ISA. Exiting.\n");
exit(1);
}
}
static const char *supportedCPUs[] = {
"atom", "penryn", "core2", "corei7",
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
"corei7-avx"
#endif
};
bool bool
Target::GetTarget(const char *arch, const char *cpu, const char *isa, Target::GetTarget(const char *arch, const char *cpu, const char *isa,
bool pic, Target *t) { bool pic, Target *t) {
if (isa == NULL) {
if (cpu != NULL) {
// If a CPU was specified explicitly, try to pick the best
// possible ISA based on that.
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
if (!strcmp(cpu, "sandybridge") ||
!strcmp(cpu, "corei7-avx"))
isa = "avx";
else
#endif
if (!strcmp(cpu, "corei7") ||
!strcmp(cpu, "penryn"))
isa = "sse4";
else
isa = "sse2";
fprintf(stderr, "Notice: no --target specified on command-line. "
"Using ISA \"%s\" based on specified CPU \"%s\".\n", isa,
cpu);
}
else {
// No CPU and no ISA, so use CPUID to figure out what this CPU
// supports.
isa = lGetSystemISA();
fprintf(stderr, "Notice: no --target specified on command-line. "
"Using system ISA \"%s\".\n", isa);
}
}
if (cpu == NULL) { if (cpu == NULL) {
std::string hostCPU = llvm::sys::getHostCPUName(); std::string hostCPU = llvm::sys::getHostCPUName();
if (hostCPU.size() > 0) if (hostCPU.size() > 0)
@@ -82,19 +161,24 @@ Target::GetTarget(const char *arch, const char *cpu, const char *isa,
cpu = "generic"; cpu = "generic";
} }
} }
else {
bool foundCPU = false;
for (int i = 0; i < int(sizeof(supportedCPUs) / sizeof(supportedCPUs[0]));
++i) {
if (!strcmp(cpu, supportedCPUs[i])) {
foundCPU = true;
break;
}
}
if (foundCPU == false) {
fprintf(stderr, "Error: CPU type \"%s\" unknown. Supported CPUs: "
"%s.\n", cpu, SupportedTargetCPUs().c_str());
return false;
}
}
t->cpu = cpu; t->cpu = cpu;
if (isa == NULL) {
if (!strcasecmp(cpu, "atom"))
isa = "sse2";
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
else if (!strcasecmp(cpu, "sandybridge") ||
!strcasecmp(cpu, "corei7-avx"))
isa = "avx";
#endif // LLVM_3_0
else
isa = "sse4";
}
if (arch == NULL) if (arch == NULL)
arch = "x86-64"; arch = "x86-64";
@@ -249,17 +333,16 @@ Target::GetTarget(const char *arch, const char *cpu, const char *isa,
} }
const char * std::string
Target::SupportedTargetCPUs() { Target::SupportedTargetCPUs() {
return "atom, barcelona, core2, corei7, " std::string ret;
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn) int count = sizeof(supportedCPUs) / sizeof(supportedCPUs[0]);
"corei7-avx, " for (int i = 0; i < count; ++i) {
#endif ret += supportedCPUs[i];
"istanbul, nocona, penryn, " if (i != count - 1)
#ifdef LLVM_2_9 ret += ", ";
"sandybridge, " }
#endif return ret;
"westmere";
} }
@@ -318,8 +401,15 @@ Target::GetTargetMachine() const {
#if defined(LLVM_3_1svn) #if defined(LLVM_3_1svn)
std::string featuresString = attributes; std::string featuresString = attributes;
llvm::TargetOptions options; llvm::TargetOptions options;
#if 0
// This was breaking e.g. round() on SSE2, where the code we want to
// run wants to do:
// x += 0x1.0p23f;
// x -= 0x1.0p23f;
// But then LLVM was optimizing this away...
if (g->opt.fastMath == true) if (g->opt.fastMath == true)
options.UnsafeFPMath = 1; options.UnsafeFPMath = 1;
#endif
llvm::TargetMachine *targetMachine = llvm::TargetMachine *targetMachine =
target->createTargetMachine(triple, cpu, featuresString, options, target->createTargetMachine(triple, cpu, featuresString, options,
relocModel); relocModel);
@@ -367,7 +457,7 @@ Target::GetISAString() const {
static bool static bool
lGenericTypeLayoutIndeterminate(LLVM_TYPE_CONST llvm::Type *type) { lGenericTypeLayoutIndeterminate(llvm::Type *type) {
if (type->isPrimitiveType() || type->isIntegerTy()) if (type->isPrimitiveType() || type->isIntegerTy())
return false; return false;
@@ -376,18 +466,18 @@ lGenericTypeLayoutIndeterminate(LLVM_TYPE_CONST llvm::Type *type) {
type == LLVMTypes::Int1VectorType) type == LLVMTypes::Int1VectorType)
return true; return true;
LLVM_TYPE_CONST llvm::ArrayType *at = llvm::ArrayType *at =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::ArrayType>(type); llvm::dyn_cast<llvm::ArrayType>(type);
if (at != NULL) if (at != NULL)
return lGenericTypeLayoutIndeterminate(at->getElementType()); return lGenericTypeLayoutIndeterminate(at->getElementType());
LLVM_TYPE_CONST llvm::PointerType *pt = llvm::PointerType *pt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(type); llvm::dyn_cast<llvm::PointerType>(type);
if (pt != NULL) if (pt != NULL)
return false; return false;
LLVM_TYPE_CONST llvm::StructType *st = llvm::StructType *st =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::StructType>(type); llvm::dyn_cast<llvm::StructType>(type);
if (st != NULL) { if (st != NULL) {
for (int i = 0; i < (int)st->getNumElements(); ++i) for (int i = 0; i < (int)st->getNumElements(); ++i)
if (lGenericTypeLayoutIndeterminate(st->getElementType(i))) if (lGenericTypeLayoutIndeterminate(st->getElementType(i)))
@@ -395,18 +485,18 @@ lGenericTypeLayoutIndeterminate(LLVM_TYPE_CONST llvm::Type *type) {
return false; return false;
} }
Assert(llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(type)); Assert(llvm::isa<llvm::VectorType>(type));
return true; return true;
} }
llvm::Value * llvm::Value *
Target::SizeOf(LLVM_TYPE_CONST llvm::Type *type, Target::SizeOf(llvm::Type *type,
llvm::BasicBlock *insertAtEnd) { llvm::BasicBlock *insertAtEnd) {
if (isa == Target::GENERIC && if (isa == Target::GENERIC &&
lGenericTypeLayoutIndeterminate(type)) { lGenericTypeLayoutIndeterminate(type)) {
llvm::Value *index[1] = { LLVMInt32(1) }; llvm::Value *index[1] = { LLVMInt32(1) };
LLVM_TYPE_CONST llvm::PointerType *ptrType = llvm::PointerType::get(type, 0); llvm::PointerType *ptrType = llvm::PointerType::get(type, 0);
llvm::Value *voidPtr = llvm::ConstantPointerNull::get(ptrType); llvm::Value *voidPtr = llvm::ConstantPointerNull::get(ptrType);
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn) #if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> arrayRef(&index[0], &index[1]); llvm::ArrayRef<llvm::Value *> arrayRef(&index[0], &index[1]);
@@ -428,7 +518,9 @@ Target::SizeOf(LLVM_TYPE_CONST llvm::Type *type,
const llvm::TargetData *td = GetTargetMachine()->getTargetData(); const llvm::TargetData *td = GetTargetMachine()->getTargetData();
Assert(td != NULL); Assert(td != NULL);
uint64_t byteSize = td->getTypeSizeInBits(type) / 8; uint64_t bitSize = td->getTypeSizeInBits(type);
Assert((bitSize % 8) == 0);
uint64_t byteSize = bitSize / 8;
if (is32Bit || g->opt.force32BitAddressing) if (is32Bit || g->opt.force32BitAddressing)
return LLVMInt32((int32_t)byteSize); return LLVMInt32((int32_t)byteSize);
else else
@@ -437,12 +529,12 @@ Target::SizeOf(LLVM_TYPE_CONST llvm::Type *type,
llvm::Value * llvm::Value *
Target::StructOffset(LLVM_TYPE_CONST llvm::Type *type, int element, Target::StructOffset(llvm::Type *type, int element,
llvm::BasicBlock *insertAtEnd) { llvm::BasicBlock *insertAtEnd) {
if (isa == Target::GENERIC && if (isa == Target::GENERIC &&
lGenericTypeLayoutIndeterminate(type) == true) { lGenericTypeLayoutIndeterminate(type) == true) {
llvm::Value *indices[2] = { LLVMInt32(0), LLVMInt32(element) }; llvm::Value *indices[2] = { LLVMInt32(0), LLVMInt32(element) };
LLVM_TYPE_CONST llvm::PointerType *ptrType = llvm::PointerType::get(type, 0); llvm::PointerType *ptrType = llvm::PointerType::get(type, 0);
llvm::Value *voidPtr = llvm::ConstantPointerNull::get(ptrType); llvm::Value *voidPtr = llvm::ConstantPointerNull::get(ptrType);
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn) #if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> arrayRef(&indices[0], &indices[2]); llvm::ArrayRef<llvm::Value *> arrayRef(&indices[0], &indices[2]);
@@ -464,8 +556,8 @@ Target::StructOffset(LLVM_TYPE_CONST llvm::Type *type, int element,
const llvm::TargetData *td = GetTargetMachine()->getTargetData(); const llvm::TargetData *td = GetTargetMachine()->getTargetData();
Assert(td != NULL); Assert(td != NULL);
LLVM_TYPE_CONST llvm::StructType *structType = llvm::StructType *structType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::StructType>(type); llvm::dyn_cast<llvm::StructType>(type);
Assert(structType != NULL); Assert(structType != NULL);
const llvm::StructLayout *sl = td->getStructLayout(structType); const llvm::StructLayout *sl = td->getStructLayout(structType);
Assert(sl != NULL); Assert(sl != NULL);

27
ispc.h
View File

@@ -38,10 +38,10 @@
#ifndef ISPC_H #ifndef ISPC_H
#define ISPC_H #define ISPC_H
#define ISPC_VERSION "1.2.1dev" #define ISPC_VERSION "1.2.2dev"
#if !defined(LLVM_2_9) && !defined(LLVM_3_0) && !defined(LLVM_3_0svn) && !defined(LLVM_3_1svn) #if !defined(LLVM_3_0) && !defined(LLVM_3_0svn) && !defined(LLVM_3_1svn)
#error "Only LLVM 2.9, 3.0, and the 3.1 development branch are supported" #error "Only LLVM 3.0, and the 3.1 development branch are supported"
#endif #endif
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
@@ -92,12 +92,6 @@ namespace llvm {
class Value; class Value;
} }
// llvm::Type *s are no longer const in llvm 3.0
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
#define LLVM_TYPE_CONST
#else
#define LLVM_TYPE_CONST const
#endif
class ArrayType; class ArrayType;
class AST; class AST;
@@ -116,6 +110,15 @@ class SymbolTable;
class Type; class Type;
struct VariableDeclaration; struct VariableDeclaration;
enum StorageClass {
SC_NONE,
SC_EXTERN,
SC_STATIC,
SC_TYPEDEF,
SC_EXTERN_C
};
/** @brief Representation of a range of positions in a source file. /** @brief Representation of a range of positions in a source file.
This class represents a range of characters in a source file This class represents a range of characters in a source file
@@ -164,7 +167,7 @@ struct Target {
/** Returns a comma-delimited string giving the names of the currently /** Returns a comma-delimited string giving the names of the currently
supported target CPUs. */ supported target CPUs. */
static const char *SupportedTargetCPUs(); static std::string SupportedTargetCPUs();
/** Returns a comma-delimited string giving the names of the currently /** Returns a comma-delimited string giving the names of the currently
supported target architectures. */ supported target architectures. */
@@ -182,13 +185,13 @@ struct Target {
const char *GetISAString() const; const char *GetISAString() const;
/** Returns the size of the given type */ /** Returns the size of the given type */
llvm::Value *SizeOf(LLVM_TYPE_CONST llvm::Type *type, llvm::Value *SizeOf(llvm::Type *type,
llvm::BasicBlock *insertAtEnd); llvm::BasicBlock *insertAtEnd);
/** Given a structure type and an element number in the structure, /** Given a structure type and an element number in the structure,
returns a value corresponding to the number of bytes from the start returns a value corresponding to the number of bytes from the start
of the structure where the element is located. */ of the structure where the element is located. */
llvm::Value *StructOffset(LLVM_TYPE_CONST llvm::Type *type, llvm::Value *StructOffset(llvm::Type *type,
int element, llvm::BasicBlock *insertAtEnd); int element, llvm::BasicBlock *insertAtEnd);
/** llvm Target object representing this target. */ /** llvm Target object representing this target. */

121
lex.ll
View File

@@ -43,6 +43,7 @@
#include <stdint.h> #include <stdint.h>
static uint64_t lParseBinary(const char *ptr, SourcePos pos, char **endPtr); static uint64_t lParseBinary(const char *ptr, SourcePos pos, char **endPtr);
static int lParseInteger(bool dotdotdot);
static void lCComment(SourcePos *); static void lCComment(SourcePos *);
static void lCppComment(SourcePos *); static void lCppComment(SourcePos *);
static void lHandleCppHash(SourcePos *); static void lHandleCppHash(SourcePos *);
@@ -322,7 +323,8 @@ inline int ispcRand() {
%option nounistd %option nounistd
WHITESPACE [ \t\r]+ WHITESPACE [ \t\r]+
INT_NUMBER (([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+))[kMG]? INT_NUMBER (([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+))[uUlL]*[kMG]?[uUlL]*
INT_NUMBER_DOTDOTDOT (([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+))[uUlL]*[kMG]?[uUlL]*\.\.\.
FLOAT_NUMBER (([0-9]+|(([0-9]+\.[0-9]*[fF]?)|(\.[0-9]+)))([eE][-+]?[0-9]+)?[fF]?) FLOAT_NUMBER (([0-9]+|(([0-9]+\.[0-9]*[fF]?)|(\.[0-9]+)))([eE][-+]?[0-9]+)?[fF]?)
HEX_FLOAT_NUMBER (0x[01](\.[0-9a-fA-F]*)?p[-+]?[0-9]+[fF]?) HEX_FLOAT_NUMBER (0x[01](\.[0-9a-fA-F]*)?p[-+]?[0-9]+[fF]?)
@@ -406,53 +408,14 @@ L?\"(\\.|[^\\"])*\" { lStringConst(&yylval, &yylloc); return TOKEN_STRING_LITERA
return TOKEN_IDENTIFIER; return TOKEN_IDENTIFIER;
} }
{INT_NUMBER}+(u|U|l|L)*? { {INT_NUMBER} {
RT; RT;
int ls = 0, us = 0; return lParseInteger(false);
}
char *endPtr = NULL; {INT_NUMBER_DOTDOTDOT} {
if (yytext[0] == '0' && yytext[1] == 'b') RT;
yylval.intVal = lParseBinary(yytext+2, yylloc, &endPtr); return lParseInteger(true);
else {
#if defined(ISPC_IS_WINDOWS) && !defined(__MINGW32__)
yylval.intVal = _strtoui64(yytext, &endPtr, 0);
#else
// FIXME: should use strtouq and then issue an error if we can't
// fit into 64 bits...
yylval.intVal = strtoull(yytext, &endPtr, 0);
#endif
}
bool kilo = false, mega = false, giga = false;
for (; *endPtr; endPtr++) {
if (*endPtr == 'k')
kilo = true;
else if (*endPtr == 'M')
mega = true;
else if (*endPtr == 'G')
giga = true;
else if (*endPtr == 'l' || *endPtr == 'L')
ls++;
else if (*endPtr == 'u' || *endPtr == 'U')
us++;
}
if (kilo)
yylval.intVal *= 1024;
if (mega)
yylval.intVal *= 1024*1024;
if (giga)
yylval.intVal *= 1024*1024*1024;
if (ls >= 2)
return us ? TOKEN_UINT64_CONSTANT : TOKEN_INT64_CONSTANT;
else if (ls == 1)
return us ? TOKEN_UINT32_CONSTANT : TOKEN_INT32_CONSTANT;
// See if we can fit this into a 32-bit integer...
if ((yylval.intVal & 0xffffffff) == yylval.intVal)
return us ? TOKEN_UINT32_CONSTANT : TOKEN_INT32_CONSTANT;
else
return us ? TOKEN_UINT64_CONSTANT : TOKEN_INT64_CONSTANT;
} }
@@ -562,6 +525,72 @@ lParseBinary(const char *ptr, SourcePos pos, char **endPtr) {
} }
static int
lParseInteger(bool dotdotdot) {
int ls = 0, us = 0;
char *endPtr = NULL;
if (yytext[0] == '0' && yytext[1] == 'b')
yylval.intVal = lParseBinary(yytext+2, yylloc, &endPtr);
else {
#if defined(ISPC_IS_WINDOWS) && !defined(__MINGW32__)
yylval.intVal = _strtoui64(yytext, &endPtr, 0);
#else
// FIXME: should use strtouq and then issue an error if we can't
// fit into 64 bits...
yylval.intVal = strtoull(yytext, &endPtr, 0);
#endif
}
bool kilo = false, mega = false, giga = false;
for (; *endPtr; endPtr++) {
if (*endPtr == 'k')
kilo = true;
else if (*endPtr == 'M')
mega = true;
else if (*endPtr == 'G')
giga = true;
else if (*endPtr == 'l' || *endPtr == 'L')
ls++;
else if (*endPtr == 'u' || *endPtr == 'U')
us++;
else
Assert(dotdotdot && *endPtr == '.');
}
if (kilo)
yylval.intVal *= 1024;
if (mega)
yylval.intVal *= 1024*1024;
if (giga)
yylval.intVal *= 1024*1024*1024;
if (dotdotdot) {
if (ls >= 2)
return us ? TOKEN_UINT64DOTDOTDOT_CONSTANT : TOKEN_INT64DOTDOTDOT_CONSTANT;
else if (ls == 1)
return us ? TOKEN_UINT32DOTDOTDOT_CONSTANT : TOKEN_INT32DOTDOTDOT_CONSTANT;
// See if we can fit this into a 32-bit integer...
if ((yylval.intVal & 0xffffffff) == yylval.intVal)
return us ? TOKEN_UINT32DOTDOTDOT_CONSTANT : TOKEN_INT32DOTDOTDOT_CONSTANT;
else
return us ? TOKEN_UINT64DOTDOTDOT_CONSTANT : TOKEN_INT64DOTDOTDOT_CONSTANT;
}
else {
if (ls >= 2)
return us ? TOKEN_UINT64_CONSTANT : TOKEN_INT64_CONSTANT;
else if (ls == 1)
return us ? TOKEN_UINT32_CONSTANT : TOKEN_INT32_CONSTANT;
// See if we can fit this into a 32-bit integer...
if ((yylval.intVal & 0xffffffff) == yylval.intVal)
return us ? TOKEN_UINT32_CONSTANT : TOKEN_INT32_CONSTANT;
else
return us ? TOKEN_UINT64_CONSTANT : TOKEN_INT64_CONSTANT;
}
}
/** Handle a C-style comment in the source. /** Handle a C-style comment in the source.
*/ */
static void static void

View File

@@ -43,44 +43,44 @@
#include <set> #include <set>
#include <map> #include <map>
LLVM_TYPE_CONST llvm::Type *LLVMTypes::VoidType = NULL; llvm::Type *LLVMTypes::VoidType = NULL;
LLVM_TYPE_CONST llvm::PointerType *LLVMTypes::VoidPointerType = NULL; llvm::PointerType *LLVMTypes::VoidPointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::PointerIntType = NULL; llvm::Type *LLVMTypes::PointerIntType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::BoolType = NULL; llvm::Type *LLVMTypes::BoolType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int8Type = NULL; llvm::Type *LLVMTypes::Int8Type = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int16Type = NULL; llvm::Type *LLVMTypes::Int16Type = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int32Type = NULL; llvm::Type *LLVMTypes::Int32Type = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int64Type = NULL; llvm::Type *LLVMTypes::Int64Type = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::FloatType = NULL; llvm::Type *LLVMTypes::FloatType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::DoubleType = NULL; llvm::Type *LLVMTypes::DoubleType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int8PointerType = NULL; llvm::Type *LLVMTypes::Int8PointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int16PointerType = NULL; llvm::Type *LLVMTypes::Int16PointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int32PointerType = NULL; llvm::Type *LLVMTypes::Int32PointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int64PointerType = NULL; llvm::Type *LLVMTypes::Int64PointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::FloatPointerType = NULL; llvm::Type *LLVMTypes::FloatPointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::DoublePointerType = NULL; llvm::Type *LLVMTypes::DoublePointerType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::MaskType = NULL; llvm::VectorType *LLVMTypes::MaskType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::BoolVectorType = NULL; llvm::VectorType *LLVMTypes::BoolVectorType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::Int1VectorType = NULL; llvm::VectorType *LLVMTypes::Int1VectorType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::Int8VectorType = NULL; llvm::VectorType *LLVMTypes::Int8VectorType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::Int16VectorType = NULL; llvm::VectorType *LLVMTypes::Int16VectorType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::Int32VectorType = NULL; llvm::VectorType *LLVMTypes::Int32VectorType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::Int64VectorType = NULL; llvm::VectorType *LLVMTypes::Int64VectorType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::FloatVectorType = NULL; llvm::VectorType *LLVMTypes::FloatVectorType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::DoubleVectorType = NULL; llvm::VectorType *LLVMTypes::DoubleVectorType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int8VectorPointerType = NULL; llvm::Type *LLVMTypes::Int8VectorPointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int16VectorPointerType = NULL; llvm::Type *LLVMTypes::Int16VectorPointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int32VectorPointerType = NULL; llvm::Type *LLVMTypes::Int32VectorPointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::Int64VectorPointerType = NULL; llvm::Type *LLVMTypes::Int64VectorPointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::FloatVectorPointerType = NULL; llvm::Type *LLVMTypes::FloatVectorPointerType = NULL;
LLVM_TYPE_CONST llvm::Type *LLVMTypes::DoubleVectorPointerType = NULL; llvm::Type *LLVMTypes::DoubleVectorPointerType = NULL;
LLVM_TYPE_CONST llvm::VectorType *LLVMTypes::VoidPointerVectorType = NULL; llvm::VectorType *LLVMTypes::VoidPointerVectorType = NULL;
llvm::Constant *LLVMTrue = NULL; llvm::Constant *LLVMTrue = NULL;
llvm::Constant *LLVMFalse = NULL; llvm::Constant *LLVMFalse = NULL;
@@ -473,9 +473,9 @@ LLVMBoolVector(const bool *bvec) {
llvm::Constant * llvm::Constant *
LLVMIntAsType(int64_t val, LLVM_TYPE_CONST llvm::Type *type) { LLVMIntAsType(int64_t val, llvm::Type *type) {
LLVM_TYPE_CONST llvm::VectorType *vecType = llvm::VectorType *vecType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(type); llvm::dyn_cast<llvm::VectorType>(type);
if (vecType != NULL) { if (vecType != NULL) {
llvm::Constant *v = llvm::ConstantInt::get(vecType->getElementType(), llvm::Constant *v = llvm::ConstantInt::get(vecType->getElementType(),
@@ -491,9 +491,9 @@ LLVMIntAsType(int64_t val, LLVM_TYPE_CONST llvm::Type *type) {
llvm::Constant * llvm::Constant *
LLVMUIntAsType(uint64_t val, LLVM_TYPE_CONST llvm::Type *type) { LLVMUIntAsType(uint64_t val, llvm::Type *type) {
LLVM_TYPE_CONST llvm::VectorType *vecType = llvm::VectorType *vecType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(type); llvm::dyn_cast<llvm::VectorType>(type);
if (vecType != NULL) { if (vecType != NULL) {
llvm::Constant *v = llvm::ConstantInt::get(vecType->getElementType(), llvm::Constant *v = llvm::ConstantInt::get(vecType->getElementType(),
@@ -642,8 +642,8 @@ LLVMFlattenInsertChain(llvm::InsertElementInst *ie, int vectorWidth,
bool bool
LLVMExtractVectorInts(llvm::Value *v, int64_t ret[], int *nElts) { LLVMExtractVectorInts(llvm::Value *v, int64_t ret[], int *nElts) {
// Make sure we do in fact have a vector of integer values here // Make sure we do in fact have a vector of integer values here
LLVM_TYPE_CONST llvm::VectorType *vt = llvm::VectorType *vt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(v->getType()); llvm::dyn_cast<llvm::VectorType>(v->getType());
Assert(vt != NULL); Assert(vt != NULL);
Assert(llvm::isa<llvm::IntegerType>(vt->getElementType())); Assert(llvm::isa<llvm::IntegerType>(vt->getElementType()));
@@ -696,7 +696,7 @@ lVectorValuesAllEqual(llvm::Value *v, int vectorLength,
static bool static bool
lIsExactMultiple(llvm::Value *val, int baseValue, int vectorLength, lIsExactMultiple(llvm::Value *val, int baseValue, int vectorLength,
std::vector<llvm::PHINode *> &seenPhis) { std::vector<llvm::PHINode *> &seenPhis) {
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(val->getType()) == false) { if (llvm::isa<llvm::VectorType>(val->getType()) == false) {
// If we've worked down to a constant int, then the moment of truth // If we've worked down to a constant int, then the moment of truth
// has arrived... // has arrived...
llvm::ConstantInt *ci = llvm::dyn_cast<llvm::ConstantInt>(val); llvm::ConstantInt *ci = llvm::dyn_cast<llvm::ConstantInt>(val);
@@ -780,7 +780,7 @@ static bool
lAllDivBaseEqual(llvm::Value *val, int64_t baseValue, int vectorLength, lAllDivBaseEqual(llvm::Value *val, int64_t baseValue, int vectorLength,
std::vector<llvm::PHINode *> &seenPhis, std::vector<llvm::PHINode *> &seenPhis,
bool &canAdd) { bool &canAdd) {
Assert(llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(val->getType())); Assert(llvm::isa<llvm::VectorType>(val->getType()));
// Make sure the base value is a positive power of 2 // Make sure the base value is a positive power of 2
Assert(baseValue > 0 && (baseValue & (baseValue-1)) == 0); Assert(baseValue > 0 && (baseValue & (baseValue-1)) == 0);
@@ -790,7 +790,7 @@ lAllDivBaseEqual(llvm::Value *val, int64_t baseValue, int vectorLength,
int64_t vecVals[ISPC_MAX_NVEC]; int64_t vecVals[ISPC_MAX_NVEC];
int nElts; int nElts;
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(val->getType()) && if (llvm::isa<llvm::VectorType>(val->getType()) &&
LLVMExtractVectorInts(val, vecVals, &nElts)) { LLVMExtractVectorInts(val, vecVals, &nElts)) {
// If we have a vector of compile-time constant integer values, // If we have a vector of compile-time constant integer values,
// then go ahead and check them directly.. // then go ahead and check them directly..
@@ -1074,8 +1074,8 @@ lVectorValuesAllEqual(llvm::Value *v, int vectorLength,
*/ */
bool bool
LLVMVectorValuesAllEqual(llvm::Value *v) { LLVMVectorValuesAllEqual(llvm::Value *v) {
LLVM_TYPE_CONST llvm::VectorType *vt = llvm::VectorType *vt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(v->getType()); llvm::dyn_cast<llvm::VectorType>(v->getType());
Assert(vt != NULL); Assert(vt != NULL);
int vectorLength = vt->getNumElements(); int vectorLength = vt->getNumElements();
@@ -1344,8 +1344,8 @@ lVectorIsLinear(llvm::Value *v, int vectorLength, int stride,
*/ */
bool bool
LLVMVectorIsLinear(llvm::Value *v, int stride) { LLVMVectorIsLinear(llvm::Value *v, int stride) {
LLVM_TYPE_CONST llvm::VectorType *vt = llvm::VectorType *vt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(v->getType()); llvm::dyn_cast<llvm::VectorType>(v->getType());
Assert(vt != NULL); Assert(vt != NULL);
int vectorLength = vt->getNumElements(); int vectorLength = vt->getNumElements();
@@ -1399,8 +1399,8 @@ lExtractFirstVectorElement(llvm::Value *v, llvm::Instruction *insertBefore,
return llvm::ExtractElementInst::Create(v, LLVMInt32(0), "first_elt", return llvm::ExtractElementInst::Create(v, LLVMInt32(0), "first_elt",
insertBefore); insertBefore);
LLVM_TYPE_CONST llvm::VectorType *vt = llvm::VectorType *vt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(v->getType()); llvm::dyn_cast<llvm::VectorType>(v->getType());
Assert(vt != NULL); Assert(vt != NULL);
std::string newName = v->getName().str() + std::string(".elt0"); std::string newName = v->getName().str() + std::string(".elt0");
@@ -1443,8 +1443,8 @@ lExtractFirstVectorElement(llvm::Value *v, llvm::Instruction *insertBefore,
llvm::Instruction *phiInsertPos = phi->getParent()->begin(); llvm::Instruction *phiInsertPos = phi->getParent()->begin();
llvm::PHINode *scalarPhi = llvm::PHINode *scalarPhi =
llvm::PHINode::Create(vt->getElementType(), llvm::PHINode::Create(vt->getElementType(),
phi->getNumIncomingValues(), newName, phi->getNumIncomingValues(),
phiInsertPos); newName, phiInsertPos);
phiMap[phi] = scalarPhi; phiMap[phi] = scalarPhi;
for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) { for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) {
@@ -1489,8 +1489,8 @@ LLVMConcatVectors(llvm::Value *v1, llvm::Value *v2,
llvm::Instruction *insertBefore) { llvm::Instruction *insertBefore) {
Assert(v1->getType() == v2->getType()); Assert(v1->getType() == v2->getType());
LLVM_TYPE_CONST llvm::VectorType *vt = llvm::VectorType *vt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(v1->getType()); llvm::dyn_cast<llvm::VectorType>(v1->getType());
Assert(vt != NULL); Assert(vt != NULL);
int32_t identity[ISPC_MAX_NVEC]; int32_t identity[ISPC_MAX_NVEC];
@@ -1518,12 +1518,8 @@ LLVMShuffleVectors(llvm::Value *v1, llvm::Value *v2, int32_t shuf[],
shufVec.push_back(LLVMInt32(shuf[i])); shufVec.push_back(LLVMInt32(shuf[i]));
} }
#ifndef LLVM_2_9
llvm::ArrayRef<llvm::Constant *> aref(&shufVec[0], &shufVec[shufSize]); llvm::ArrayRef<llvm::Constant *> aref(&shufVec[0], &shufVec[shufSize]);
llvm::Value *vec = llvm::ConstantVector::get(aref); llvm::Value *vec = llvm::ConstantVector::get(aref);
#else // LLVM_2_9
llvm::Value *vec = llvm::ConstantVector::get(shufVec);
#endif
return new llvm::ShuffleVectorInst(v1, v2, vec, "shuffle", insertBefore); return new llvm::ShuffleVectorInst(v1, v2, vec, "shuffle", insertBefore);
} }

View File

@@ -48,57 +48,50 @@ namespace llvm {
class InsertElementInst; class InsertElementInst;
} }
// llvm::Type *s are no longer const in llvm 3.0
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
#define LLVM_TYPE_CONST
#else
#define LLVM_TYPE_CONST const
#endif
/** This structure holds pointers to a variety of LLVM types; code /** This structure holds pointers to a variety of LLVM types; code
elsewhere can use them from here, ratherthan needing to make more elsewhere can use them from here, ratherthan needing to make more
verbose LLVM API calls. verbose LLVM API calls.
*/ */
struct LLVMTypes { struct LLVMTypes {
static LLVM_TYPE_CONST llvm::Type *VoidType; static llvm::Type *VoidType;
static LLVM_TYPE_CONST llvm::PointerType *VoidPointerType; static llvm::PointerType *VoidPointerType;
static LLVM_TYPE_CONST llvm::Type *PointerIntType; static llvm::Type *PointerIntType;
static LLVM_TYPE_CONST llvm::Type *BoolType; static llvm::Type *BoolType;
static LLVM_TYPE_CONST llvm::Type *Int8Type; static llvm::Type *Int8Type;
static LLVM_TYPE_CONST llvm::Type *Int16Type; static llvm::Type *Int16Type;
static LLVM_TYPE_CONST llvm::Type *Int32Type; static llvm::Type *Int32Type;
static LLVM_TYPE_CONST llvm::Type *Int64Type; static llvm::Type *Int64Type;
static LLVM_TYPE_CONST llvm::Type *FloatType; static llvm::Type *FloatType;
static LLVM_TYPE_CONST llvm::Type *DoubleType; static llvm::Type *DoubleType;
static LLVM_TYPE_CONST llvm::Type *Int8PointerType; static llvm::Type *Int8PointerType;
static LLVM_TYPE_CONST llvm::Type *Int16PointerType; static llvm::Type *Int16PointerType;
static LLVM_TYPE_CONST llvm::Type *Int32PointerType; static llvm::Type *Int32PointerType;
static LLVM_TYPE_CONST llvm::Type *Int64PointerType; static llvm::Type *Int64PointerType;
static LLVM_TYPE_CONST llvm::Type *FloatPointerType; static llvm::Type *FloatPointerType;
static LLVM_TYPE_CONST llvm::Type *DoublePointerType; static llvm::Type *DoublePointerType;
static LLVM_TYPE_CONST llvm::VectorType *MaskType; static llvm::VectorType *MaskType;
static LLVM_TYPE_CONST llvm::VectorType *BoolVectorType; static llvm::VectorType *BoolVectorType;
static LLVM_TYPE_CONST llvm::VectorType *Int1VectorType; static llvm::VectorType *Int1VectorType;
static LLVM_TYPE_CONST llvm::VectorType *Int8VectorType; static llvm::VectorType *Int8VectorType;
static LLVM_TYPE_CONST llvm::VectorType *Int16VectorType; static llvm::VectorType *Int16VectorType;
static LLVM_TYPE_CONST llvm::VectorType *Int32VectorType; static llvm::VectorType *Int32VectorType;
static LLVM_TYPE_CONST llvm::VectorType *Int64VectorType; static llvm::VectorType *Int64VectorType;
static LLVM_TYPE_CONST llvm::VectorType *FloatVectorType; static llvm::VectorType *FloatVectorType;
static LLVM_TYPE_CONST llvm::VectorType *DoubleVectorType; static llvm::VectorType *DoubleVectorType;
static LLVM_TYPE_CONST llvm::Type *Int8VectorPointerType; static llvm::Type *Int8VectorPointerType;
static LLVM_TYPE_CONST llvm::Type *Int16VectorPointerType; static llvm::Type *Int16VectorPointerType;
static LLVM_TYPE_CONST llvm::Type *Int32VectorPointerType; static llvm::Type *Int32VectorPointerType;
static LLVM_TYPE_CONST llvm::Type *Int64VectorPointerType; static llvm::Type *Int64VectorPointerType;
static LLVM_TYPE_CONST llvm::Type *FloatVectorPointerType; static llvm::Type *FloatVectorPointerType;
static LLVM_TYPE_CONST llvm::Type *DoubleVectorPointerType; static llvm::Type *DoubleVectorPointerType;
static LLVM_TYPE_CONST llvm::VectorType *VoidPointerVectorType; static llvm::VectorType *VoidPointerVectorType;
}; };
/** These variables hold the corresponding LLVM constant values as a /** These variables hold the corresponding LLVM constant values as a
@@ -175,11 +168,11 @@ extern llvm::Constant *LLVMDoubleVector(double f);
/** Returns a constant integer or vector (according to the given type) of /** Returns a constant integer or vector (according to the given type) of
the given signed integer value. */ the given signed integer value. */
extern llvm::Constant *LLVMIntAsType(int64_t, LLVM_TYPE_CONST llvm::Type *t); extern llvm::Constant *LLVMIntAsType(int64_t, llvm::Type *t);
/** Returns a constant integer or vector (according to the given type) of /** Returns a constant integer or vector (according to the given type) of
the given unsigned integer value. */ the given unsigned integer value. */
extern llvm::Constant *LLVMUIntAsType(uint64_t, LLVM_TYPE_CONST llvm::Type *t); extern llvm::Constant *LLVMUIntAsType(uint64_t, llvm::Type *t);
/** Returns an LLVM boolean vector based on the given array of values. /** Returns an LLVM boolean vector based on the given array of values.
The array should have g->target.vectorWidth elements. */ The array should have g->target.vectorWidth elements. */

View File

@@ -44,16 +44,9 @@
#ifdef ISPC_IS_WINDOWS #ifdef ISPC_IS_WINDOWS
#include <time.h> #include <time.h>
#endif // ISPC_IS_WINDOWS #endif // ISPC_IS_WINDOWS
#include <llvm/Support/PrettyStackTrace.h>
#include <llvm/Support/Signals.h> #include <llvm/Support/Signals.h>
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn) #include <llvm/Support/TargetRegistry.h>
#include <llvm/Support/TargetRegistry.h> #include <llvm/Support/TargetSelect.h>
#include <llvm/Support/TargetSelect.h>
#else
#include <llvm/Target/TargetRegistry.h>
#include <llvm/Target/TargetSelect.h>
#include <llvm/Target/SubtargetFeature.h>
#endif
#ifdef ISPC_IS_WINDOWS #ifdef ISPC_IS_WINDOWS
#define strcasecmp stricmp #define strcasecmp stricmp
@@ -67,9 +60,7 @@ static void
lPrintVersion() { lPrintVersion() {
printf("Intel(r) SPMD Program Compiler (ispc), %s (build %s @ %s, LLVM %s)\n", printf("Intel(r) SPMD Program Compiler (ispc), %s (build %s @ %s, LLVM %s)\n",
ISPC_VERSION, BUILD_VERSION, BUILD_DATE, ISPC_VERSION, BUILD_VERSION, BUILD_DATE,
#ifdef LLVM_2_9 #if defined(LLVM_3_0)
"2.9"
#elif defined(LLVM_3_0) || defined(LLVM_3_0svn)
"3.0" "3.0"
#elif defined(LLVM_3_1) || defined(LLVM_3_1svn) #elif defined(LLVM_3_1) || defined(LLVM_3_1svn)
"3.1" "3.1"
@@ -91,12 +82,10 @@ usage(int ret) {
Target::SupportedTargetArchs()); Target::SupportedTargetArchs());
printf(" [--c++-include-file=<name>]\t\tSpecify name of file to emit in #include statement in generated C++ code.\n"); printf(" [--c++-include-file=<name>]\t\tSpecify name of file to emit in #include statement in generated C++ code.\n");
printf(" [--cpu=<cpu>]\t\t\tSelect target CPU type\n"); printf(" [--cpu=<cpu>]\t\t\tSelect target CPU type\n");
printf(" <cpu>={%s}\n", Target::SupportedTargetCPUs()); printf(" <cpu>={%s}\n", Target::SupportedTargetCPUs().c_str());
printf(" [-D<foo>]\t\t\t\t#define given value when running preprocessor\n"); printf(" [-D<foo>]\t\t\t\t#define given value when running preprocessor\n");
printf(" [--emit-asm]\t\t\tGenerate assembly language file as output\n"); printf(" [--emit-asm]\t\t\tGenerate assembly language file as output\n");
#ifndef LLVM_2_9
printf(" [--emit-c++]\t\t\tEmit a C++ source file as output\n"); printf(" [--emit-c++]\t\t\tEmit a C++ source file as output\n");
#endif // !LLVM_2_9
printf(" [--emit-llvm]\t\t\tEmit LLVM bitode file as output\n"); printf(" [--emit-llvm]\t\t\tEmit LLVM bitode file as output\n");
printf(" [--emit-obj]\t\t\tGenerate object file file as output (default)\n"); printf(" [--emit-obj]\t\t\tGenerate object file file as output (default)\n");
printf(" [-g]\t\t\t\tGenerate debugging information\n"); printf(" [-g]\t\t\t\tGenerate debugging information\n");
@@ -202,17 +191,18 @@ static void lGetAllArgs(int Argc, char *Argv[], int &argc, char *argv[128]) {
} }
static void
lSignal(void *) {
FATAL("Unhandled signal sent to process; terminating.");
}
int main(int Argc, char *Argv[]) { int main(int Argc, char *Argv[]) {
int argc; int argc;
char *argv[128]; char *argv[128];
lGetAllArgs(Argc, Argv, argc, argv); lGetAllArgs(Argc, Argv, argc, argv);
#if 0 llvm::sys::AddSignalHandler(lSignal, NULL);
// Use LLVM's little utility function to print out nice stack traces if
// we crash
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc, argv);
#endif
// initialize available LLVM targets // initialize available LLVM targets
LLVMInitializeX86TargetInfo(); LLVMInitializeX86TargetInfo();
@@ -220,9 +210,7 @@ int main(int Argc, char *Argv[]) {
LLVMInitializeX86AsmPrinter(); LLVMInitializeX86AsmPrinter();
LLVMInitializeX86AsmParser(); LLVMInitializeX86AsmParser();
LLVMInitializeX86Disassembler(); LLVMInitializeX86Disassembler();
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
LLVMInitializeX86TargetMC(); LLVMInitializeX86TargetMC();
#endif
char *file = NULL; char *file = NULL;
const char *headerFileName = NULL; const char *headerFileName = NULL;
@@ -279,10 +267,8 @@ int main(int Argc, char *Argv[]) {
} }
else if (!strcmp(argv[i], "--emit-asm")) else if (!strcmp(argv[i], "--emit-asm"))
ot = Module::Asm; ot = Module::Asm;
#ifndef LLVM_2_9
else if (!strcmp(argv[i], "--emit-c++")) else if (!strcmp(argv[i], "--emit-c++"))
ot = Module::CXX; ot = Module::CXX;
#endif // !LLVM_2_9
else if (!strcmp(argv[i], "--emit-llvm")) else if (!strcmp(argv[i], "--emit-llvm"))
ot = Module::Bitcode; ot = Module::Bitcode;
else if (!strcmp(argv[i], "--emit-obj")) else if (!strcmp(argv[i], "--emit-obj"))

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -88,6 +88,24 @@
#include <llvm/Support/raw_ostream.h> #include <llvm/Support/raw_ostream.h>
#include <llvm/Bitcode/ReaderWriter.h> #include <llvm/Bitcode/ReaderWriter.h>
static void
lDeclareSizeAndPtrIntTypes(SymbolTable *symbolTable) {
const Type *ptrIntType = (g->target.is32Bit) ? AtomicType::VaryingInt32 :
AtomicType::VaryingInt64;
ptrIntType = ptrIntType->GetAsUnboundVariabilityType();
symbolTable->AddType("intptr_t", ptrIntType, SourcePos());
symbolTable->AddType("uintptr_t", ptrIntType->GetAsUnsignedType(),
SourcePos());
symbolTable->AddType("ptrdiff_t", ptrIntType, SourcePos());
const Type *sizeType = (g->target.is32Bit || g->opt.force32BitAddressing) ?
AtomicType::VaryingInt32 : AtomicType::VaryingInt64;
sizeType = sizeType->GetAsUnboundVariabilityType();
symbolTable->AddType("size_t", sizeType, SourcePos());
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Module // Module
@@ -103,6 +121,8 @@ Module::Module(const char *fn) {
symbolTable = new SymbolTable; symbolTable = new SymbolTable;
ast = new AST; ast = new AST;
lDeclareSizeAndPtrIntTypes(symbolTable);
module = new llvm::Module(filename ? filename : "<stdin>", *g->ctx); module = new llvm::Module(filename ? filename : "<stdin>", *g->ctx);
module->setTargetTriple(g->target.GetTripleString()); module->setTargetTriple(g->target.GetTripleString());
@@ -211,116 +231,170 @@ Module::CompileFile() {
void void
Module::AddTypeDef(Symbol *sym) { Module::AddTypeDef(const std::string &name, const Type *type,
SourcePos pos) {
// Typedefs are easy; just add the mapping between the given name and // Typedefs are easy; just add the mapping between the given name and
// the given type. // the given type.
symbolTable->AddType(sym->name.c_str(), sym->type, sym->pos); symbolTable->AddType(name.c_str(), type, pos);
} }
void void
Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) { Module::AddGlobalVariable(const std::string &name, const Type *type, Expr *initExpr,
bool isConst, StorageClass storageClass, SourcePos pos) {
// These may be NULL due to errors in parsing; just gracefully return // These may be NULL due to errors in parsing; just gracefully return
// here if so. // here if so.
if (sym == NULL || sym->type == NULL) { if (name == "" || type == NULL) {
// But if these are NULL and there haven't been any previous
// errors, something surprising is going on
Assert(errorCount > 0); Assert(errorCount > 0);
return; return;
} }
if (symbolTable->LookupFunction(sym->name.c_str())) { if (symbolTable->LookupFunction(name.c_str())) {
Error(sym->pos, "Global variable \"%s\" shadows previously-declared " Error(pos, "Global variable \"%s\" shadows previously-declared "
"function.", sym->name.c_str()); "function.", name.c_str());
return; return;
} }
if (sym->storageClass == SC_EXTERN_C) { if (storageClass == SC_EXTERN_C) {
Error(sym->pos, "extern \"C\" qualifier can only be used for " Error(pos, "extern \"C\" qualifier can only be used for "
"functions."); "functions.");
return; return;
} }
if (Type::Equal(sym->type, AtomicType::Void)) { if (Type::Equal(type, AtomicType::Void)) {
Error(sym->pos, "\"void\" type global variable is illegal."); Error(pos, "\"void\" type global variable is illegal.");
return; return;
} }
sym->type = ArrayType::SizeUnsizedArrays(sym->type, initExpr); type = ArrayType::SizeUnsizedArrays(type, initExpr);
if (sym->type == NULL) if (type == NULL)
return; return;
const ArrayType *at = dynamic_cast<const ArrayType *>(sym->type); const ArrayType *at = dynamic_cast<const ArrayType *>(type);
if (at != NULL && at->TotalElementCount() == 0) { if (at != NULL && at->TotalElementCount() == 0) {
Error(sym->pos, "Illegal to declare a global variable with unsized " Error(pos, "Illegal to declare a global variable with unsized "
"array dimensions that aren't set with an initializer " "array dimensions that aren't set with an initializer "
"expression."); "expression.");
return; return;
} }
LLVM_TYPE_CONST llvm::Type *llvmType = sym->type->LLVMType(g->ctx); llvm::Type *llvmType = type->LLVMType(g->ctx);
if (llvmType == NULL) if (llvmType == NULL)
return; return;
// See if we have an initializer expression for the global. If so, // See if we have an initializer expression for the global. If so,
// make sure it's a compile-time constant! // make sure it's a compile-time constant!
llvm::Constant *llvmInitializer = NULL; llvm::Constant *llvmInitializer = NULL;
if (sym->storageClass == SC_EXTERN || sym->storageClass == SC_EXTERN_C) { ConstExpr *constValue = NULL;
if (storageClass == SC_EXTERN || storageClass == SC_EXTERN_C) {
if (initExpr != NULL) if (initExpr != NULL)
Error(sym->pos, "Initializer can't be provided with \"extern\" " Error(pos, "Initializer can't be provided with \"extern\" "
"global variable \"%s\".", sym->name.c_str()); "global variable \"%s\".", name.c_str());
} }
else if (initExpr != NULL) { else {
initExpr = TypeCheck(initExpr);
if (initExpr != NULL) { if (initExpr != NULL) {
// We need to make sure the initializer expression is initExpr = TypeCheck(initExpr);
// the same type as the global. (But not if it's an
// ExprList; they don't have types per se / can't type
// convert themselves anyway.)
if (dynamic_cast<ExprList *>(initExpr) == NULL)
initExpr = TypeConvertExpr(initExpr, sym->type, "initializer");
if (initExpr != NULL) { if (initExpr != NULL) {
initExpr = Optimize(initExpr); // We need to make sure the initializer expression is
// Fingers crossed, now let's see if we've got a // the same type as the global. (But not if it's an
// constant value.. // ExprList; they don't have types per se / can't type
llvmInitializer = initExpr->GetConstant(sym->type); // convert themselves anyway.)
if (dynamic_cast<ExprList *>(initExpr) == NULL)
initExpr = TypeConvertExpr(initExpr, type, "initializer");
if (initExpr != NULL) {
initExpr = Optimize(initExpr);
// Fingers crossed, now let's see if we've got a
// constant value..
llvmInitializer = initExpr->GetConstant(type);
if (llvmInitializer != NULL) { if (llvmInitializer != NULL) {
if (sym->type->IsConstType()) if (type->IsConstType())
// Try to get a ConstExpr associated with // Try to get a ConstExpr associated with
// the symbol. This dynamic_cast can // the symbol. This dynamic_cast can
// validly fail, for example for types like // validly fail, for example for types like
// StructTypes where a ConstExpr can't // StructTypes where a ConstExpr can't
// represent their values. // represent their values.
sym->constValue = constValue = dynamic_cast<ConstExpr *>(initExpr);
dynamic_cast<ConstExpr *>(initExpr); }
else
Error(initExpr->pos, "Initializer for global variable \"%s\" "
"must be a constant.", name.c_str());
} }
else
Error(initExpr->pos, "Initializer for global variable \"%s\" "
"must be a constant.", sym->name.c_str());
} }
} }
// If no initializer was provided or if we couldn't get a value
// above, initialize it with zeros..
if (llvmInitializer == NULL)
llvmInitializer = llvm::Constant::getNullValue(llvmType);
} }
// If no initializer was provided or if we couldn't get a value Symbol *sym = symbolTable->LookupVariable(name.c_str());
// above, initialize it with zeros.. llvm::GlobalVariable *oldGV = NULL;
if (llvmInitializer == NULL) if (sym != NULL) {
llvmInitializer = llvm::Constant::getNullValue(llvmType); // We've already seen either a declaration or a definition of this
// global.
// If the type doesn't match with the previous one, issue an error.
if (!Type::Equal(sym->type, type) ||
(sym->storageClass != SC_EXTERN &&
sym->storageClass != SC_EXTERN_C &&
sym->storageClass != storageClass)) {
Error(pos, "Definition of variable \"%s\" conflicts with "
"definition at %s:%d.", name.c_str(),
sym->pos.name, sym->pos.first_line);
return;
}
llvm::GlobalVariable *gv =
llvm::dyn_cast<llvm::GlobalVariable>(sym->storagePtr);
Assert(gv != NULL);
// And issue an error if this is a redefinition of a variable
if (gv->hasInitializer() &&
sym->storageClass != SC_EXTERN && sym->storageClass != SC_EXTERN_C) {
Error(pos, "Redefinition of variable \"%s\" is illegal. "
"(Previous definition at %s:%d.)", sym->name.c_str(),
sym->pos.name, sym->pos.first_line);
return;
}
// Now, we either have a redeclaration of a global, or a definition
// of a previously-declared global. First, save the pointer to the
// previous llvm::GlobalVariable
oldGV = gv;
}
else {
sym = new Symbol(name, pos, type, storageClass);
symbolTable->AddVariable(sym);
}
sym->constValue = constValue;
llvm::GlobalValue::LinkageTypes linkage = llvm::GlobalValue::LinkageTypes linkage =
(sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage : (sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage :
llvm::GlobalValue::ExternalLinkage; llvm::GlobalValue::ExternalLinkage;
// Note that the NULL llvmInitializer is what leads to "extern"
// declarations coming up extern and not defining storage (a bit
// subtle)...
sym->storagePtr = new llvm::GlobalVariable(*module, llvmType, isConst, sym->storagePtr = new llvm::GlobalVariable(*module, llvmType, isConst,
linkage, llvmInitializer, linkage, llvmInitializer,
sym->name.c_str()); sym->name.c_str());
symbolTable->AddVariable(sym);
if (diBuilder && (sym->storageClass != SC_EXTERN)) { // Patch up any references to the previous GlobalVariable (e.g. from a
llvm::DIFile file = sym->pos.GetDIFile(); // declaration of a global that was later defined.)
diBuilder->createGlobalVariable(sym->name, if (oldGV != NULL) {
oldGV->replaceAllUsesWith(sym->storagePtr);
oldGV->removeFromParent();
sym->storagePtr->setName(sym->name.c_str());
}
if (diBuilder) {
llvm::DIFile file = pos.GetDIFile();
diBuilder->createGlobalVariable(name,
file, file,
sym->pos.first_line, pos.first_line,
sym->type->GetDIType(file), sym->type->GetDIType(file),
(sym->storageClass == SC_STATIC), (sym->storageClass == SC_STATIC),
sym->storagePtr); sym->storagePtr);
@@ -411,22 +485,23 @@ lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) {
false if any errors were encountered. false if any errors were encountered.
*/ */
void void
Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) { Module::AddFunctionDeclaration(const std::string &name,
const FunctionType *functionType = const FunctionType *functionType,
dynamic_cast<const FunctionType *>(funSym->type); StorageClass storageClass, bool isInline,
SourcePos pos) {
Assert(functionType != NULL); Assert(functionType != NULL);
// If a global variable with the same name has already been declared // If a global variable with the same name has already been declared
// issue an error. // issue an error.
if (symbolTable->LookupVariable(funSym->name.c_str()) != NULL) { if (symbolTable->LookupVariable(name.c_str()) != NULL) {
Error(funSym->pos, "Function \"%s\" shadows previously-declared global variable. " Error(pos, "Function \"%s\" shadows previously-declared global variable. "
"Ignoring this definition.", "Ignoring this definition.",
funSym->name.c_str()); name.c_str());
return; return;
} }
std::vector<Symbol *> overloadFuncs; std::vector<Symbol *> overloadFuncs;
symbolTable->LookupFunction(funSym->name.c_str(), &overloadFuncs); symbolTable->LookupFunction(name.c_str(), &overloadFuncs);
if (overloadFuncs.size() > 0) { if (overloadFuncs.size() > 0) {
for (unsigned int i = 0; i < overloadFuncs.size(); ++i) { for (unsigned int i = 0; i < overloadFuncs.size(); ++i) {
Symbol *overloadFunc = overloadFuncs[i]; Symbol *overloadFunc = overloadFuncs[i];
@@ -450,65 +525,67 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
break; break;
} }
if (i == functionType->GetNumParameters()) { if (i == functionType->GetNumParameters()) {
Error(funSym->pos, "Illegal to overload function by return " std::string thisRetType = functionType->GetReturnTypeString();
"type only (previous declaration was at line %d of " std::string otherRetType = ofType->GetReturnTypeString();
"file %s).", overloadFunc->pos.first_line, Error(pos, "Illegal to overload function by return "
overloadFunc->pos.name); "type only. This function returns \"%s\" while "
"previous declaration at %s:%d returns \"%s\".",
thisRetType.c_str(), overloadFunc->pos.name,
overloadFunc->pos.first_line, otherRetType.c_str());
return; return;
} }
} }
} }
} }
if (funSym->storageClass == SC_EXTERN_C) { if (storageClass == SC_EXTERN_C) {
// Make sure the user hasn't supplied both an 'extern "C"' and a // Make sure the user hasn't supplied both an 'extern "C"' and a
// 'task' qualifier with the function // 'task' qualifier with the function
if (functionType->isTask) { if (functionType->isTask) {
Error(funSym->pos, "\"task\" qualifier is illegal with C-linkage extern " Error(pos, "\"task\" qualifier is illegal with C-linkage extern "
"function \"%s\". Ignoring this function.", funSym->name.c_str()); "function \"%s\". Ignoring this function.", name.c_str());
return; return;
} }
std::vector<Symbol *> funcs; std::vector<Symbol *> funcs;
symbolTable->LookupFunction(funSym->name.c_str(), &funcs); symbolTable->LookupFunction(name.c_str(), &funcs);
if (funcs.size() > 0) { if (funcs.size() > 0) {
if (funcs.size() > 1) { if (funcs.size() > 1) {
// Multiple functions with this name have already been declared; // Multiple functions with this name have already been declared;
// can't overload here // can't overload here
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\"; " Error(pos, "Can't overload extern \"C\" function \"%s\"; "
"%d functions with the same name have already been declared.", "%d functions with the same name have already been declared.",
funSym->name.c_str(), (int)funcs.size()); name.c_str(), (int)funcs.size());
return; return;
} }
// One function with the same name has been declared; see if it // One function with the same name has been declared; see if it
// has the same type as this one, in which case it's ok. // has the same type as this one, in which case it's ok.
if (Type::Equal(funcs[0]->type, funSym->type)) if (Type::Equal(funcs[0]->type, functionType))
return; return;
else { else {
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".", Error(pos, "Can't overload extern \"C\" function \"%s\".",
funSym->name.c_str()); name.c_str());
return; return;
} }
} }
} }
// Get the LLVM FunctionType // Get the LLVM FunctionType
bool includeMask = (funSym->storageClass != SC_EXTERN_C); bool includeMask = (storageClass != SC_EXTERN_C);
LLVM_TYPE_CONST llvm::FunctionType *llvmFunctionType = llvm::FunctionType *llvmFunctionType =
functionType->LLVMFunctionType(g->ctx, includeMask); functionType->LLVMFunctionType(g->ctx, includeMask);
if (llvmFunctionType == NULL) if (llvmFunctionType == NULL)
return; return;
// And create the llvm::Function // And create the llvm::Function
llvm::GlobalValue::LinkageTypes linkage = (funSym->storageClass == SC_STATIC || llvm::GlobalValue::LinkageTypes linkage = (storageClass == SC_STATIC ||
isInline) ? isInline) ?
llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage; llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage;
std::string functionName;
if (funSym->storageClass == SC_EXTERN_C) std::string functionName = name;
functionName = funSym->name; if (storageClass != SC_EXTERN_C) {
else { functionName += functionType->Mangle();
functionName = funSym->MangledName();
if (g->mangleFunctionsWithTarget) if (g->mangleFunctionsWithTarget)
functionName += g->target.GetISAString(); functionName += g->target.GetISAString();
} }
@@ -518,7 +595,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
// Set function attributes: we never throw exceptions // Set function attributes: we never throw exceptions
function->setDoesNotThrow(true); function->setDoesNotThrow(true);
if (!(funSym->storageClass == SC_EXTERN_C) && if (storageClass != SC_EXTERN_C &&
!g->generateDebuggingSymbols && !g->generateDebuggingSymbols &&
isInline) isInline)
function->addFnAttr(llvm::Attribute::AlwaysInline); function->addFnAttr(llvm::Attribute::AlwaysInline);
@@ -528,17 +605,17 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
// Make sure that the return type isn't 'varying' if the function is // Make sure that the return type isn't 'varying' if the function is
// 'export'ed. // 'export'ed.
if (funSym->storageClass == SC_EXPORT && if (functionType->isExported &&
lRecursiveCheckValidParamType(functionType->GetReturnType())) lRecursiveCheckValidParamType(functionType->GetReturnType()))
Error(funSym->pos, "Illegal to return a \"varying\" type from exported " Error(pos, "Illegal to return a \"varying\" type from exported "
"function \"%s\"", funSym->name.c_str()); "function \"%s\"", name.c_str());
if (functionType->isTask && if (functionType->isTask &&
Type::Equal(functionType->GetReturnType(), AtomicType::Void) == false) Type::Equal(functionType->GetReturnType(), AtomicType::Void) == false)
Error(funSym->pos, "Task-qualified functions must have void return type."); Error(pos, "Task-qualified functions must have void return type.");
if (functionType->isExported || functionType->isExternC) if (functionType->isExported || functionType->isExternC)
lCheckForStructParameters(functionType, funSym->pos); lCheckForStructParameters(functionType, pos);
// Loop over all of the arguments; process default values if present // Loop over all of the arguments; process default values if present
// and do other checks and parameter attribute setting. // and do other checks and parameter attribute setting.
@@ -547,12 +624,12 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
for (int i = 0; i < nArgs; ++i) { for (int i = 0; i < nArgs; ++i) {
const Type *argType = functionType->GetParameterType(i); const Type *argType = functionType->GetParameterType(i);
const std::string &argName = functionType->GetParameterName(i); const std::string &argName = functionType->GetParameterName(i);
ConstExpr *defaultValue = functionType->GetParameterDefault(i); Expr *defaultValue = functionType->GetParameterDefault(i);
const SourcePos &argPos = functionType->GetParameterSourcePos(i); const SourcePos &argPos = functionType->GetParameterSourcePos(i);
// If the function is exported, make sure that the parameter // If the function is exported, make sure that the parameter
// doesn't have any varying stuff going on in it. // doesn't have any varying stuff going on in it.
if (funSym->storageClass == SC_EXPORT) if (functionType->isExported)
lCheckForVaryingParameter(argType, argName, argPos); lCheckForVaryingParameter(argType, argName, argPos);
// ISPC assumes that no pointers alias. (It should be possible to // ISPC assumes that no pointers alias. (It should be possible to
@@ -596,29 +673,41 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
function->eraseFromParent(); function->eraseFromParent();
function = module->getFunction(functionName); function = module->getFunction(functionName);
} }
funSym->function = function;
// Finally, we know all is good and we can add the function to the // Finally, we know all is good and we can add the function to the
// symbol table // symbol table
Symbol *funSym = new Symbol(name, pos, functionType, storageClass);
funSym->function = function;
bool ok = symbolTable->AddFunction(funSym); bool ok = symbolTable->AddFunction(funSym);
Assert(ok); Assert(ok);
} }
void void
Module::AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args, Module::AddFunctionDefinition(const std::string &name, const FunctionType *type,
Stmt *code) { Stmt *code) {
ast->AddFunction(sym, args, code); Symbol *sym = symbolTable->LookupFunction(name.c_str(), type);
if (sym == NULL) {
Assert(m->errorCount > 0);
return;
}
// 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);
} }
bool bool
Module::writeOutput(OutputType outputType, const char *outFileName, Module::writeOutput(OutputType outputType, const char *outFileName,
const char *includeFileName) { const char *includeFileName) {
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
if (diBuilder != NULL && outputType != Header) if (diBuilder != NULL && outputType != Header)
diBuilder->finalize(); diBuilder->finalize();
#endif // LLVM_3_0
// First, issue a warning if the output file suffix and the type of // First, issue a warning if the output file suffix and the type of
// file being created seem to mismatch. This can help catch missing // file being created seem to mismatch. This can help catch missing
@@ -640,14 +729,12 @@ Module::writeOutput(OutputType outputType, const char *outFileName,
if (strcasecmp(suffix, "o") && strcasecmp(suffix, "obj")) if (strcasecmp(suffix, "o") && strcasecmp(suffix, "obj"))
fileType = "object"; fileType = "object";
break; break;
#ifndef LLVM_2_9
case CXX: case CXX:
if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") && if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") &&
strcasecmp(suffix, "c++") && strcasecmp(suffix, "cxx") && strcasecmp(suffix, "c++") && strcasecmp(suffix, "cxx") &&
strcasecmp(suffix, "cpp")) strcasecmp(suffix, "cpp"))
fileType = "c++"; fileType = "c++";
break; break;
#endif // !LLVM_2_9
case Header: case Header:
if (strcasecmp(suffix, "h") && strcasecmp(suffix, "hh") && if (strcasecmp(suffix, "h") && strcasecmp(suffix, "hh") &&
strcasecmp(suffix, "hpp")) strcasecmp(suffix, "hpp"))
@@ -663,14 +750,12 @@ Module::writeOutput(OutputType outputType, const char *outFileName,
return writeHeader(outFileName); return writeHeader(outFileName);
else if (outputType == Bitcode) else if (outputType == Bitcode)
return writeBitcode(module, outFileName); return writeBitcode(module, outFileName);
#ifndef LLVM_2_9
else if (outputType == CXX) { else if (outputType == CXX) {
extern bool WriteCXXFile(llvm::Module *module, const char *fn, extern bool WriteCXXFile(llvm::Module *module, const char *fn,
int vectorWidth, const char *includeName); int vectorWidth, const char *includeName);
return WriteCXXFile(module, outFileName, g->target.vectorWidth, return WriteCXXFile(module, outFileName, g->target.vectorWidth,
includeFileName); includeFileName);
} }
#endif // !LLVM_2_9
else else
return writeObjectFileOrAssembly(outputType, outFileName); return writeObjectFileOrAssembly(outputType, outFileName);
} }
@@ -755,109 +840,56 @@ Module::writeObjectFileOrAssembly(llvm::TargetMachine *targetMachine,
} }
/** Small structure used in representing dependency graphs of structures /** Emits a declaration for the given struct to the given file. This
(i.e. given a StructType, which other structure types does it have as function first makes sure that declarations for any structs that are
elements). (recursively) members of this struct are emitted first.
*/
struct StructDAGNode {
StructDAGNode()
: visited(false) { }
bool visited;
std::vector<const StructType *> dependents;
};
/** Visit a node for the topological sort.
*/ */
static void static void
lVisitNode(const StructType *structType, lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedStructs,
std::map<const StructType *, StructDAGNode *> &structToNode, FILE *file) {
std::vector<const StructType *> &sortedTypes) { // Has this struct type already been declared? (This happens if it's a
Assert(structToNode.find(structType) != structToNode.end()); // member of another struct for which we emitted a declaration
// Get the node that encodes the structs that this one is immediately // previously.)
// dependent on. for (int i = 0; i < (int)emittedStructs->size(); ++i)
StructDAGNode *node = structToNode[structType]; if (Type::EqualIgnoringConst(st, (*emittedStructs)[i]))
if (node->visited) return;
return;
node->visited = true; // Otherwise first make sure any contained structs have been declared.
// Depth-first traversal: visit all of the dependent nodes... for (int i = 0; i < st->GetElementCount(); ++i) {
for (unsigned int i = 0; i < node->dependents.size(); ++i) const StructType *elementStructType =
lVisitNode(node->dependents[i], structToNode, sortedTypes); dynamic_cast<const StructType *>(st->GetElementType(i));
// ...and then add this one to the sorted list if (elementStructType != NULL)
sortedTypes.push_back(structType); lEmitStructDecl(elementStructType, emittedStructs, file);
}
// And now it's safe to declare this one
emittedStructs->push_back(st);
fprintf(file, "struct %s", st->GetStructName().c_str());
if (st->GetSOAWidth() > 0)
// This has to match the naming scheme in
// StructType::GetCDeclaration().
fprintf(file, "_SOA%d", st->GetSOAWidth());
fprintf(file, " {\n");
for (int i = 0; i < st->GetElementCount(); ++i) {
const Type *type = st->GetElementType(i)->GetAsNonConstType();
std::string d = type->GetCDeclaration(st->GetElementName(i));
fprintf(file, " %s;\n", d.c_str());
}
fprintf(file, "};\n\n");
} }
/** Given a set of structures that we want to print C declarations of in a /** Given a set of structures that we want to print C declarations of in a
header file, order them so that any struct that is used as a member header file, emit their declarations.
variable in another struct is printed before the struct that uses it
and then print them to the given file.
*/ */
static void static void
lEmitStructDecls(std::vector<const StructType *> &structTypes, FILE *file) { lEmitStructDecls(std::vector<const StructType *> &structTypes, FILE *file) {
// First, build a DAG among the struct types where there is an edge std::vector<const StructType *> emittedStructs;
// from node A to node B if struct type A depends on struct type B for (unsigned int i = 0; i < structTypes.size(); ++i)
lEmitStructDecl(structTypes[i], &emittedStructs, file);
// Records the struct types that have incoming edges in the Assert(emittedStructs.size() == structTypes.size());
// DAG--i.e. the ones that one or more other struct types depend on
std::set<const StructType *> hasIncomingEdges;
// Records the mapping between struct type pointers and the
// StructDagNode structures
std::map<const StructType *, StructDAGNode *> structToNode;
for (unsigned int i = 0; i < structTypes.size(); ++i) {
// For each struct type, create its DAG node and record the
// relationship between it and its node
const StructType *st = structTypes[i];
StructDAGNode *node = new StructDAGNode;
structToNode[st] = node;
for (int j = 0; j < st->GetElementCount(); ++j) {
const StructType *elementStructType =
dynamic_cast<const StructType *>(st->GetElementType(j));
// If this element is a struct type and we haven't already
// processed it for the current struct type, then upate th
// dependencies and record that this element type has other
// struct types that depend on it.
if (elementStructType != NULL &&
(std::find(node->dependents.begin(), node->dependents.end(),
elementStructType) == node->dependents.end())) {
node->dependents.push_back(elementStructType);
hasIncomingEdges.insert(elementStructType);
}
}
}
// Perform a topological sort of the struct types. Kick it off by
// visiting nodes with no incoming edges; i.e. the struct types that no
// other struct types depend on.
std::vector<const StructType *> sortedTypes;
for (unsigned int i = 0; i < structTypes.size(); ++i) {
const StructType *structType = structTypes[i];
if (hasIncomingEdges.find(structType) == hasIncomingEdges.end())
lVisitNode(structType, structToNode, sortedTypes);
}
Assert(sortedTypes.size() == structTypes.size());
// And finally we can emit the struct declarations by going through the
// sorted ones in order.
for (unsigned int i = 0; i < sortedTypes.size(); ++i) {
const StructType *st = sortedTypes[i];
fprintf(file, "struct %s", st->GetStructName().c_str());
if (st->GetSOAWidth() > 0)
// This has to match the naming scheme in
// StructType::GetCDeclaration().
fprintf(file, "_SOA%d", st->GetSOAWidth());
fprintf(file, " {\n");
for (int j = 0; j < st->GetElementCount(); ++j) {
const Type *type = st->GetElementType(j)->GetAsNonConstType();
std::string d = type->GetCDeclaration(st->GetElementName(j));
fprintf(file, " %s;\n", d.c_str());
}
fprintf(file, "};\n\n");
}
} }
@@ -1024,21 +1056,6 @@ lPrintFunctionDeclarations(FILE *file, const std::vector<Symbol *> &funcs) {
} }
static void
lPrintExternGlobals(FILE *file, const std::vector<Symbol *> &externGlobals) {
for (unsigned int i = 0; i < externGlobals.size(); ++i) {
Symbol *sym = externGlobals[i];
if (lRecursiveCheckValidParamType(sym->type))
Warning(sym->pos, "Not emitting declaration for symbol \"%s\" into "
"generated header file since it (or some of its members) "
"has types that are illegal in exported symbols.",
sym->name.c_str());
else
fprintf(file, "extern %s;\n", sym->type->GetCDeclaration(sym->name).c_str());
}
}
static bool static bool
lIsExported(const Symbol *sym) { lIsExported(const Symbol *sym) {
const FunctionType *ft = dynamic_cast<const FunctionType *>(sym->type); const FunctionType *ft = dynamic_cast<const FunctionType *>(sym->type);
@@ -1055,12 +1072,6 @@ lIsExternC(const Symbol *sym) {
} }
static bool
lIsExternGlobal(const Symbol *sym) {
return sym->storageClass == SC_EXTERN || sym->storageClass == SC_EXTERN_C;
}
bool bool
Module::writeHeader(const char *fn) { Module::writeHeader(const char *fn) {
FILE *f = fopen(fn, "w"); FILE *f = fopen(fn, "w");
@@ -1113,13 +1124,6 @@ Module::writeHeader(const char *fn) {
lGetExportedParamTypes(externCFuncs, &exportedStructTypes, lGetExportedParamTypes(externCFuncs, &exportedStructTypes,
&exportedEnumTypes, &exportedVectorTypes); &exportedEnumTypes, &exportedVectorTypes);
// And do the same for the 'extern' globals
std::vector<Symbol *> externGlobals;
symbolTable->GetMatchingVariables(lIsExternGlobal, &externGlobals);
for (unsigned int i = 0; i < externGlobals.size(); ++i)
lGetExportedTypes(externGlobals[i]->type, &exportedStructTypes,
&exportedEnumTypes, &exportedVectorTypes);
// And print them // And print them
lEmitVectorTypedefs(exportedVectorTypes, f); lEmitVectorTypedefs(exportedVectorTypes, f);
lEmitEnumDecls(exportedEnumTypes, f); lEmitEnumDecls(exportedEnumTypes, f);
@@ -1146,15 +1150,6 @@ Module::writeHeader(const char *fn) {
// end namespace // end namespace
fprintf(f, "\n#ifdef __cplusplus\n}\n#endif // __cplusplus\n"); fprintf(f, "\n#ifdef __cplusplus\n}\n#endif // __cplusplus\n");
// and only now emit externs for globals, outside of the ispc namespace
if (externGlobals.size() > 0) {
fprintf(f, "\n");
fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
fprintf(f, "// Globals declared \"extern\" from ispc code\n");
fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
lPrintExternGlobals(f, externGlobals);
}
// end guard // end guard
fprintf(f, "\n#endif // %s\n", guard.c_str()); fprintf(f, "\n#endif // %s\n", guard.c_str());
@@ -1171,18 +1166,12 @@ Module::execPreprocessor(const char* infilename, llvm::raw_string_ostream* ostre
llvm::raw_fd_ostream stderrRaw(2, false); llvm::raw_fd_ostream stderrRaw(2, false);
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
clang::TextDiagnosticPrinter *diagPrinter = clang::TextDiagnosticPrinter *diagPrinter =
new clang::TextDiagnosticPrinter(stderrRaw, clang::DiagnosticOptions()); new clang::TextDiagnosticPrinter(stderrRaw, clang::DiagnosticOptions());
llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs(new clang::DiagnosticIDs); llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs(new clang::DiagnosticIDs);
clang::DiagnosticsEngine *diagEngine = clang::DiagnosticsEngine *diagEngine =
new clang::DiagnosticsEngine(diagIDs, diagPrinter); new clang::DiagnosticsEngine(diagIDs, diagPrinter);
inst.setDiagnostics(diagEngine); inst.setDiagnostics(diagEngine);
#else
clang::TextDiagnosticPrinter *diagPrinter =
new clang::TextDiagnosticPrinter(stderrRaw, clang::DiagnosticOptions());
inst.createDiagnostics(0, NULL, diagPrinter);
#endif
clang::TargetOptions &options = inst.getTargetOpts(); clang::TargetOptions &options = inst.getTargetOpts();
llvm::Triple triple(module->getTargetTriple()); llvm::Triple triple(module->getTargetTriple());
@@ -1208,9 +1197,7 @@ Module::execPreprocessor(const char* infilename, llvm::raw_string_ostream* ostre
clang::HeaderSearchOptions &headerOpts = inst.getHeaderSearchOpts(); clang::HeaderSearchOptions &headerOpts = inst.getHeaderSearchOpts();
headerOpts.UseBuiltinIncludes = 0; headerOpts.UseBuiltinIncludes = 0;
#ifndef LLVM_2_9
headerOpts.UseStandardSystemIncludes = 0; headerOpts.UseStandardSystemIncludes = 0;
#endif // !LLVM_2_9
headerOpts.UseStandardCXXIncludes = 0; headerOpts.UseStandardCXXIncludes = 0;
if (g->debugPrint) if (g->debugPrint)
headerOpts.Verbose = 1; headerOpts.Verbose = 1;
@@ -1418,7 +1405,7 @@ lAddExtractedGlobals(llvm::Module *module,
for (unsigned int i = 0; i < globals[firstActive].size(); ++i) { for (unsigned int i = 0; i < globals[firstActive].size(); ++i) {
RewriteGlobalInfo &rgi = globals[firstActive][i]; RewriteGlobalInfo &rgi = globals[firstActive][i];
llvm::GlobalVariable *gv = rgi.gv; llvm::GlobalVariable *gv = rgi.gv;
LLVM_TYPE_CONST llvm::Type *type = gv->getType()->getElementType(); llvm::Type *type = gv->getType()->getElementType();
llvm::Constant *initializer = rgi.init; llvm::Constant *initializer = rgi.init;
// Create a new global in the given model that matches the original // Create a new global in the given model that matches the original
@@ -1482,7 +1469,7 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
// we'll start by generating an 'extern' declaration of each one that // we'll start by generating an 'extern' declaration of each one that
// we have in the current module so that we can then call out to that. // we have in the current module so that we can then call out to that.
llvm::Function *targetFuncs[Target::NUM_ISAS]; llvm::Function *targetFuncs[Target::NUM_ISAS];
LLVM_TYPE_CONST llvm::FunctionType *ftype = NULL; llvm::FunctionType *ftype = NULL;
for (int i = 0; i < Target::NUM_ISAS; ++i) { for (int i = 0; i < Target::NUM_ISAS; ++i) {
if (funcs.func[i] == NULL) { if (funcs.func[i] == NULL) {
@@ -1490,10 +1477,14 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
continue; continue;
} }
// Grab the type of the function as well. // Grab the type of the function as well. Note that the various
if (ftype != NULL) // functions will have different types if they have arguments that
Assert(ftype == funcs.func[i]->getFunctionType()); // are pointers to structs, due to the fact that we mangle LLVM
else // struct type names with the target vector width. However,
// because we only allow uniform stuff to pass through the
// export'ed function layer, they should all have the same memory
// layout, so this is benign..
if (ftype == NULL)
ftype = funcs.func[i]->getFunctionType(); ftype = funcs.func[i]->getFunctionType();
targetFuncs[i] = targetFuncs[i] =
@@ -1548,24 +1539,13 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
for (; argIter != dispatchFunc->arg_end(); ++argIter) for (; argIter != dispatchFunc->arg_end(); ++argIter)
args.push_back(argIter); args.push_back(argIter);
if (voidReturn) { if (voidReturn) {
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::CallInst::Create(targetFuncs[i], args, "", callBBlock); llvm::CallInst::Create(targetFuncs[i], args, "", callBBlock);
#else
llvm::CallInst::Create(targetFuncs[i], args.begin(), args.end(),
"", callBBlock);
#endif
llvm::ReturnInst::Create(*g->ctx, callBBlock); llvm::ReturnInst::Create(*g->ctx, callBBlock);
} }
else { else {
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::Value *retValue = llvm::Value *retValue =
llvm::CallInst::Create(targetFuncs[i], args, "ret_value", llvm::CallInst::Create(targetFuncs[i], args, "ret_value",
callBBlock); callBBlock);
#else
llvm::Value *retValue =
llvm::CallInst::Create(targetFuncs[i], args.begin(), args.end(),
"ret_value", callBBlock);
#endif
llvm::ReturnInst::Create(*g->ctx, retValue, callBBlock); llvm::ReturnInst::Create(*g->ctx, retValue, callBBlock);
} }
@@ -1663,13 +1643,11 @@ Module::CompileAndOutput(const char *srcFile, const char *arch, const char *cpu,
return errorCount > 0; return errorCount > 0;
} }
else { else {
#ifndef LLVM_2_9
if (outputType == CXX) { if (outputType == CXX) {
Error(SourcePos(), "Illegal to specify more then one target when " Error(SourcePos(), "Illegal to specify more then one target when "
"compiling C++ output."); "compiling C++ output.");
return 1; return 1;
} }
#endif // !LLVM_2_9
// The user supplied multiple targets // The user supplied multiple targets
std::vector<std::string> targets = lExtractTargets(target); std::vector<std::string> targets = lExtractTargets(target);

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -59,30 +59,33 @@ public:
int CompileFile(); int CompileFile();
/** Add a named type definition to the module. */ /** Add a named type definition to the module. */
void AddTypeDef(Symbol *sym); void AddTypeDef(const std::string &name, const Type *type,
SourcePos pos);
/** Add a new global variable corresponding to the given Symbol to the /** Add a new global variable corresponding to the given Symbol to the
module. If non-NULL, initExpr gives the initiailizer expression module. If non-NULL, initExpr gives the initiailizer expression
for the global's inital value. */ for the global's inital value. */
void AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst); void AddGlobalVariable(const std::string &name, const Type *type,
Expr *initExpr, bool isConst,
StorageClass storageClass, SourcePos pos);
/** Add a declaration of the function defined by the given function /** Add a declaration of the function defined by the given function
symbol to the module. */ symbol to the module. */
void AddFunctionDeclaration(Symbol *funSym, bool isInline); void AddFunctionDeclaration(const std::string &name,
const FunctionType *ftype,
StorageClass sc, bool isInline, SourcePos pos);
/** Adds the function described by the declaration information and the /** Adds the function described by the declaration information and the
provided statements to the module. */ provided statements to the module. */
void AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args, void AddFunctionDefinition(const std::string &name,
Stmt *code); const FunctionType *ftype, Stmt *code);
/** After a source file has been compiled, output can be generated in a /** After a source file has been compiled, output can be generated in a
number of different formats. */ number of different formats. */
enum OutputType { Asm, /** Generate text assembly language output */ enum OutputType { Asm, /** Generate text assembly language output */
Bitcode, /** Generate LLVM IR bitcode output */ Bitcode, /** Generate LLVM IR bitcode output */
Object, /** Generate a native object file */ Object, /** Generate a native object file */
#ifndef LLVM_2_9
CXX, /** Generate a C++ file */ CXX, /** Generate a C++ file */
#endif // !LLVM_2_9
Header /** Generate a C/C++ header file with Header /** Generate a C/C++ header file with
declarations of 'export'ed functions, global declarations of 'export'ed functions, global
variables, and the types used by them. */ variables, and the types used by them. */

122
opt.cpp
View File

@@ -59,9 +59,6 @@
#include <llvm/Constants.h> #include <llvm/Constants.h>
#include <llvm/Analysis/ConstantFolding.h> #include <llvm/Analysis/ConstantFolding.h>
#include <llvm/Target/TargetLibraryInfo.h> #include <llvm/Target/TargetLibraryInfo.h>
#ifdef LLVM_2_9
#include <llvm/Support/StandardPasses.h>
#endif // LLVM_2_9
#include <llvm/ADT/Triple.h> #include <llvm/ADT/Triple.h>
#include <llvm/Transforms/Scalar.h> #include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h> #include <llvm/Transforms/IPO.h>
@@ -188,13 +185,8 @@ static llvm::Instruction *
lCallInst(llvm::Function *func, llvm::Value *arg0, llvm::Value *arg1, lCallInst(llvm::Function *func, llvm::Value *arg0, llvm::Value *arg1,
const char *name, llvm::Instruction *insertBefore = NULL) { const char *name, llvm::Instruction *insertBefore = NULL) {
llvm::Value *args[2] = { arg0, arg1 }; llvm::Value *args[2] = { arg0, arg1 };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[2]); llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[2]);
return llvm::CallInst::Create(func, newArgArray, name, insertBefore); return llvm::CallInst::Create(func, newArgArray, name, insertBefore);
#else
return llvm::CallInst::Create(func, &args[0], &args[2],
name, insertBefore);
#endif
} }
@@ -203,13 +195,8 @@ lCallInst(llvm::Function *func, llvm::Value *arg0, llvm::Value *arg1,
llvm::Value *arg2, const char *name, llvm::Value *arg2, const char *name,
llvm::Instruction *insertBefore = NULL) { llvm::Instruction *insertBefore = NULL) {
llvm::Value *args[3] = { arg0, arg1, arg2 }; llvm::Value *args[3] = { arg0, arg1, arg2 };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[3]); llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[3]);
return llvm::CallInst::Create(func, newArgArray, name, insertBefore); return llvm::CallInst::Create(func, newArgArray, name, insertBefore);
#else
return llvm::CallInst::Create(func, &args[0], &args[3],
name, insertBefore);
#endif
} }
@@ -219,13 +206,8 @@ lCallInst(llvm::Function *func, llvm::Value *arg0, llvm::Value *arg1,
llvm::Value *arg2, llvm::Value *arg3, const char *name, llvm::Value *arg2, llvm::Value *arg3, const char *name,
llvm::Instruction *insertBefore = NULL) { llvm::Instruction *insertBefore = NULL) {
llvm::Value *args[4] = { arg0, arg1, arg2, arg3 }; llvm::Value *args[4] = { arg0, arg1, arg2, arg3 };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[4]); llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[4]);
return llvm::CallInst::Create(func, newArgArray, name, insertBefore); return llvm::CallInst::Create(func, newArgArray, name, insertBefore);
#else
return llvm::CallInst::Create(func, &args[0], &args[4],
name, insertBefore);
#endif
} }
#endif #endif
@@ -234,28 +216,19 @@ lCallInst(llvm::Function *func, llvm::Value *arg0, llvm::Value *arg1,
llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4, llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4,
const char *name, llvm::Instruction *insertBefore = NULL) { const char *name, llvm::Instruction *insertBefore = NULL) {
llvm::Value *args[5] = { arg0, arg1, arg2, arg3, arg4 }; llvm::Value *args[5] = { arg0, arg1, arg2, arg3, arg4 };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[5]); llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[5]);
return llvm::CallInst::Create(func, newArgArray, name, insertBefore); return llvm::CallInst::Create(func, newArgArray, name, insertBefore);
#else
return llvm::CallInst::Create(func, &args[0], &args[5],
name, insertBefore);
#endif
} }
static llvm::Instruction * static llvm::Instruction *
lCallInst(llvm::Function *func, llvm::Value *arg0, llvm::Value *arg1, lCallInst(llvm::Function *func, llvm::Value *arg0, llvm::Value *arg1,
llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4, llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4,
llvm::Value *arg5, const char *name, llvm::Value *arg5, const char *name,
llvm::Instruction *insertBefore = NULL) { llvm::Instruction *insertBefore = NULL) {
llvm::Value *args[6] = { arg0, arg1, arg2, arg3, arg4, arg5 }; llvm::Value *args[6] = { arg0, arg1, arg2, arg3, arg4, arg5 };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[6]); llvm::ArrayRef<llvm::Value *> newArgArray(&args[0], &args[6]);
return llvm::CallInst::Create(func, newArgArray, name, insertBefore); return llvm::CallInst::Create(func, newArgArray, name, insertBefore);
#else
return llvm::CallInst::Create(func, &args[0], &args[6],
name, insertBefore);
#endif
} }
@@ -263,14 +236,9 @@ static llvm::Instruction *
lGEPInst(llvm::Value *ptr, llvm::Value *offset, const char *name, lGEPInst(llvm::Value *ptr, llvm::Value *offset, const char *name,
llvm::Instruction *insertBefore) { llvm::Instruction *insertBefore) {
llvm::Value *index[1] = { offset }; llvm::Value *index[1] = { offset };
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::ArrayRef<llvm::Value *> arrayRef(&index[0], &index[1]); llvm::ArrayRef<llvm::Value *> arrayRef(&index[0], &index[1]);
return llvm::GetElementPtrInst::Create(ptr, arrayRef, name, return llvm::GetElementPtrInst::Create(ptr, arrayRef, name,
insertBefore); insertBefore);
#else
return llvm::GetElementPtrInst::Create(ptr, &index[0], &index[1],
name, insertBefore);
#endif
} }
@@ -286,6 +254,8 @@ Optimize(llvm::Module *module, int optLevel) {
llvm::PassManager optPM; llvm::PassManager optPM;
llvm::FunctionPassManager funcPM(module); llvm::FunctionPassManager funcPM(module);
optPM.add(llvm::createVerifierPass());
if (g->target.isa != Target::GENERIC) { if (g->target.isa != Target::GENERIC) {
llvm::TargetLibraryInfo *targetLibraryInfo = llvm::TargetLibraryInfo *targetLibraryInfo =
new llvm::TargetLibraryInfo(llvm::Triple(module->getTargetTriple())); new llvm::TargetLibraryInfo(llvm::Triple(module->getTargetTriple()));
@@ -293,9 +263,7 @@ Optimize(llvm::Module *module, int optLevel) {
optPM.add(new llvm::TargetData(module)); optPM.add(new llvm::TargetData(module));
} }
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
optPM.add(llvm::createIndVarSimplifyPass()); optPM.add(llvm::createIndVarSimplifyPass());
#endif
if (optLevel == 0) { if (optLevel == 0) {
// This is more or less the minimum set of optimizations that we // This is more or less the minimum set of optimizations that we
@@ -419,32 +387,6 @@ Optimize(llvm::Module *module, int optLevel) {
optPM.add(CreateIntrinsicsOptPass()); optPM.add(CreateIntrinsicsOptPass());
optPM.add(CreateVSelMovmskOptPass()); optPM.add(CreateVSelMovmskOptPass());
#if defined(LLVM_2_9)
llvm::createStandardModulePasses(&optPM, 3,
false /* opt size */,
true /* unit at a time */,
g->opt.unrollLoops,
true /* simplify lib calls */,
false /* may have exceptions */,
llvm::createFunctionInliningPass());
llvm::createStandardLTOPasses(&optPM, true /* internalize pass */,
true /* inline once again */,
false /* verify after each pass */);
llvm::createStandardFunctionPasses(&optPM, 3);
optPM.add(CreateIsCompileTimeConstantPass(true));
optPM.add(CreateIntrinsicsOptPass());
optPM.add(CreateVSelMovmskOptPass());
llvm::createStandardModulePasses(&optPM, 3,
false /* opt size */,
true /* unit at a time */,
g->opt.unrollLoops,
true /* simplify lib calls */,
false /* may have exceptions */,
llvm::createFunctionInliningPass());
#else
funcPM.add(llvm::createTypeBasedAliasAnalysisPass()); funcPM.add(llvm::createTypeBasedAliasAnalysisPass());
funcPM.add(llvm::createBasicAliasAnalysisPass()); funcPM.add(llvm::createBasicAliasAnalysisPass());
funcPM.add(llvm::createCFGSimplificationPass()); funcPM.add(llvm::createCFGSimplificationPass());
@@ -540,7 +482,7 @@ Optimize(llvm::Module *module, int optLevel) {
optPM.add(llvm::createStripDeadPrototypesPass()); optPM.add(llvm::createStripDeadPrototypesPass());
optPM.add(llvm::createGlobalDCEPass()); optPM.add(llvm::createGlobalDCEPass());
optPM.add(llvm::createConstantMergePass()); optPM.add(llvm::createConstantMergePass());
#endif
optPM.add(CreateMakeInternalFuncsStaticPass()); optPM.add(CreateMakeInternalFuncsStaticPass());
optPM.add(llvm::createGlobalDCEPass()); optPM.add(llvm::createGlobalDCEPass());
} }
@@ -631,22 +573,18 @@ IntrinsicsOpt::IntrinsicsOpt()
llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_sse_movmsk_ps); llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_sse_movmsk_ps);
maskInstructions.push_back(sseMovmsk); maskInstructions.push_back(sseMovmsk);
maskInstructions.push_back(m->module->getFunction("__movmsk")); maskInstructions.push_back(m->module->getFunction("__movmsk"));
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::Function *avxMovmsk = llvm::Function *avxMovmsk =
llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_avx_movmsk_ps_256); llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_avx_movmsk_ps_256);
Assert(avxMovmsk != NULL); Assert(avxMovmsk != NULL);
maskInstructions.push_back(avxMovmsk); maskInstructions.push_back(avxMovmsk);
#endif
// And all of the blend instructions // And all of the blend instructions
blendInstructions.push_back(BlendInstruction( blendInstructions.push_back(BlendInstruction(
llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_sse41_blendvps), llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_sse41_blendvps),
0xf, 0, 1, 2)); 0xf, 0, 1, 2));
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
blendInstructions.push_back(BlendInstruction( blendInstructions.push_back(BlendInstruction(
llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_avx_blendv_ps_256), llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_avx_blendv_ps_256),
0xff, 0, 1, 2)); 0xff, 0, 1, 2));
#endif
} }
@@ -744,7 +682,6 @@ lIsUndef(llvm::Value *value) {
bool bool
IntrinsicsOpt::runOnBasicBlock(llvm::BasicBlock &bb) { IntrinsicsOpt::runOnBasicBlock(llvm::BasicBlock &bb) {
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
llvm::Function *avxMaskedLoad32 = llvm::Function *avxMaskedLoad32 =
llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_avx_maskload_ps_256); llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_avx_maskload_ps_256);
llvm::Function *avxMaskedLoad64 = llvm::Function *avxMaskedLoad64 =
@@ -755,7 +692,6 @@ IntrinsicsOpt::runOnBasicBlock(llvm::BasicBlock &bb) {
llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_avx_maskstore_pd_256); llvm::Intrinsic::getDeclaration(m->module, llvm::Intrinsic::x86_avx_maskstore_pd_256);
Assert(avxMaskedLoad32 != NULL && avxMaskedStore32 != NULL); Assert(avxMaskedLoad32 != NULL && avxMaskedStore32 != NULL);
Assert(avxMaskedLoad64 != NULL && avxMaskedStore64 != NULL); Assert(avxMaskedLoad64 != NULL && avxMaskedStore64 != NULL);
#endif
bool modifiedAny = false; bool modifiedAny = false;
restart: restart:
@@ -827,7 +763,6 @@ IntrinsicsOpt::runOnBasicBlock(llvm::BasicBlock &bb) {
goto restart; goto restart;
} }
} }
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
else if (callInst->getCalledFunction() == avxMaskedLoad32 || else if (callInst->getCalledFunction() == avxMaskedLoad32 ||
callInst->getCalledFunction() == avxMaskedLoad64) { callInst->getCalledFunction() == avxMaskedLoad64) {
llvm::Value *factor = callInst->getArgOperand(1); llvm::Value *factor = callInst->getArgOperand(1);
@@ -894,7 +829,6 @@ IntrinsicsOpt::runOnBasicBlock(llvm::BasicBlock &bb) {
goto restart; goto restart;
} }
} }
#endif
} }
return modifiedAny; return modifiedAny;
} }
@@ -1050,7 +984,7 @@ static llvm::Value *
lCheckForActualPointer(llvm::Value *v) { lCheckForActualPointer(llvm::Value *v) {
if (v == NULL) if (v == NULL)
return NULL; return NULL;
else if (llvm::isa<LLVM_TYPE_CONST llvm::PointerType>(v->getType())) else if (llvm::isa<llvm::PointerType>(v->getType()))
return v; return v;
else if (llvm::isa<llvm::PtrToIntInst>(v)) else if (llvm::isa<llvm::PtrToIntInst>(v))
return v; return v;
@@ -1247,13 +1181,9 @@ lGetBasePtrAndOffsets(llvm::Value *ptrs, llvm::Value **offsets,
} }
Assert(base != NULL); Assert(base != NULL);
#ifdef LLVM_2_9
*offsets = llvm::ConstantVector::get(delta);
#else
llvm::ArrayRef<llvm::Constant *> deltas(&delta[0], llvm::ArrayRef<llvm::Constant *> deltas(&delta[0],
&delta[elements.size()]); &delta[elements.size()]);
*offsets = llvm::ConstantVector::get(deltas); *offsets = llvm::ConstantVector::get(deltas);
#endif
return base; return base;
} }
@@ -1978,8 +1908,8 @@ MaskedStoreOptPass::runOnBasicBlock(llvm::BasicBlock &bb) {
} }
else if (maskAsInt == allOnMask) { else if (maskAsInt == allOnMask) {
// The mask is all on, so turn this into a regular store // The mask is all on, so turn this into a regular store
LLVM_TYPE_CONST llvm::Type *rvalueType = rvalue->getType(); llvm::Type *rvalueType = rvalue->getType();
LLVM_TYPE_CONST llvm::Type *ptrType = llvm::Type *ptrType =
llvm::PointerType::get(rvalueType, 0); llvm::PointerType::get(rvalueType, 0);
lvalue = new llvm::BitCastInst(lvalue, ptrType, "lvalue_to_ptr_type", callInst); lvalue = new llvm::BitCastInst(lvalue, ptrType, "lvalue_to_ptr_type", callInst);
@@ -2081,7 +2011,7 @@ MaskedLoadOptPass::runOnBasicBlock(llvm::BasicBlock &bb) {
} }
else if (maskAsInt == allOnMask) { else if (maskAsInt == allOnMask) {
// The mask is all on, so turn this into a regular load // The mask is all on, so turn this into a regular load
LLVM_TYPE_CONST llvm::Type *ptrType = llvm::Type *ptrType =
llvm::PointerType::get(callInst->getType(), 0); llvm::PointerType::get(callInst->getType(), 0);
ptr = new llvm::BitCastInst(ptr, ptrType, "ptr_cast_for_load", ptr = new llvm::BitCastInst(ptr, ptrType, "ptr_cast_for_load",
callInst); callInst);
@@ -2139,17 +2069,17 @@ lIsSafeToBlend(llvm::Value *lvalue) {
else { else {
llvm::AllocaInst *ai = llvm::dyn_cast<llvm::AllocaInst>(lvalue); llvm::AllocaInst *ai = llvm::dyn_cast<llvm::AllocaInst>(lvalue);
if (ai) { if (ai) {
LLVM_TYPE_CONST llvm::Type *type = ai->getType(); llvm::Type *type = ai->getType();
LLVM_TYPE_CONST llvm::PointerType *pt = llvm::PointerType *pt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(type); llvm::dyn_cast<llvm::PointerType>(type);
assert(pt != NULL); assert(pt != NULL);
type = pt->getElementType(); type = pt->getElementType();
LLVM_TYPE_CONST llvm::ArrayType *at; llvm::ArrayType *at;
while ((at = llvm::dyn_cast<LLVM_TYPE_CONST llvm::ArrayType>(type))) { while ((at = llvm::dyn_cast<llvm::ArrayType>(type))) {
type = at->getElementType(); type = at->getElementType();
} }
LLVM_TYPE_CONST llvm::VectorType *vt = llvm::VectorType *vt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::VectorType>(type); llvm::dyn_cast<llvm::VectorType>(type);
return (vt != NULL && return (vt != NULL &&
(int)vt->getNumElements() == g->target.vectorWidth); (int)vt->getNumElements() == g->target.vectorWidth);
} }
@@ -2302,7 +2232,7 @@ lComputeCommonPointer(llvm::Value *base, llvm::Value *offsets,
struct ScatterImpInfo { struct ScatterImpInfo {
ScatterImpInfo(const char *pName, const char *msName, ScatterImpInfo(const char *pName, const char *msName,
LLVM_TYPE_CONST llvm::Type *vpt, int a) llvm::Type *vpt, int a)
: align(a) { : align(a) {
pseudoFunc = m->module->getFunction(pName); pseudoFunc = m->module->getFunction(pName);
maskedStoreFunc = m->module->getFunction(msName); maskedStoreFunc = m->module->getFunction(msName);
@@ -2311,7 +2241,7 @@ struct ScatterImpInfo {
} }
llvm::Function *pseudoFunc; llvm::Function *pseudoFunc;
llvm::Function *maskedStoreFunc; llvm::Function *maskedStoreFunc;
LLVM_TYPE_CONST llvm::Type *vecPtrType; llvm::Type *vecPtrType;
const int align; const int align;
}; };
@@ -2812,7 +2742,7 @@ lCoalescePerfInfo(const std::vector<llvm::CallInst *> &coalesceGroup,
*/ */
llvm::Value * llvm::Value *
lGEPAndLoad(llvm::Value *basePtr, int64_t offset, int align, lGEPAndLoad(llvm::Value *basePtr, int64_t offset, int align,
llvm::Instruction *insertBefore, LLVM_TYPE_CONST llvm::Type *type) { llvm::Instruction *insertBefore, llvm::Type *type) {
llvm::Value *ptr = lGEPInst(basePtr, LLVMInt64(offset), "new_base", llvm::Value *ptr = lGEPInst(basePtr, LLVMInt64(offset), "new_base",
insertBefore); insertBefore);
ptr = new llvm::BitCastInst(ptr, llvm::PointerType::get(type, 0), ptr = new llvm::BitCastInst(ptr, llvm::PointerType::get(type, 0),
@@ -2866,7 +2796,7 @@ lEmitLoads(llvm::Value *basePtr, std::vector<CoalescedLoadOp> &loadOps,
} }
case 4: { case 4: {
// 4-wide vector load // 4-wide vector load
LLVM_TYPE_CONST llvm::VectorType *vt = llvm::VectorType *vt =
llvm::VectorType::get(LLVMTypes::Int32Type, 4); llvm::VectorType::get(LLVMTypes::Int32Type, 4);
loadOps[i].load = lGEPAndLoad(basePtr, start, align, loadOps[i].load = lGEPAndLoad(basePtr, start, align,
insertBefore, vt); insertBefore, vt);
@@ -2874,7 +2804,7 @@ lEmitLoads(llvm::Value *basePtr, std::vector<CoalescedLoadOp> &loadOps,
} }
case 8: { case 8: {
// 8-wide vector load // 8-wide vector load
LLVM_TYPE_CONST llvm::VectorType *vt = llvm::VectorType *vt =
llvm::VectorType::get(LLVMTypes::Int32Type, 8); llvm::VectorType::get(LLVMTypes::Int32Type, 8);
loadOps[i].load = lGEPAndLoad(basePtr, start, align, loadOps[i].load = lGEPAndLoad(basePtr, start, align,
insertBefore, vt); insertBefore, vt);
@@ -2966,7 +2896,7 @@ lApplyLoad2(llvm::Value *result, const CoalescedLoadOp &load,
Assert(set[elt] == false && set[elt+1] == false); Assert(set[elt] == false && set[elt+1] == false);
// In this case, we bitcast from a 4xi32 to a 2xi64 vector // In this case, we bitcast from a 4xi32 to a 2xi64 vector
LLVM_TYPE_CONST llvm::Type *vec2x64Type = llvm::Type *vec2x64Type =
llvm::VectorType::get(LLVMTypes::Int64Type, 2); llvm::VectorType::get(LLVMTypes::Int64Type, 2);
result = new llvm::BitCastInst(result, vec2x64Type, "to2x64", result = new llvm::BitCastInst(result, vec2x64Type, "to2x64",
insertBefore); insertBefore);
@@ -2978,7 +2908,7 @@ lApplyLoad2(llvm::Value *result, const CoalescedLoadOp &load,
"insert64", insertBefore); "insert64", insertBefore);
// And back to 4xi32. // And back to 4xi32.
LLVM_TYPE_CONST llvm::Type *vec4x32Type = llvm::Type *vec4x32Type =
llvm::VectorType::get(LLVMTypes::Int32Type, 4); llvm::VectorType::get(LLVMTypes::Int32Type, 4);
result = new llvm::BitCastInst(result, vec4x32Type, "to4x32", result = new llvm::BitCastInst(result, vec4x32Type, "to4x32",
insertBefore); insertBefore);
@@ -3058,7 +2988,7 @@ lApplyLoad4(llvm::Value *result, const CoalescedLoadOp &load,
static llvm::Value * static llvm::Value *
lAssemble4Vector(const std::vector<CoalescedLoadOp> &loadOps, lAssemble4Vector(const std::vector<CoalescedLoadOp> &loadOps,
const int64_t offsets[4], llvm::Instruction *insertBefore) { const int64_t offsets[4], llvm::Instruction *insertBefore) {
LLVM_TYPE_CONST llvm::Type *returnType = llvm::Type *returnType =
llvm::VectorType::get(LLVMTypes::Int32Type, 4); llvm::VectorType::get(LLVMTypes::Int32Type, 4);
llvm::Value *result = llvm::UndefValue::get(returnType); llvm::Value *result = llvm::UndefValue::get(returnType);
@@ -3198,7 +3128,7 @@ lApplyLoad12s(llvm::Value *result, const std::vector<CoalescedLoadOp> &loadOps,
static llvm::Value * static llvm::Value *
lAssemble4Vector(const std::vector<CoalescedLoadOp> &loadOps, lAssemble4Vector(const std::vector<CoalescedLoadOp> &loadOps,
const int64_t offsets[4], llvm::Instruction *insertBefore) { const int64_t offsets[4], llvm::Instruction *insertBefore) {
LLVM_TYPE_CONST llvm::Type *returnType = llvm::Type *returnType =
llvm::VectorType::get(LLVMTypes::Int32Type, 4); llvm::VectorType::get(LLVMTypes::Int32Type, 4);
llvm::Value *result = llvm::UndefValue::get(returnType); llvm::Value *result = llvm::UndefValue::get(returnType);
@@ -3405,13 +3335,9 @@ lCoalesceGathers(const std::vector<llvm::CallInst *> &coalesceGroup) {
memory. */ memory. */
static bool static bool
lInstructionMayWriteToMemory(llvm::Instruction *inst) { lInstructionMayWriteToMemory(llvm::Instruction *inst) {
#ifdef LLVM_2_9
if (llvm::isa<llvm::StoreInst>(inst))
#else
if (llvm::isa<llvm::StoreInst>(inst) || if (llvm::isa<llvm::StoreInst>(inst) ||
llvm::isa<llvm::AtomicRMWInst>(inst) || llvm::isa<llvm::AtomicRMWInst>(inst) ||
llvm::isa<llvm::AtomicCmpXchgInst>(inst)) llvm::isa<llvm::AtomicCmpXchgInst>(inst))
#endif // !LLVM_2_9
// FIXME: we could be less conservative and try to allow stores if // FIXME: we could be less conservative and try to allow stores if
// we are sure that the pointers don't overlap.. // we are sure that the pointers don't overlap..
return true; return true;

119
parse.yy
View File

@@ -173,8 +173,11 @@ struct ForeachDimension {
} }
%token TOKEN_INT32_CONSTANT TOKEN_UINT32_CONSTANT TOKEN_INT64_CONSTANT %token TOKEN_INT32_CONSTANT TOKEN_UINT32_CONSTANT
%token TOKEN_UINT64_CONSTANT TOKEN_FLOAT_CONSTANT TOKEN_STRING_C_LITERAL %token TOKEN_INT64_CONSTANT TOKEN_UINT64_CONSTANT
%token TOKEN_INT32DOTDOTDOT_CONSTANT TOKEN_UINT32DOTDOTDOT_CONSTANT
%token TOKEN_INT64DOTDOTDOT_CONSTANT TOKEN_UINT64DOTDOTDOT_CONSTANT
%token TOKEN_FLOAT_CONSTANT TOKEN_STRING_C_LITERAL
%token TOKEN_IDENTIFIER TOKEN_STRING_LITERAL TOKEN_TYPE_NAME TOKEN_NULL %token TOKEN_IDENTIFIER TOKEN_STRING_LITERAL TOKEN_TYPE_NAME TOKEN_NULL
%token TOKEN_PTR_OP TOKEN_INC_OP TOKEN_DEC_OP TOKEN_LEFT_OP TOKEN_RIGHT_OP %token TOKEN_PTR_OP TOKEN_INC_OP TOKEN_DEC_OP TOKEN_LEFT_OP TOKEN_RIGHT_OP
%token TOKEN_LE_OP TOKEN_GE_OP TOKEN_EQ_OP TOKEN_NE_OP %token TOKEN_LE_OP TOKEN_GE_OP TOKEN_EQ_OP TOKEN_NE_OP
@@ -196,7 +199,7 @@ struct ForeachDimension {
%token TOKEN_CIF TOKEN_CDO TOKEN_CFOR TOKEN_CWHILE TOKEN_CBREAK %token TOKEN_CIF TOKEN_CDO TOKEN_CFOR TOKEN_CWHILE TOKEN_CBREAK
%token TOKEN_CCONTINUE TOKEN_CRETURN TOKEN_SYNC TOKEN_PRINT TOKEN_ASSERT %token TOKEN_CCONTINUE TOKEN_CRETURN TOKEN_SYNC TOKEN_PRINT TOKEN_ASSERT
%type <expr> primary_expression postfix_expression %type <expr> primary_expression postfix_expression integer_dotdotdot
%type <expr> unary_expression cast_expression funcall_expression launch_expression %type <expr> unary_expression cast_expression funcall_expression launch_expression
%type <expr> multiplicative_expression additive_expression shift_expression %type <expr> multiplicative_expression additive_expression shift_expression
%type <expr> relational_expression equality_expression and_expression %type <expr> relational_expression equality_expression and_expression
@@ -250,6 +253,12 @@ struct ForeachDimension {
string_constant string_constant
: TOKEN_STRING_LITERAL { $$ = new std::string(*yylval.stringVal); } : TOKEN_STRING_LITERAL { $$ = new std::string(*yylval.stringVal); }
| string_constant TOKEN_STRING_LITERAL
{
std::string s = *((std::string *)$1);
s += *yylval.stringVal;
$$ = new std::string(s);
}
; ;
primary_expression primary_expression
@@ -622,7 +631,9 @@ declaration_statement
if ($1->declarators[i] == NULL) if ($1->declarators[i] == NULL)
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
else else
m->AddTypeDef($1->declarators[i]->GetSymbol()); m->AddTypeDef($1->declarators[i]->name,
$1->declarators[i]->type,
$1->declarators[i]->pos);
} }
$$ = NULL; $$ = NULL;
} }
@@ -801,7 +812,6 @@ storage_class_specifier
: TOKEN_TYPEDEF { $$ = SC_TYPEDEF; } : TOKEN_TYPEDEF { $$ = SC_TYPEDEF; }
| TOKEN_EXTERN { $$ = SC_EXTERN; } | TOKEN_EXTERN { $$ = SC_EXTERN; }
| TOKEN_EXTERN TOKEN_STRING_C_LITERAL { $$ = SC_EXTERN_C; } | TOKEN_EXTERN TOKEN_STRING_C_LITERAL { $$ = SC_EXTERN_C; }
| TOKEN_EXPORT { $$ = SC_EXPORT; }
| TOKEN_STATIC { $$ = SC_STATIC; } | TOKEN_STATIC { $$ = SC_STATIC; }
; ;
@@ -864,7 +874,6 @@ struct_or_union_specifier
std::vector<SourcePos> elementPositions; std::vector<SourcePos> elementPositions;
GetStructTypesNamesPositions(*$3, &elementTypes, &elementNames, GetStructTypesNamesPositions(*$3, &elementTypes, &elementNames,
&elementPositions); &elementPositions);
// FIXME: should be unbound
$$ = new StructType("", elementTypes, elementNames, elementPositions, $$ = new StructType("", elementTypes, elementNames, elementPositions,
false, Variability::Unbound, @1); false, Variability::Unbound, @1);
} }
@@ -882,10 +891,9 @@ struct_or_union_specifier
| struct_or_union struct_or_union_name | struct_or_union struct_or_union_name
{ {
const Type *st = m->symbolTable->LookupType($2); const Type *st = m->symbolTable->LookupType($2);
if (!st) { if (st == NULL) {
std::vector<std::string> alternates = m->symbolTable->ClosestTypeMatch($2); st = new UndefinedStructType($2, Variability::Unbound, false, @2);
std::string alts = lGetAlternates(alternates); m->symbolTable->AddType($2, st, @2);
Error(@2, "Struct type \"%s\" unknown.%s", $2, alts.c_str());
} }
else if (dynamic_cast<const StructType *>(st) == NULL) else if (dynamic_cast<const StructType *>(st) == NULL)
Error(@2, "Type \"%s\" is not a struct type! (%s)", $2, Error(@2, "Type \"%s\" is not a struct type! (%s)", $2,
@@ -976,6 +984,11 @@ specifier_qualifier_list
"function declarations."); "function declarations.");
$$ = $2; $$ = $2;
} }
else if ($1 == TYPEQUAL_EXPORT) {
Error(@1, "\"export\" qualifier is illegal outside of "
"function declarations.");
$$ = $2;
}
else else
FATAL("Unhandled type qualifier in parser."); FATAL("Unhandled type qualifier in parser.");
} }
@@ -1108,6 +1121,7 @@ type_qualifier
| TOKEN_UNIFORM { $$ = TYPEQUAL_UNIFORM; } | TOKEN_UNIFORM { $$ = TYPEQUAL_UNIFORM; }
| TOKEN_VARYING { $$ = TYPEQUAL_VARYING; } | TOKEN_VARYING { $$ = TYPEQUAL_VARYING; }
| TOKEN_TASK { $$ = TYPEQUAL_TASK; } | TOKEN_TASK { $$ = TYPEQUAL_TASK; }
| TOKEN_EXPORT { $$ = TYPEQUAL_EXPORT; }
| TOKEN_INLINE { $$ = TYPEQUAL_INLINE; } | TOKEN_INLINE { $$ = TYPEQUAL_INLINE; }
| TOKEN_SIGNED { $$ = TYPEQUAL_SIGNED; } | TOKEN_SIGNED { $$ = TYPEQUAL_SIGNED; }
| TOKEN_UNSIGNED { $$ = TYPEQUAL_UNSIGNED; } | TOKEN_UNSIGNED { $$ = TYPEQUAL_UNSIGNED; }
@@ -1160,7 +1174,7 @@ direct_declarator
: TOKEN_IDENTIFIER : TOKEN_IDENTIFIER
{ {
Declarator *d = new Declarator(DK_BASE, @1); Declarator *d = new Declarator(DK_BASE, @1);
d->sym = new Symbol(yytext, @1); d->name = yytext;
$$ = d; $$ = d;
} }
| '(' declarator ')' | '(' declarator ')'
@@ -1335,8 +1349,10 @@ type_name
{ {
if ($1 == NULL || $2 == NULL) if ($1 == NULL || $2 == NULL)
$$ = NULL; $$ = NULL;
else else {
$$ = $2->GetType($1, NULL); $2->InitFromType($1, NULL);
$$ = $2->type;
}
} }
; ;
@@ -1614,11 +1630,34 @@ foreach_active_identifier
} }
; ;
integer_dotdotdot
: TOKEN_INT32DOTDOTDOT_CONSTANT {
$$ = new ConstExpr(AtomicType::UniformInt32->GetAsConstType(),
(int32_t)yylval.intVal, @1);
}
| TOKEN_UINT32DOTDOTDOT_CONSTANT {
$$ = new ConstExpr(AtomicType::UniformUInt32->GetAsConstType(),
(uint32_t)yylval.intVal, @1);
}
| TOKEN_INT64DOTDOTDOT_CONSTANT {
$$ = new ConstExpr(AtomicType::UniformInt64->GetAsConstType(),
(int64_t)yylval.intVal, @1);
}
| TOKEN_UINT64DOTDOTDOT_CONSTANT {
$$ = new ConstExpr(AtomicType::UniformUInt64->GetAsConstType(),
(uint64_t)yylval.intVal, @1);
}
;
foreach_dimension_specifier foreach_dimension_specifier
: foreach_identifier '=' assignment_expression TOKEN_DOTDOTDOT assignment_expression : foreach_identifier '=' assignment_expression TOKEN_DOTDOTDOT assignment_expression
{ {
$$ = new ForeachDimension($1, $3, $5); $$ = new ForeachDimension($1, $3, $5);
} }
| foreach_identifier '=' integer_dotdotdot assignment_expression
{
$$ = new ForeachDimension($1, $3, $4);
}
; ;
foreach_dimension_list foreach_dimension_list
@@ -1817,11 +1856,14 @@ function_definition
} }
compound_statement compound_statement
{ {
std::vector<Symbol *> args;
if ($2 != NULL) { if ($2 != NULL) {
Symbol *sym = $2->GetFunctionInfo($1, &args); $2->InitFromDeclSpecs($1);
if (sym != NULL) const FunctionType *funcType =
m->AddFunctionDefinition(sym, args, $4); dynamic_cast<const FunctionType *>($2->type);
if (funcType == NULL)
Assert(m->errorCount > 0);
else
m->AddFunctionDefinition($2->name, funcType, $4);
} }
m->symbolTable->PopScope(); // push in lAddFunctionParams(); m->symbolTable->PopScope(); // push in lAddFunctionParams();
} }
@@ -1931,35 +1973,27 @@ lAddDeclaration(DeclSpecs *ds, Declarator *decl) {
// Error happened earlier during parsing // Error happened earlier during parsing
return; return;
decl->InitFromDeclSpecs(ds);
if (ds->storageClass == SC_TYPEDEF) if (ds->storageClass == SC_TYPEDEF)
m->AddTypeDef(decl->GetSymbol()); m->AddTypeDef(decl->name, decl->type, decl->pos);
else { else {
const Type *t = decl->GetType(ds); if (decl->type == NULL) {
if (t == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return; return;
} }
Symbol *sym = decl->GetSymbol(); decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
if (sym == NULL) {
Assert(m->errorCount > 0); const FunctionType *ft = dynamic_cast<const FunctionType *>(decl->type);
return;
}
const FunctionType *ft = dynamic_cast<const FunctionType *>(t);
if (ft != NULL) { if (ft != NULL) {
sym->type = ft;
sym->storageClass = ds->storageClass;
bool isInline = (ds->typeQualifiers & TYPEQUAL_INLINE); bool isInline = (ds->typeQualifiers & TYPEQUAL_INLINE);
m->AddFunctionDeclaration(sym, isInline); m->AddFunctionDeclaration(decl->name, ft, ds->storageClass,
isInline, decl->pos);
} }
else { else {
if (sym->type == NULL)
Assert(m->errorCount > 0);
else
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
bool isConst = (ds->typeQualifiers & TYPEQUAL_CONST) != 0; bool isConst = (ds->typeQualifiers & TYPEQUAL_CONST) != 0;
m->AddGlobalVariable(sym, decl->initExpr, isConst); m->AddGlobalVariable(decl->name, decl->type, decl->initExpr,
isConst, decl->storageClass, decl->pos);
} }
} }
} }
@@ -1988,16 +2022,13 @@ lAddFunctionParams(Declarator *decl) {
// now loop over its parameters and add them to the symbol table // now loop over its parameters and add them to the symbol table
for (unsigned int i = 0; i < decl->functionParams.size(); ++i) { for (unsigned int i = 0; i < decl->functionParams.size(); ++i) {
Declaration *pdecl = decl->functionParams[i]; Declaration *pdecl = decl->functionParams[i];
if (pdecl == NULL || pdecl->declarators.size() == 0) Assert(pdecl != NULL && pdecl->declarators.size() == 1);
// zero size declarators array corresponds to an anonymous Declarator *declarator = pdecl->declarators[0];
// parameter if (declarator == NULL)
continue;
Assert(pdecl->declarators.size() == 1);
Symbol *sym = pdecl->declarators[0]->GetSymbol();
if (sym == NULL || sym->type == NULL)
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
else { else {
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying); Symbol *sym = new Symbol(declarator->name, declarator->pos,
declarator->type, declarator->storageClass);
#ifndef NDEBUG #ifndef NDEBUG
bool ok = m->symbolTable->AddVariable(sym); bool ok = m->symbolTable->AddVariable(sym);
if (ok == false) if (ok == false)
@@ -2064,8 +2095,6 @@ lGetStorageClassString(StorageClass sc) {
return ""; return "";
case SC_EXTERN: case SC_EXTERN:
return "extern"; return "extern";
case SC_EXPORT:
return "export";
case SC_STATIC: case SC_STATIC:
return "static"; return "static";
case SC_TYPEDEF: case SC_TYPEDEF:

View File

@@ -1,6 +1,6 @@
// -*- mode: c++ -*- // -*- mode: c++ -*-
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -746,6 +746,125 @@ static inline void prefetch_nt(const void * varying ptr) {
} }
} }
///////////////////////////////////////////////////////////////////////////
// non-short-circuiting alternatives
__declspec(safe,cost1)
static inline bool and(bool a, bool b) {
return a && b;
}
__declspec(safe,cost1)
static inline uniform bool and(uniform bool a, uniform bool b) {
return a && b;
}
__declspec(safe,cost1)
static inline bool or(bool a, bool b) {
return a || b;
}
__declspec(safe,cost1)
static inline uniform bool or(uniform bool a, uniform bool b) {
return a || b;
}
__declspec(safe,cost1)
static inline int8 select(bool c, int8 a, int8 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline int8 select(uniform bool c, int8 a, int8 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline uniform int8 select(uniform bool c, uniform int8 a,
uniform int8 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline int16 select(bool c, int16 a, int16 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline int16 select(uniform bool c, int16 a, int16 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline uniform int16 select(uniform bool c, uniform int16 a,
uniform int16 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline int32 select(bool c, int32 a, int32 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline int32 select(uniform bool c, int32 a, int32 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline uniform int32 select(uniform bool c, uniform int32 a,
uniform int32 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline int64 select(bool c, int64 a, int64 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline int64 select(uniform bool c, int64 a, int64 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline uniform int64 select(uniform bool c, uniform int64 a,
uniform int64 b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline float select(bool c, float a, float b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline float select(uniform bool c, float a, float b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline uniform float select(uniform bool c, uniform float a,
uniform float b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline double select(bool c, double a, double b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline double select(uniform bool c, double a, double b) {
return c ? a : b;
}
__declspec(safe,cost1)
static inline uniform double select(uniform bool c, uniform double a,
uniform double b) {
return c ? a : b;
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Horizontal ops / reductions // Horizontal ops / reductions
@@ -1469,22 +1588,17 @@ static inline void memory_barrier() {
#define DEFINE_ATOMIC_OP(TA,TB,OPA,OPB,MASKTYPE) \ #define DEFINE_ATOMIC_OP(TA,TB,OPA,OPB,MASKTYPE) \
static inline TA atomic_##OPA##_global(uniform TA * uniform ptr, TA value) { \ static inline TA atomic_##OPA##_global(uniform TA * uniform ptr, TA value) { \
memory_barrier(); \
TA ret = __atomic_##OPB##_##TB##_global(ptr, value, (MASKTYPE)__mask); \ TA ret = __atomic_##OPB##_##TB##_global(ptr, value, (MASKTYPE)__mask); \
memory_barrier(); \
return ret; \ return ret; \
} \ } \
static inline uniform TA atomic_##OPA##_global(uniform TA * uniform ptr, \ static inline uniform TA atomic_##OPA##_global(uniform TA * uniform ptr, \
uniform TA value) { \ uniform TA value) { \
memory_barrier(); \
uniform TA ret = __atomic_##OPB##_uniform_##TB##_global(ptr, value); \ uniform TA ret = __atomic_##OPB##_uniform_##TB##_global(ptr, value); \
memory_barrier(); \
return ret; \ return ret; \
} \ } \
static inline TA atomic_##OPA##_global(uniform TA * varying ptr, TA value) { \ static inline TA atomic_##OPA##_global(uniform TA * varying ptr, TA value) { \
uniform TA * uniform ptrArray[programCount]; \ uniform TA * uniform ptrArray[programCount]; \
ptrArray[programIndex] = ptr; \ ptrArray[programIndex] = ptr; \
memory_barrier(); \
TA ret; \ TA ret; \
__foreach_active (i) { \ __foreach_active (i) { \
uniform TA * uniform p = ptrArray[i]; \ uniform TA * uniform p = ptrArray[i]; \
@@ -1492,13 +1606,11 @@ static inline TA atomic_##OPA##_global(uniform TA * varying ptr, TA value) { \
uniform TA r = __atomic_##OPB##_uniform_##TB##_global(p, v); \ uniform TA r = __atomic_##OPB##_uniform_##TB##_global(p, v); \
ret = insert(ret, i, r); \ ret = insert(ret, i, r); \
} \ } \
memory_barrier(); \
return ret; \ return ret; \
} \ } \
#define DEFINE_ATOMIC_SWAP(TA,TB) \ #define DEFINE_ATOMIC_SWAP(TA,TB) \
static inline TA atomic_swap_global(uniform TA * uniform ptr, TA value) { \ static inline TA atomic_swap_global(uniform TA * uniform ptr, TA value) { \
memory_barrier(); \
uniform int i = 0; \ uniform int i = 0; \
TA ret[programCount]; \ TA ret[programCount]; \
TA memVal; \ TA memVal; \
@@ -1528,20 +1640,16 @@ static inline TA atomic_swap_global(uniform TA * uniform ptr, TA value) { \
/* And the last instance that wanted to swap gets the value we \ /* And the last instance that wanted to swap gets the value we \
originally got back from memory... */ \ originally got back from memory... */ \
ret[lastSwap] = memVal; \ ret[lastSwap] = memVal; \
memory_barrier(); \
return ret[programIndex]; \ return ret[programIndex]; \
} \ } \
static inline uniform TA atomic_swap_global(uniform TA * uniform ptr, \ static inline uniform TA atomic_swap_global(uniform TA * uniform ptr, \
uniform TA value) { \ uniform TA value) { \
memory_barrier(); \
uniform TA ret = __atomic_swap_uniform_##TB##_global(ptr, value); \ uniform TA ret = __atomic_swap_uniform_##TB##_global(ptr, value); \
memory_barrier(); \
return ret; \ return ret; \
} \ } \
static inline TA atomic_swap_global(uniform TA * varying ptr, TA value) { \ static inline TA atomic_swap_global(uniform TA * varying ptr, TA value) { \
uniform TA * uniform ptrArray[programCount]; \ uniform TA * uniform ptrArray[programCount]; \
ptrArray[programIndex] = ptr; \ ptrArray[programIndex] = ptr; \
memory_barrier(); \
TA ret; \ TA ret; \
__foreach_active (i) { \ __foreach_active (i) { \
uniform TA * uniform p = ptrArray[i]; \ uniform TA * uniform p = ptrArray[i]; \
@@ -1549,7 +1657,6 @@ static inline TA atomic_swap_global(uniform TA * varying ptr, TA value) { \
uniform TA r = __atomic_swap_uniform_##TB##_global(p, v); \ uniform TA r = __atomic_swap_uniform_##TB##_global(p, v); \
ret = insert(ret, i, r); \ ret = insert(ret, i, r); \
} \ } \
memory_barrier(); \
return ret; \ return ret; \
} \ } \
@@ -1557,25 +1664,19 @@ static inline TA atomic_swap_global(uniform TA * varying ptr, TA value) { \
static inline TA atomic_##OPA##_global(uniform TA * uniform ptr, TA value) { \ static inline TA atomic_##OPA##_global(uniform TA * uniform ptr, TA value) { \
uniform TA oneval = reduce_##OPA(value); \ uniform TA oneval = reduce_##OPA(value); \
TA ret; \ TA ret; \
if (lanemask() != 0) { \ if (lanemask() != 0) \
memory_barrier(); \
ret = __atomic_##OPB##_uniform_##TB##_global(ptr, oneval); \ ret = __atomic_##OPB##_uniform_##TB##_global(ptr, oneval); \
memory_barrier(); \
} \
return ret; \ return ret; \
} \ } \
static inline uniform TA atomic_##OPA##_global(uniform TA * uniform ptr, \ static inline uniform TA atomic_##OPA##_global(uniform TA * uniform ptr, \
uniform TA value) { \ uniform TA value) { \
memory_barrier(); \
uniform TA ret = __atomic_##OPB##_uniform_##TB##_global(ptr, value); \ uniform TA ret = __atomic_##OPB##_uniform_##TB##_global(ptr, value); \
memory_barrier(); \
return ret; \ return ret; \
} \ } \
static inline TA atomic_##OPA##_global(uniform TA * varying ptr, \ static inline TA atomic_##OPA##_global(uniform TA * varying ptr, \
TA value) { \ TA value) { \
uniform TA * uniform ptrArray[programCount]; \ uniform TA * uniform ptrArray[programCount]; \
ptrArray[programIndex] = ptr; \ ptrArray[programIndex] = ptr; \
memory_barrier(); \
TA ret; \ TA ret; \
__foreach_active (i) { \ __foreach_active (i) { \
uniform TA * uniform p = ptrArray[i]; \ uniform TA * uniform p = ptrArray[i]; \
@@ -1583,7 +1684,6 @@ static inline TA atomic_##OPA##_global(uniform TA * varying ptr, \
uniform TA r = __atomic_##OPB##_uniform_##TB##_global(p, v); \ uniform TA r = __atomic_##OPB##_uniform_##TB##_global(p, v); \
ret = insert(ret, i, r); \ ret = insert(ret, i, r); \
} \ } \
memory_barrier(); \
return ret; \ return ret; \
} }
@@ -1638,25 +1738,20 @@ DEFINE_ATOMIC_SWAP(double,double)
#define ATOMIC_DECL_CMPXCHG(TA, TB, MASKTYPE) \ #define ATOMIC_DECL_CMPXCHG(TA, TB, MASKTYPE) \
static inline uniform TA atomic_compare_exchange_global( \ static inline uniform TA atomic_compare_exchange_global( \
uniform TA * uniform ptr, uniform TA oldval, uniform TA newval) { \ uniform TA * uniform ptr, uniform TA oldval, uniform TA newval) { \
memory_barrier(); \
uniform TA ret = \ uniform TA ret = \
__atomic_compare_exchange_uniform_##TB##_global(ptr, oldval, newval); \ __atomic_compare_exchange_uniform_##TB##_global(ptr, oldval, newval); \
memory_barrier(); \
return ret; \ return ret; \
} \ } \
static inline TA atomic_compare_exchange_global( \ static inline TA atomic_compare_exchange_global( \
uniform TA * uniform ptr, TA oldval, TA newval) { \ uniform TA * uniform ptr, TA oldval, TA newval) { \
memory_barrier(); \
TA ret = __atomic_compare_exchange_##TB##_global(ptr, oldval, newval, \ TA ret = __atomic_compare_exchange_##TB##_global(ptr, oldval, newval, \
(MASKTYPE)__mask); \ (MASKTYPE)__mask); \
memory_barrier(); \
return ret; \ return ret; \
} \ } \
static inline TA atomic_compare_exchange_global( \ static inline TA atomic_compare_exchange_global( \
uniform TA * varying ptr, TA oldval, TA newval) { \ uniform TA * varying ptr, TA oldval, TA newval) { \
uniform TA * uniform ptrArray[programCount]; \ uniform TA * uniform ptrArray[programCount]; \
ptrArray[programIndex] = ptr; \ ptrArray[programIndex] = ptr; \
memory_barrier(); \
TA ret; \ TA ret; \
__foreach_active (i) { \ __foreach_active (i) { \
uniform TA r = \ uniform TA r = \
@@ -1665,7 +1760,6 @@ static inline TA atomic_compare_exchange_global( \
extract(newval, i)); \ extract(newval, i)); \
ret = insert(ret, i, r); \ ret = insert(ret, i, r); \
} \ } \
memory_barrier(); \
return ret; \ return ret; \
} }
@@ -1678,6 +1772,49 @@ ATOMIC_DECL_CMPXCHG(double, double, IntMaskType)
#undef ATOMIC_DECL_CMPXCHG #undef ATOMIC_DECL_CMPXCHG
// void * variants of swap and compare exchange
static inline void *atomic_swap_global(void ** uniform ptr,
void * value) {
return (void *)atomic_swap_global((intptr_t * uniform)ptr,
(intptr_t)value);
}
static inline void * uniform atomic_swap_global(void ** uniform ptr,
void * uniform value) {
return (void * uniform)atomic_swap_global((intptr_t * uniform)ptr,
(uniform intptr_t)value);
}
static inline void *atomic_swap_global(void ** ptr, void * value) {
return (void *)atomic_swap_global((intptr_t *)ptr,
(intptr_t)value);
}
static inline void *
atomic_compare_exchange_global(void ** uniform ptr,
void * oldval, void * newval) {
return (void *)atomic_compare_exchange_global((intptr_t * uniform)ptr,
(intptr_t)oldval,
(intptr_t)newval);
}
static inline void * uniform
atomic_compare_exchange_global(void ** uniform ptr, void * uniform oldval,
void * uniform newval) {
return (void * uniform)atomic_compare_exchange_global((intptr_t * uniform)ptr,
(uniform intptr_t)oldval,
(uniform intptr_t)newval);
}
static inline void *
atomic_compare_exchange_global(void ** ptr, void * oldval,
void * newval) {
return (void *)atomic_compare_exchange_global((intptr_t *)ptr,
(intptr_t)oldval,
(intptr_t)newval);
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// local atomics // local atomics
@@ -1849,6 +1986,49 @@ LOCAL_CMPXCHG(double)
#undef LOCAL_ATOMIC #undef LOCAL_ATOMIC
#undef LOCAL_CMPXCHG #undef LOCAL_CMPXCHG
// void * variants of swap and compare exchange
static inline void *atomic_swap_local(void ** uniform ptr,
void * value) {
return (void *)atomic_swap_local((intptr_t * uniform)ptr,
(intptr_t)value);
}
static inline void * uniform atomic_swap_local(void ** uniform ptr,
void * uniform value) {
return (void * uniform)atomic_swap_local((intptr_t * uniform)ptr,
(uniform intptr_t)value);
}
static inline void *atomic_swap_local(void ** ptr, void * value) {
return (void *)atomic_swap_local((intptr_t *)ptr,
(intptr_t)value);
}
static inline void *
atomic_compare_exchange_local(void ** uniform ptr,
void * oldval, void * newval) {
return (void *)atomic_compare_exchange_local((intptr_t * uniform)ptr,
(intptr_t)oldval,
(intptr_t)newval);
}
static inline void * uniform
atomic_compare_exchange_local(void ** uniform ptr, void * uniform oldval,
void * uniform newval) {
return (void * uniform)atomic_compare_exchange_local((intptr_t * uniform)ptr,
(uniform intptr_t)oldval,
(uniform intptr_t)newval);
}
static inline void *
atomic_compare_exchange_local(void ** ptr, void * oldval,
void * newval) {
return (void *)atomic_compare_exchange_local((intptr_t *)ptr,
(intptr_t)oldval,
(intptr_t)newval);
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Transcendentals (float precision) // Transcendentals (float precision)
@@ -3551,8 +3731,9 @@ static inline int16 float_to_half(float f) {
// like recursive filters in DSP - not a typical half-float application. Whether // like recursive filters in DSP - not a typical half-float application. Whether
// FP16 denormals are rare in practice, I don't know. Whatever slow path your HW // FP16 denormals are rare in practice, I don't know. Whatever slow path your HW
// may or may not have for denormals, this may well hit it. // may or may not have for denormals, this may well hit it.
int32 fint2 = intbits(floatbits(fint & round_mask) * floatbits(magic)) - round_mask; float fscale = floatbits(fint & round_mask) * floatbits(magic);
fint2 = (fint2 > f16infty) ? f16infty : fint2; // Clamp to signed infinity if overflowed fscale = min(fscale, floatbits((31 << 23) - 0x1000));
int32 fint2 = intbits(fscale) - round_mask;
if (fint < f32infty) if (fint < f32infty)
o = fint2 >> 13; // Take the bits! o = fint2 >> 13; // Take the bits!

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,7 @@
#include "util.h" #include "util.h"
#include "expr.h" #include "expr.h"
#include "type.h" #include "type.h"
#include "func.h"
#include "sym.h" #include "sym.h"
#include "module.h" #include "module.h"
#include "llvmutil.h" #include "llvmutil.h"
@@ -167,14 +168,28 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
} }
// References must have initializer expressions as well. // References must have initializer expressions as well.
if (dynamic_cast<const ReferenceType *>(sym->type) && initExpr == NULL) { if (IsReferenceType(sym->type) == true) {
Error(sym->pos, if (initExpr == NULL) {
"Must provide initializer for reference-type variable \"%s\".", Error(sym->pos, "Must provide initializer for reference-type "
sym->name.c_str()); "variable \"%s\".", sym->name.c_str());
continue; continue;
}
if (IsReferenceType(initExpr->GetType()) == false) {
const Type *initLVType = initExpr->GetLValueType();
if (initLVType == NULL) {
Error(initExpr->pos, "Initializer for reference-type variable "
"\"%s\" must have an lvalue type.", sym->name.c_str());
continue;
}
if (initLVType->IsUniformType() == false) {
Error(initExpr->pos, "Initializer for reference-type variable "
"\"%s\" must have a uniform lvalue type.", sym->name.c_str());
continue;
}
}
} }
LLVM_TYPE_CONST llvm::Type *llvmType = sym->type->LLVMType(g->ctx); llvm::Type *llvmType = sym->type->LLVMType(g->ctx);
if (llvmType == NULL) { if (llvmType == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return; return;
@@ -2173,8 +2188,8 @@ SwitchStmt::EstimateCost() const {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// ReturnStmt // ReturnStmt
ReturnStmt::ReturnStmt(Expr *v, bool cc, SourcePos p) ReturnStmt::ReturnStmt(Expr *e, bool cc, SourcePos p)
: Stmt(p), val(v), : Stmt(p), expr(e),
doCoherenceCheck(cc && !g->opt.disableCoherentControlFlow) { doCoherenceCheck(cc && !g->opt.disableCoherentControlFlow) {
} }
@@ -2189,8 +2204,29 @@ ReturnStmt::EmitCode(FunctionEmitContext *ctx) const {
return; return;
} }
// Make sure we're not trying to return a reference to something where
// that doesn't make sense
const Function *func = ctx->GetFunction();
const Type *returnType = func->GetReturnType();
if (IsReferenceType(returnType) == true &&
IsReferenceType(expr->GetType()) == false) {
const Type *lvType = expr->GetLValueType();
if (lvType == NULL) {
Error(expr->pos, "Illegal to return non-lvalue from function "
"returning reference type \"%s\".",
returnType->GetString().c_str());
return;
}
else if (lvType->IsUniformType() == false) {
Error(expr->pos, "Illegal to return varying lvalue type from "
"function returning a reference type \"%s\".",
returnType->GetString().c_str());
return;
}
}
ctx->SetDebugPos(pos); ctx->SetDebugPos(pos);
ctx->CurrentLanesReturned(val, doCoherenceCheck); ctx->CurrentLanesReturned(expr, doCoherenceCheck);
} }
@@ -2210,7 +2246,8 @@ void
ReturnStmt::Print(int indent) const { ReturnStmt::Print(int indent) const {
printf("%*c%sReturn Stmt", indent, ' ', doCoherenceCheck ? "Coherent " : ""); printf("%*c%sReturn Stmt", indent, ' ', doCoherenceCheck ? "Coherent " : "");
pos.Print(); pos.Print();
if (val) val->Print(); if (expr)
expr->Print();
else printf("(void)"); else printf("(void)");
printf("\n"); printf("\n");
} }
@@ -2228,6 +2265,9 @@ GotoStmt::GotoStmt(const char *l, SourcePos gotoPos, SourcePos ip)
void void
GotoStmt::EmitCode(FunctionEmitContext *ctx) const { GotoStmt::EmitCode(FunctionEmitContext *ctx) const {
if (!ctx->GetCurrentBasicBlock())
return;
if (ctx->VaryingCFDepth() > 0) { if (ctx->VaryingCFDepth() > 0) {
Error(pos, "\"goto\" statements are only legal under \"uniform\" " Error(pos, "\"goto\" statements are only legal under \"uniform\" "
"control flow."); "control flow.");
@@ -2457,7 +2497,7 @@ lProcessPrintArg(Expr *expr, FunctionEmitContext *ctx, std::string &argTypes) {
else { else {
argTypes.push_back(t); argTypes.push_back(t);
LLVM_TYPE_CONST llvm::Type *llvmExprType = type->LLVMType(g->ctx); llvm::Type *llvmExprType = type->LLVMType(g->ctx);
llvm::Value *ptr = ctx->AllocaInst(llvmExprType, "print_arg"); llvm::Value *ptr = ctx->AllocaInst(llvmExprType, "print_arg");
llvm::Value *val = expr->GetValue(ctx); llvm::Value *val = expr->GetValue(ctx);
if (!val) if (!val)
@@ -2478,6 +2518,9 @@ lProcessPrintArg(Expr *expr, FunctionEmitContext *ctx, std::string &argTypes) {
*/ */
void void
PrintStmt::EmitCode(FunctionEmitContext *ctx) const { PrintStmt::EmitCode(FunctionEmitContext *ctx) const {
if (!ctx->GetCurrentBasicBlock())
return;
ctx->SetDebugPos(pos); ctx->SetDebugPos(pos);
// __do_print takes 5 arguments; we'll get them stored in the args[] array // __do_print takes 5 arguments; we'll get them stored in the args[] array
@@ -2494,7 +2537,7 @@ PrintStmt::EmitCode(FunctionEmitContext *ctx) const {
std::string argTypes; std::string argTypes;
if (values == NULL) { if (values == NULL) {
LLVM_TYPE_CONST llvm::Type *ptrPtrType = llvm::Type *ptrPtrType =
llvm::PointerType::get(LLVMTypes::VoidPointerType, 0); llvm::PointerType::get(LLVMTypes::VoidPointerType, 0);
args[4] = llvm::Constant::getNullValue(ptrPtrType); args[4] = llvm::Constant::getNullValue(ptrPtrType);
} }
@@ -2506,7 +2549,7 @@ PrintStmt::EmitCode(FunctionEmitContext *ctx) const {
int nArgs = elist ? elist->exprs.size() : 1; int nArgs = elist ? elist->exprs.size() : 1;
// Allocate space for the array of pointers to values to be printed // Allocate space for the array of pointers to values to be printed
LLVM_TYPE_CONST llvm::Type *argPtrArrayType = llvm::Type *argPtrArrayType =
llvm::ArrayType::get(LLVMTypes::VoidPointerType, nArgs); llvm::ArrayType::get(LLVMTypes::VoidPointerType, nArgs);
llvm::Value *argPtrArray = ctx->AllocaInst(argPtrArrayType, llvm::Value *argPtrArray = ctx->AllocaInst(argPtrArrayType,
"print_arg_ptrs"); "print_arg_ptrs");
@@ -2583,6 +2626,9 @@ AssertStmt::AssertStmt(const std::string &msg, Expr *e, SourcePos p)
void void
AssertStmt::EmitCode(FunctionEmitContext *ctx) const { AssertStmt::EmitCode(FunctionEmitContext *ctx) const {
if (!ctx->GetCurrentBasicBlock())
return;
if (expr == NULL) if (expr == NULL)
return; return;
const Type *type = expr->GetType(); const Type *type = expr->GetType();
@@ -2658,6 +2704,9 @@ DeleteStmt::DeleteStmt(Expr *e, SourcePos p)
void void
DeleteStmt::EmitCode(FunctionEmitContext *ctx) const { DeleteStmt::EmitCode(FunctionEmitContext *ctx) const {
if (!ctx->GetCurrentBasicBlock())
return;
const Type *exprType; const Type *exprType;
if (expr == NULL || ((exprType = expr->GetType()) == NULL)) { if (expr == NULL || ((exprType = expr->GetType()) == NULL)) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
@@ -2774,7 +2823,7 @@ CreateForeachActiveStmt(Symbol *iterSym, Stmt *stmts, SourcePos pos) {
Expr *maskVecExpr = new SymbolExpr(maskSym, pos); Expr *maskVecExpr = new SymbolExpr(maskSym, pos);
std::vector<Symbol *> mmFuns; std::vector<Symbol *> mmFuns;
m->symbolTable->LookupFunction("__movmsk", &mmFuns); m->symbolTable->LookupFunction("__movmsk", &mmFuns);
Assert(mmFuns.size() == 2); Assert(mmFuns.size() == (g->target.maskBitCount == 32 ? 2 : 1));
FunctionSymbolExpr *movmskFunc = new FunctionSymbolExpr("__movmsk", mmFuns, FunctionSymbolExpr *movmskFunc = new FunctionSymbolExpr("__movmsk", mmFuns,
pos); pos);
ExprList *movmskArgs = new ExprList(maskVecExpr, pos); ExprList *movmskArgs = new ExprList(maskVecExpr, pos);

6
stmt.h
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -265,7 +265,7 @@ public:
statement in the program. */ statement in the program. */
class ReturnStmt : public Stmt { class ReturnStmt : public Stmt {
public: public:
ReturnStmt(Expr *v, bool cc, SourcePos p); ReturnStmt(Expr *e, bool cc, SourcePos p);
void EmitCode(FunctionEmitContext *ctx) const; void EmitCode(FunctionEmitContext *ctx) const;
void Print(int indent) const; void Print(int indent) const;
@@ -273,7 +273,7 @@ public:
Stmt *TypeCheck(); Stmt *TypeCheck();
int EstimateCost() const; int EstimateCost() const;
Expr *val; Expr *expr;
/** This indicates whether the generated code will check to see if no /** This indicates whether the generated code will check to see if no
more program instances are currently running after the return, in more program instances are currently running after the return, in
which case the code can possibly jump to the end of the current which case the code can possibly jump to the end of the current

101
sym.cpp
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -56,12 +56,6 @@ Symbol::Symbol(const std::string &n, SourcePos p, const Type *t,
} }
std::string
Symbol::MangledName() const {
return name + type->Mangle();
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// SymbolTable // SymbolTable
@@ -72,7 +66,7 @@ SymbolTable::SymbolTable() {
SymbolTable::~SymbolTable() { SymbolTable::~SymbolTable() {
// Otherwise we have mismatched push/pop scopes // Otherwise we have mismatched push/pop scopes
Assert(variables.size() == 1 && types.size() == 1); Assert(variables.size() == 1);
PopScope(); PopScope();
} }
@@ -80,7 +74,6 @@ SymbolTable::~SymbolTable() {
void void
SymbolTable::PushScope() { SymbolTable::PushScope() {
variables.push_back(new SymbolMapType); variables.push_back(new SymbolMapType);
types.push_back(new TypeMapType);
} }
@@ -89,10 +82,6 @@ SymbolTable::PopScope() {
Assert(variables.size() > 1); Assert(variables.size() > 1);
delete variables.back(); delete variables.back();
variables.pop_back(); variables.pop_back();
Assert(types.size() > 1);
delete types.back();
types.pop_back();
} }
@@ -192,26 +181,17 @@ SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
bool bool
SymbolTable::AddType(const char *name, const Type *type, SourcePos pos) { SymbolTable::AddType(const char *name, const Type *type, SourcePos pos) {
// Like AddVariable(), we go backwards through the type maps, working const Type *t = LookupType(name);
// from innermost scope to outermost. if (t != NULL && dynamic_cast<const UndefinedStructType *>(t) == NULL) {
for (int i = types.size()-1; i >= 0; --i) { // If we have a previous declaration of anything other than an
TypeMapType &sm = *(types[i]); // UndefinedStructType with this struct name, issue an error. If
if (sm.find(name) != sm.end()) { // we have an UndefinedStructType, then we'll fall through to the
if (i == (int)types.size() - 1) { // code below that adds the definition to the type map.
Error(pos, "Ignoring redefinition of type \"%s\".", name); Error(pos, "Ignoring redefinition of type \"%s\".", name);
return false; return false;
}
else {
Warning(pos, "Type \"%s\" shadows type declared in outer scope.", name);
TypeMapType &sm = *(types.back());
sm[name] = type;
return true;
}
}
} }
TypeMapType &sm = *(types.back()); types[name] = type;
sm[name] = type;
return true; return true;
} }
@@ -219,11 +199,9 @@ SymbolTable::AddType(const char *name, const Type *type, SourcePos pos) {
const Type * const Type *
SymbolTable::LookupType(const char *name) const { SymbolTable::LookupType(const char *name) const {
// Again, search through the type maps backward to get scoping right. // Again, search through the type maps backward to get scoping right.
for (int i = types.size()-1; i >= 0; --i) { TypeMapType::const_iterator iter = types.find(name);
TypeMapType &sm = *(types[i]); if (iter != types.end())
if (sm.find(name) != sm.end()) return iter->second;
return sm[name];
}
return NULL; return NULL;
} }
@@ -288,21 +266,19 @@ SymbolTable::closestTypeMatch(const char *str, bool structsVsEnums) const {
const int maxDelta = 2; const int maxDelta = 2;
std::vector<std::string> matches[maxDelta+1]; std::vector<std::string> matches[maxDelta+1];
for (unsigned int i = 0; i < types.size(); ++i) { TypeMapType::const_iterator iter;
TypeMapType::const_iterator iter; for (iter = types.begin(); iter != types.end(); ++iter) {
for (iter = types[i]->begin(); iter != types[i]->end(); ++iter) { // Skip over either StructTypes or EnumTypes, depending on the
// Skip over either StructTypes or EnumTypes, depending on the // value of the structsVsEnums parameter
// value of the structsVsEnums parameter bool isEnum = (dynamic_cast<const EnumType *>(iter->second) != NULL);
bool isEnum = (dynamic_cast<const EnumType *>(iter->second) != NULL); if (isEnum && structsVsEnums)
if (isEnum && structsVsEnums) continue;
continue; else if (!isEnum && !structsVsEnums)
else if (!isEnum && !structsVsEnums) continue;
continue;
int dist = StringEditDistance(str, iter->first, maxDelta+1); int dist = StringEditDistance(str, iter->first, maxDelta+1);
if (dist <= maxDelta) if (dist <= maxDelta)
matches[dist].push_back(iter->first); matches[dist].push_back(iter->first);
}
} }
for (int i = 0; i <= maxDelta; ++i) { for (int i = 0; i <= maxDelta; ++i) {
@@ -342,16 +318,12 @@ SymbolTable::Print() {
depth = 0; depth = 0;
fprintf(stderr, "Named types:\n---------------\n"); fprintf(stderr, "Named types:\n---------------\n");
for (unsigned int i = 0; i < types.size(); ++i) { TypeMapType::iterator siter = types.begin();
TypeMapType &sm = *types[i]; while (siter != types.end()) {
TypeMapType::iterator siter = sm.begin(); fprintf(stderr, "%*c", depth, ' ');
while (siter != sm.end()) { fprintf(stderr, "%s -> %s\n", siter->first.c_str(),
fprintf(stderr, "%*c", depth, ' '); siter->second->GetString().c_str());
fprintf(stderr, "%s -> %s\n", siter->first.c_str(), ++siter;
siter->second->GetString().c_str());
++siter;
}
depth += 4;
} }
} }
@@ -382,14 +354,11 @@ SymbolTable::RandomSymbol() {
const Type * const Type *
SymbolTable::RandomType() { SymbolTable::RandomType() {
int v = ispcRand() % types.size(); int count = types.size();
if (types[v]->size() == 0) TypeMapType::iterator iter = types.begin();
return NULL;
int count = ispcRand() % types[v]->size();
TypeMapType::iterator iter = types[v]->begin();
while (count-- > 0) { while (count-- > 0) {
++iter; ++iter;
Assert(iter != types[v]->end()); Assert(iter != types.end());
} }
return iter->second; return iter->second;
} }

20
sym.h
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -67,15 +67,8 @@ public:
Symbol(const std::string &name, SourcePos pos, const Type *t = NULL, Symbol(const std::string &name, SourcePos pos, const Type *t = NULL,
StorageClass sc = SC_NONE); StorageClass sc = SC_NONE);
/** This method should only be called for function symbols; for them,
it returns a mangled version of the function name with the argument
types encoded into the returned name. This is used to generate
unique symbols in object files for overloaded functions.
*/
std::string MangledName() const;
SourcePos pos; /*!< Source file position where the symbol was defined */ SourcePos pos; /*!< Source file position where the symbol was defined */
const std::string name; /*!< Symbol's name */ std::string name; /*!< Symbol's name */
llvm::Value *storagePtr; /*!< For symbols with storage associated with llvm::Value *storagePtr; /*!< For symbols with storage associated with
them (i.e. variables but not functions), them (i.e. variables but not functions),
this member stores a pointer to its this member stores a pointer to its
@@ -208,6 +201,9 @@ public:
/** Adds the named type to the symbol table. This is used for both /** Adds the named type to the symbol table. This is used for both
struct definitions (where <tt>struct Foo</tt> causes type \c Foo to struct definitions (where <tt>struct Foo</tt> causes type \c Foo to
be added to the symbol table) as well as for <tt>typedef</tt>s. be added to the symbol table) as well as for <tt>typedef</tt>s.
For structs with forward declarations ("struct Foo;") and are thus
UndefinedStructTypes, this method replaces these with an actual
struct definition if one is provided.
@param name Name of the type to be added @param name Name of the type to be added
@param type Type that \c name represents @param type Type that \c name represents
@@ -272,12 +268,10 @@ private:
typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType; typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType;
FunctionMapType functions; FunctionMapType functions;
/** Type definitions can also be scoped. A new \c TypeMapType /** Type definitions can't currently be scoped.
is added to the back of the \c types \c vector each time a new scope
is entered. (And it's removed when the scope exits).
*/ */
typedef std::map<std::string, const Type *> TypeMapType; typedef std::map<std::string, const Type *> TypeMapType;
std::vector<TypeMapType *> types; TypeMapType types;
}; };

View File

@@ -0,0 +1,15 @@
export uniform int width() { return programCount; }
float foo(float &) { return 1; }
float bar(uniform float []) { return 2; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
float x = 0;
RET[programIndex] = foo(x) + bar(aFOO);
}
export void result(uniform float RET[]) {
RET[programIndex] = 3;
}

View File

@@ -0,0 +1,12 @@
export uniform int width() { return programCount; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
float a = 1. / aFOO[programIndex];
RET[programIndex] = max(0, a);
}
export void result(uniform float RET[]) {
RET[programIndex] = 1. / (1+programIndex);
}

View File

@@ -0,0 +1,14 @@
export uniform int width() { return programCount; }
float foo(float &a) { return 1; }
float foo(const float &a) { return 2; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
float x = 0;
RET[programIndex] = foo(x);
}
export void result(uniform float RET[]) {
RET[programIndex] = 1;
}

View File

@@ -0,0 +1,28 @@
export uniform int width() { return programCount; }
typedef float (*func)();
float foo();
float bar();
struct X { func f, g; };
static uniform X x = { foo, &bar };
export void f_f(uniform float RET[], uniform float aFOO[]) {
RET[programIndex] = x.f() + x.g();
}
export void result(uniform float RET[]) {
RET[programIndex] = programIndex;
}
float foo() {
return 2 * programIndex;
}
float bar() {
return -programIndex;
}

View File

@@ -15,7 +15,7 @@ export void f_f(uniform float RET[], uniform float aFOO[]) {
float a = aFOO[programIndex]; float a = aFOO[programIndex];
float b = aFOO[0]-1; float b = aFOO[0]-1;
uniform FuncType func = foo; uniform FuncType func = foo;
RET[programIndex] = (func ? func : bar)(a, b); RET[programIndex] = (func ? func : &bar)(a, b);
} }
export void result(uniform float RET[]) { export void result(uniform float RET[]) {

View File

@@ -14,7 +14,7 @@ static float bar(float a, float b) {
export void f_f(uniform float RET[], uniform float aFOO[]) { export void f_f(uniform float RET[], uniform float aFOO[]) {
float a = aFOO[programIndex]; float a = aFOO[programIndex];
float b = aFOO[0]-1; float b = aFOO[0]-1;
FuncType func = foo; FuncType func = &foo;
if (a == 2) if (a == 2)
func = NULL; func = NULL;
if (func != NULL) if (func != NULL)

View File

@@ -16,7 +16,7 @@ export void f_f(uniform float RET[], uniform float aFOO[]) {
float b = aFOO[0]-1; float b = aFOO[0]-1;
FuncType func = NULL; FuncType func = NULL;
if (a == 2) if (a == 2)
func = foo; func = &foo;
if (!func) if (!func)
RET[programIndex] = -1; RET[programIndex] = -1;
else else

View File

@@ -14,7 +14,7 @@ static float bar(float a, float b) {
export void f_f(uniform float RET[], uniform float aFOO[]) { export void f_f(uniform float RET[], uniform float aFOO[]) {
float a = aFOO[programIndex]; float a = aFOO[programIndex];
float b = aFOO[0]-1; float b = aFOO[0]-1;
uniform FuncType func = bar; uniform FuncType func = &bar;
if (aFOO[0] == 1) if (aFOO[0] == 1)
func = foo; func = foo;
RET[programIndex] = func(a, b); RET[programIndex] = func(a, b);

View File

@@ -0,0 +1,14 @@
export uniform int width() { return programCount; }
extern int foo;
int foo = 1;
export void f_f(uniform float RET[], uniform float aFOO[]) {
RET[programIndex] = foo;
}
export void result(uniform float RET[]) {
RET[programIndex] = 1;
}

19
tests/intptr.ispc Normal file
View File

@@ -0,0 +1,19 @@
export uniform int width() { return programCount; }
export void f_v(uniform float RET[]) {
RET[programIndex] = sizeof(uniform intptr_t);
}
export void result(uniform float RET[]) {
RET[programIndex] =
#if (ISPC_POINTER_SIZE==32)
4
#elif (ISPC_POINTER_SIZE==64)
8
#else
#error Unknown pointer size
#endif
;
}

View File

@@ -0,0 +1,18 @@
export uniform int width() { return programCount; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
uniform int x[2][10];
for (uniform int i = 0; i < 2; ++i) {
for (uniform int j = 0; j < 10; ++j) {
x[i][j] = 10*i+j;
}
}
uniform int (* varying y)[10] = x;
RET[programIndex] = y[1][programIndex % 5];
}
export void result(uniform float RET[]) {
RET[programIndex] = 10+ (programIndex % 5);
}

View File

@@ -0,0 +1,12 @@
export uniform int width() { return programCount; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
uniform float * uniform ptr = aFOO;
RET[programIndex] = *(ptr + programIndex) - 1;
}
export void result(uniform float RET[]) {
RET[programIndex] = programIndex;
}

View File

@@ -0,0 +1,14 @@
export uniform int width() { return programCount; }
bool bar(float * x) {
return (x != 0);
}
export void f_f(uniform float RET[], uniform float aFOO[]) {
RET[programIndex] = bar(NULL);
}
export void result(uniform float RET[]) {
RET[programIndex] = 0;
}

View File

@@ -0,0 +1,14 @@
export uniform int width() { return programCount; }
int func(const int &a) { return a+1; }
int bar() { return 0; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
RET[programIndex] = func(bar());
}
export void result(uniform float RET[]) {
RET[programIndex] = 1;
}

View File

@@ -0,0 +1,16 @@
export uniform int width() { return programCount; }
float foo(uniform float<4> &vec) {
return vec[programIndex & 3];
}
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
uniform float<4> vec = { b, -1, 2*b, -b };
RET[programIndex] = foo(vec);
}
export void result(uniform float RET[]) {
uniform float a[4] = { 5, -1, 10, -5 };
RET[programIndex] = a[programIndex & 3];
}

View File

@@ -1,25 +0,0 @@
export uniform int width() { return programCount; }
uniform int * uniform ptr;
float foo(uniform float a[]) {
int index = (programIndex & 1) * 10000;
if (a[programIndex] < 10000 && a[index] == 1)
return 1;
else
return 1234;
}
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
float a = aFOO[programIndex];
float a0 = aFOO[0], a1 = aFOO[1];
if ((programIndex & 1) == 0)
RET[programIndex] = foo(aFOO);
else
RET[programIndex] = 2;
}
export void result(uniform float RET[]) {
RET[programIndex] = (programIndex & 1) ? 2 : 1;
}

View File

@@ -0,0 +1,36 @@
export uniform int width() { return programCount; }
struct Foo;
void bing(Foo * uniform);
struct Foo {
int i;
varying float f;
Foo * uniform next;
};
void bar(Foo * uniform f) {
bing(f);
}
export void f_f(uniform float RET[], uniform float aFOO[]) {
uniform Foo fa, fb;
fa.next = &fb;
fb.f = aFOO[programIndex];
fb.i = 100;
bar(&fa);
RET[programIndex] = fb.f;
}
void bing(Foo * uniform f) {
f = f->next;
f->f *= 2;
}
export void result(uniform float RET[]) {
RET[programIndex] = 2 + 2*programIndex;
}

View File

@@ -0,0 +1,33 @@
export uniform int width() { return programCount; }
struct Foo;
void bing(varying Foo * uniform);
struct Foo {
float f;
int i;
};
void bar(varying Foo * uniform f) {
bing(f);
}
export void f_f(uniform float RET[], uniform float aFOO[]) {
Foo f;
f.f = aFOO[programIndex];
f.i = programIndex;
bar(&f);
RET[programIndex] = f.f;
}
void bing(varying Foo * uniform f) {
f->f *= 2;
}
export void result(uniform float RET[]) {
RET[programIndex] = 2 + 2*programIndex;
}

View File

@@ -0,0 +1,24 @@
struct Foo {
float x;
float a[0];
};
export uniform int width() { return programCount; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
uniform int nFloats = 3+programCount;
varying Foo * uniform ptr = (varying Foo * uniform)(uniform new varying int32[nFloats]);
memset(ptr, 0, nFloats*sizeof(int32));
for (uniform int i = 0; i < nFloats-1; ++i)
ptr->a[i] = i;
ptr->x = aFOO[programIndex];
RET[programIndex] = ptr->a[1+programIndex];
}
export void result(uniform float RET[]) {
RET[programIndex] = 1 + programIndex;
}

View File

@@ -0,0 +1,17 @@
export uniform int width() { return programCount; }
float add(float a, float b, uniform float * uniform result) {
result[programIndex] = a+b;
return a+b;
}
export void f_f(uniform float RET[], uniform float aFOO[]) {
float a = aFOO[programIndex];
float b = 0.; b = a;
(void)add(a, b, RET);
}
export void result(uniform float RET[]) {
RET[programIndex] = 2 + 2*programIndex;
}

View File

@@ -0,0 +1,17 @@
export uniform int width() { return programCount; }
uniform float add(float a, float b, uniform float * uniform result) {
result[programIndex] = a+b;
return 1;
}
export void f_f(uniform float RET[], uniform float aFOO[]) {
float a = aFOO[programIndex];
float b = 0.; b = a;
(void)add(a, b, RET);
}
export void result(uniform float RET[]) {
RET[programIndex] = 2 + 2*programIndex;
}

View File

@@ -0,0 +1,5 @@
// Illegal to take address of non-lvalue or function
void foo() {
int *ptr = &(1+1);
}

View File

@@ -1,4 +1,4 @@
// Dereference operator "->" can't be applied to non-pointer type "varying struct Foo" // Member operator "->" can't be applied to non-pointer type "varying struct Foo"
struct Foo { int x; }; struct Foo { int x; };

View File

@@ -1,4 +1,4 @@
// Unable to find matching overload for call to function // Unable to find any matching overload for call to function
void foo(int x); void foo(int x);

View File

@@ -1,4 +1,4 @@
// Unable to find matching overload for call to function // Unable to find any matching overload for call to function
void foo(int x); void foo(int x);

View File

@@ -1,4 +1,4 @@
// Unable to find matching overload for call to function // Unable to find any matching overload for call to function
void foo(); void foo();

View File

@@ -0,0 +1,4 @@
// Definition of variable "foo" conflicts with definition at
extern int foo;
float foo;

View File

@@ -0,0 +1,4 @@
// Definition of variable "foo" conflicts with definition at
extern int foo;
extern float foo;

View File

@@ -0,0 +1,4 @@
// Definition of variable "foo" conflicts with definition at
int foo;
float foo;

View File

@@ -0,0 +1,4 @@
// Redefinition of variable "foo" is illegal
int foo;
int foo;

View File

@@ -1,4 +1,4 @@
// Can't convert between incompatible pointer types // Can't convert from pointer type "void * varying" to incompatible pointer type "uniform int32 * varying" for return statement
int *foo(void *p) { int *foo(void *p) {
return p; return p;

View File

@@ -0,0 +1,6 @@
// Initializer for reference-type variable "x" must have an lvalue type
float &func(uniform float a[], int i, float f) {
float &x = 1.; // a[i];
}

View File

@@ -0,0 +1,6 @@
// Initializer for reference-type variable "x" must have a uniform lvalue type
float &func(uniform float a[], int i, float f) {
float &x = a[i];
}

View File

@@ -0,0 +1,6 @@
// Initializer for reference-type variable "x" must have a uniform lvalue type
float &func(uniform int a[], int i, float f) {
float &x = a[i];
}

View File

@@ -0,0 +1,5 @@
// Illegal to return non-lvalue from function returning reference type
float &func(uniform float a[], int i, float f) {
return 1.f;
}

View File

@@ -0,0 +1,5 @@
// Illegal to return varying lvalue type from function returning a reference type
float &func(uniform float a[], int i, float f) {
return a[i];
}

View File

@@ -0,0 +1,5 @@
// Member operator "." can't be applied to declared but not defined struct type
struct Foo;
int bar(Foo & foo) { return foo.x; }

View File

@@ -0,0 +1,5 @@
// Member operator "->" can't be applied to declared but not defined struct type
struct Foo;
int bar(Foo * uniform foo) { return foo->x; }

View File

@@ -1,4 +1,4 @@
// Unsized arrays aren't allowed in struct definitions // Unsized arrays aren't allowed except for the last member in a struct definition.
struct Foo { struct Foo {
float a[]; float a[];

580
type.cpp
View File

@@ -42,6 +42,7 @@
#include "module.h" #include "module.h"
#include <stdio.h> #include <stdio.h>
#include <map>
#include <llvm/Value.h> #include <llvm/Value.h>
#include <llvm/Module.h> #include <llvm/Module.h>
#include <llvm/Analysis/DIBuilder.h> #include <llvm/Analysis/DIBuilder.h>
@@ -59,7 +60,7 @@ static bool
lShouldPrintName(const std::string &name) { lShouldPrintName(const std::string &name) {
if (name.size() == 0) if (name.size() == 0)
return false; return false;
else if (name[0] != '_') else if (name[0] != '_' && name[0] != '$')
return true; return true;
else else
return (name.size() == 1) || (name[1] != '_'); return (name.size() == 1) || (name[1] != '_');
@@ -81,11 +82,7 @@ lCreateDIArray(llvm::DIType eltType, int count) {
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(lowerBound, upperBound); llvm::Value *sub = m->diBuilder->getOrCreateSubrange(lowerBound, upperBound);
std::vector<llvm::Value *> subs; std::vector<llvm::Value *> subs;
subs.push_back(sub); subs.push_back(sub);
#ifdef LLVM_2_9
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(&subs[0], subs.size());
#else
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(subs); llvm::DIArray subArray = m->diBuilder->getOrCreateArray(subs);
#endif
uint64_t size = eltType.getSizeInBits() * count; uint64_t size = eltType.getSizeInBits() * count;
uint64_t align = eltType.getAlignInBits(); uint64_t align = eltType.getAlignInBits();
@@ -418,7 +415,7 @@ AtomicType::GetCDeclaration(const std::string &name) const {
} }
LLVM_TYPE_CONST llvm::Type * llvm::Type *
AtomicType::LLVMType(llvm::LLVMContext *ctx) const { AtomicType::LLVMType(llvm::LLVMContext *ctx) const {
Assert(variability.type != Variability::Unbound); Assert(variability.type != Variability::Unbound);
bool isUniform = (variability == Variability::Uniform); bool isUniform = (variability == Variability::Uniform);
@@ -518,12 +515,7 @@ AtomicType::GetDIType(llvm::DIDescriptor scope) const {
else if (variability == Variability::Varying) { else if (variability == Variability::Varying) {
llvm::DIType unifType = GetAsUniformType()->GetDIType(scope); llvm::DIType unifType = GetAsUniformType()->GetDIType(scope);
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target.vectorWidth-1); llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target.vectorWidth-1);
#ifdef LLVM_2_9
llvm::Value *suba[] = { sub };
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(suba, 1);
#else
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub); llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub);
#endif // LLVM_2_9
uint64_t size = unifType.getSizeInBits() * g->target.vectorWidth; uint64_t size = unifType.getSizeInBits() * g->target.vectorWidth;
uint64_t align = unifType.getAlignInBits() * g->target.vectorWidth; uint64_t align = unifType.getAlignInBits() * g->target.vectorWidth;
return m->diBuilder->createVectorType(size, align, unifType, subArray); return m->diBuilder->createVectorType(size, align, unifType, subArray);
@@ -734,7 +726,7 @@ EnumType::GetCDeclaration(const std::string &varName) const {
} }
LLVM_TYPE_CONST llvm::Type * llvm::Type *
EnumType::LLVMType(llvm::LLVMContext *ctx) const { EnumType::LLVMType(llvm::LLVMContext *ctx) const {
Assert(variability != Variability::Unbound); Assert(variability != Variability::Unbound);
@@ -767,14 +759,8 @@ EnumType::GetDIType(llvm::DIDescriptor scope) const {
m->diBuilder->createEnumerator(enumerators[i]->name, enumeratorValue); m->diBuilder->createEnumerator(enumerators[i]->name, enumeratorValue);
enumeratorDescriptors.push_back(descriptor); enumeratorDescriptors.push_back(descriptor);
} }
#ifdef LLVM_2_9
llvm::DIArray elementArray =
m->diBuilder->getOrCreateArray(&enumeratorDescriptors[0],
enumeratorDescriptors.size());
#else
llvm::DIArray elementArray = llvm::DIArray elementArray =
m->diBuilder->getOrCreateArray(enumeratorDescriptors); m->diBuilder->getOrCreateArray(enumeratorDescriptors);
#endif
llvm::DIFile diFile = pos.GetDIFile(); llvm::DIFile diFile = pos.GetDIFile();
llvm::DIType diType = llvm::DIType diType =
@@ -789,12 +775,7 @@ EnumType::GetDIType(llvm::DIDescriptor scope) const {
return diType; return diType;
case Variability::Varying: { case Variability::Varying: {
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target.vectorWidth-1); llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target.vectorWidth-1);
#ifdef LLVM_2_9
llvm::Value *suba[] = { sub };
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(suba, 1);
#else
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub); llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub);
#endif // !LLVM_2_9
uint64_t size = diType.getSizeInBits() * g->target.vectorWidth; uint64_t size = diType.getSizeInBits() * g->target.vectorWidth;
uint64_t align = diType.getAlignInBits() * g->target.vectorWidth; uint64_t align = diType.getAlignInBits() * g->target.vectorWidth;
return m->diBuilder->createVectorType(size, align, diType, subArray); return m->diBuilder->createVectorType(size, align, diType, subArray);
@@ -966,42 +947,6 @@ PointerType::GetAsFrozenSlice() const {
} }
/** Returns a structure corresponding to the pointer representation for
slice pointers; the first member of this structure is a uniform or
varying pointer, and the second element is either a uniform or varying
int32.
*/
const StructType *
PointerType::GetSliceStructType() const {
Assert(isSlice == true);
std::vector<const Type *> eltTypes;
eltTypes.push_back(GetAsNonSlice());
switch (variability.type) {
case Variability::Uniform:
eltTypes.push_back(AtomicType::UniformInt32);
break;
case Variability::Varying:
eltTypes.push_back(AtomicType::VaryingInt32);
break;
default:
FATAL("Unexpected variability in PointerType::GetSliceStructType()");
}
std::vector<std::string> eltNames;
std::vector<SourcePos> eltPos;
eltNames.push_back("ptr");
eltNames.push_back("offset");
eltPos.push_back(SourcePos());
eltPos.push_back(SourcePos());
return new StructType("__ptr_slice_tmp", eltTypes, eltNames, eltPos, isConst,
Variability::Uniform, SourcePos());
}
const PointerType * const PointerType *
PointerType::ResolveUnboundVariability(Variability v) const { PointerType::ResolveUnboundVariability(Variability v) const {
if (baseType == NULL) { if (baseType == NULL) {
@@ -1103,22 +1048,41 @@ PointerType::GetCDeclaration(const std::string &name) const {
} }
LLVM_TYPE_CONST llvm::Type * llvm::Type *
PointerType::LLVMType(llvm::LLVMContext *ctx) const { PointerType::LLVMType(llvm::LLVMContext *ctx) const {
if (baseType == NULL) { if (baseType == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
} }
if (isSlice) if (isSlice) {
// Slice pointers are represented as a structure with a pointer and llvm::Type *types[2];
// an integer offset; the corresponding ispc type is returned by types[0] = GetAsNonSlice()->LLVMType(ctx);
// GetSliceStructType().
return GetSliceStructType()->LLVMType(ctx); switch (variability.type) {
case Variability::Uniform:
types[1] = LLVMTypes::Int32Type;
break;
case Variability::Varying:
types[1] = LLVMTypes::Int32VectorType;
break;
case Variability::SOA:
types[1] = llvm::ArrayType::get(LLVMTypes::Int32Type,
variability.soaWidth);
break;
default:
FATAL("unexpected variability for slice pointer in "
"PointerType::LLVMType");
}
llvm::ArrayRef<llvm::Type *> typesArrayRef =
llvm::ArrayRef<llvm::Type *>(types, 2);
return llvm::StructType::get(*g->ctx, typesArrayRef);
}
switch (variability.type) { switch (variability.type) {
case Variability::Uniform: { case Variability::Uniform: {
LLVM_TYPE_CONST llvm::Type *ptype = NULL; llvm::Type *ptype = NULL;
const FunctionType *ftype = dynamic_cast<const FunctionType *>(baseType); const FunctionType *ftype = dynamic_cast<const FunctionType *>(baseType);
if (ftype != NULL) if (ftype != NULL)
// Get the type of the function variant that takes the mask as the // Get the type of the function variant that takes the mask as the
@@ -1157,13 +1121,15 @@ PointerType::GetDIType(llvm::DIDescriptor scope) const {
llvm::DIType diTargetType = baseType->GetDIType(scope); llvm::DIType diTargetType = baseType->GetDIType(scope);
int bitsSize = g->target.is32Bit ? 32 : 64; int bitsSize = g->target.is32Bit ? 32 : 64;
int ptrAlignBits = bitsSize;
switch (variability.type) { switch (variability.type) {
case Variability::Uniform: case Variability::Uniform:
return m->diBuilder->createPointerType(diTargetType, bitsSize); return m->diBuilder->createPointerType(diTargetType, bitsSize,
ptrAlignBits);
case Variability::Varying: { case Variability::Varying: {
// emit them as an array of pointers // emit them as an array of pointers
llvm::DIType eltType = m->diBuilder->createPointerType(diTargetType, llvm::DIType eltType = m->diBuilder->createPointerType(diTargetType,
bitsSize); bitsSize, ptrAlignBits);
return lCreateDIArray(eltType, g->target.vectorWidth); return lCreateDIArray(eltType, g->target.vectorWidth);
} }
case Variability::SOA: { case Variability::SOA: {
@@ -1196,14 +1162,14 @@ ArrayType::ArrayType(const Type *c, int a)
} }
LLVM_TYPE_CONST llvm::ArrayType * llvm::ArrayType *
ArrayType::LLVMType(llvm::LLVMContext *ctx) const { ArrayType::LLVMType(llvm::LLVMContext *ctx) const {
if (child == NULL) { if (child == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
} }
LLVM_TYPE_CONST llvm::Type *ct = child->LLVMType(ctx); llvm::Type *ct = child->LLVMType(ctx);
if (ct == NULL) { if (ct == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
@@ -1648,14 +1614,14 @@ VectorType::GetElementType() const {
} }
LLVM_TYPE_CONST llvm::Type * llvm::Type *
VectorType::LLVMType(llvm::LLVMContext *ctx) const { VectorType::LLVMType(llvm::LLVMContext *ctx) const {
if (base == NULL) { if (base == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
} }
LLVM_TYPE_CONST llvm::Type *bt = base->LLVMType(ctx); llvm::Type *bt = base->LLVMType(ctx);
if (!bt) if (!bt)
return NULL; return NULL;
@@ -1684,12 +1650,7 @@ llvm::DIType
VectorType::GetDIType(llvm::DIDescriptor scope) const { VectorType::GetDIType(llvm::DIDescriptor scope) const {
llvm::DIType eltType = base->GetDIType(scope); llvm::DIType eltType = base->GetDIType(scope);
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, numElements-1); llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, numElements-1);
#ifdef LLVM_2_9
llvm::Value *subs[1] = { sub };
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(subs, 1);
#else
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub); llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub);
#endif
uint64_t sizeBits = eltType.getSizeInBits() * numElements; uint64_t sizeBits = eltType.getSizeInBits() * numElements;
@@ -1744,12 +1705,103 @@ VectorType::getVectorMemoryCount() const {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// StructType // StructType
// We maintain a map from struct names to LLVM struct types so that we can
// uniquely get the llvm::StructType * for a given ispc struct type. Note
// that we need to mangle the name a bit so that we can e.g. differentiate
// between the uniform and varying variants of a given struct type. This
// is handled by lMangleStructName() below.
static std::map<std::string, llvm::StructType *> lStructTypeMap;
/** Using a struct's name, its variability, and the vector width for the
current compilation target, this function generates a string that
encodes that full structure type, for use in the lStructTypeMap. Note
that the vector width is needed in order to differentiate between
'varying' structs with different compilation targets, which have
different memory layouts...
*/
static std::string
lMangleStructName(const std::string &name, Variability variability) {
char buf[32];
std::string n;
// Encode vector width
sprintf(buf, "v%d", g->target.vectorWidth);
n += buf;
// Variability
switch (variability.type) {
case Variability::Uniform:
n += "_uniform_";
break;
case Variability::Varying:
n += "_varying_";
break;
case Variability::SOA:
sprintf(buf, "_soa%d_", variability.soaWidth);
n += buf;
break;
default:
FATAL("Unexpected varaibility in lMangleStructName()");
}
// And stuff the name at the end....
n += name;
return n;
}
StructType::StructType(const std::string &n, const std::vector<const Type *> &elts, StructType::StructType(const std::string &n, const std::vector<const Type *> &elts,
const std::vector<std::string> &en, const std::vector<std::string> &en,
const std::vector<SourcePos> &ep, const std::vector<SourcePos> &ep,
bool ic, Variability v, SourcePos p) bool ic, Variability v, SourcePos p)
: name(n), elementTypes(elts), elementNames(en), elementPositions(ep), : name(n), elementTypes(elts), elementNames(en), elementPositions(ep),
variability(v), isConst(ic), pos(p) { variability(v), isConst(ic), pos(p) {
if (variability != Variability::Unbound) {
// For structs with non-unbound variability, we'll create the
// correspoing LLVM struct type now, if one hasn't been made
// already.
// Create a unique anonymous struct name if we have an anonymous
// struct (name == ""), or if we are creating a derived type from
// an anonymous struct (e.g. the varying variant--name == '$').
if (name == "" || name[0] == '$') {
char buf[16];
static int count = 0;
sprintf(buf, "$anon%d", count);
name = buf;
++count;
}
// If a non-opaque LLVM struct for this type has already been
// created, we're done. For an opaque struct type, we'll override
// the old definition now that we have a full definition.
std::string mname = lMangleStructName(name, variability);
if (lStructTypeMap.find(mname) != lStructTypeMap.end() &&
lStructTypeMap[mname]->isOpaque() == false)
return;
// Actually make the LLVM struct
std::vector<llvm::Type *> elementTypes;
for (int i = 0; i < GetElementCount(); ++i) {
const Type *type = GetElementType(i);
if (type == NULL) {
Assert(m->errorCount > 0);
return;
}
elementTypes.push_back(type->LLVMType(g->ctx));
}
if (lStructTypeMap.find(mname) == lStructTypeMap.end()) {
// New struct definition
llvm::StructType *st =
llvm::StructType::create(*g->ctx, elementTypes, mname);
lStructTypeMap[mname] = st;
}
else {
// Definition for what was before just a declaration
lStructTypeMap[mname]->setBody(elementTypes);
}
}
} }
@@ -1877,31 +1929,34 @@ StructType::GetAsNonConstType() const {
std::string std::string
StructType::GetString() const { StructType::GetString() const {
std::string ret; std::string ret;
if (isConst) ret += "const "; if (isConst)
ret += "const ";
ret += variability.GetString(); ret += variability.GetString();
ret += " "; ret += " ";
// Don't print the entire struct declaration, just print the struct's name. if (name[0] == '$') {
// @todo Do we need a separate method that prints the declaration? // Print the whole anonymous struct declaration
#if 0 ret += std::string("struct { ") + name;
ret += std::string("struct { ") + name; for (unsigned int i = 0; i < elementTypes.size(); ++i) {
for (unsigned int i = 0; i < elementTypes.size(); ++i) { ret += elementTypes[i]->GetString();
ret += elementTypes[i]->GetString(); ret += " ";
ret += " "; ret += elementNames[i];
ret += elementNames[i]; ret += "; ";
ret += "; "; }
ret += "}";
} }
ret += "}"; else {
#else ret += "struct ";
ret += "struct "; ret += name;
ret += name; }
#endif
return ret; return ret;
} }
std::string /** Mangle a struct name for use in function name mangling. */
StructType::Mangle() const { static std::string
lMangleStruct(Variability variability, bool isConst, const std::string &name) {
Assert(variability != Variability::Unbound); Assert(variability != Variability::Unbound);
std::string ret; std::string ret;
@@ -1910,12 +1965,15 @@ StructType::Mangle() const {
ret += "_c_"; ret += "_c_";
ret += variability.MangleString(); ret += variability.MangleString();
ret += name + std::string("]<"); ret += name + std::string("]");
for (unsigned int i = 0; i < elementTypes.size(); ++i)
ret += GetElementType(i)->Mangle();
ret += ">";
return ret; return ret;
} }
std::string
StructType::Mangle() const {
return lMangleStruct(variability, isConst, name);
}
std::string std::string
@@ -1923,31 +1981,31 @@ StructType::GetCDeclaration(const std::string &n) const {
std::string ret; std::string ret;
if (isConst) ret += "const "; if (isConst) ret += "const ";
ret += std::string("struct ") + name; ret += std::string("struct ") + name;
if (lShouldPrintName(n)) if (lShouldPrintName(n)) {
ret += std::string(" ") + n; ret += std::string(" ") + n;
if (variability.soaWidth > 0) { if (variability.soaWidth > 0) {
char buf[32]; char buf[32];
// This has to match the naming scheme used in lEmitStructDecls() // This has to match the naming scheme used in lEmitStructDecls()
// in module.cpp // in module.cpp
sprintf(buf, "_SOA%d", variability.soaWidth); sprintf(buf, "_SOA%d", variability.soaWidth);
ret += buf; ret += buf;
}
} }
return ret; return ret;
} }
LLVM_TYPE_CONST llvm::Type * llvm::Type *
StructType::LLVMType(llvm::LLVMContext *ctx) const { StructType::LLVMType(llvm::LLVMContext *ctx) const {
std::vector<LLVM_TYPE_CONST llvm::Type *> llvmTypes; Assert(variability != Variability::Unbound);
for (int i = 0; i < GetElementCount(); ++i) { std::string mname = lMangleStructName(name, variability);
const Type *type = GetElementType(i); if (lStructTypeMap.find(mname) == lStructTypeMap.end()) {
if (type == NULL) Assert(m->errorCount > 0);
return NULL; return NULL;
llvmTypes.push_back(type->LLVMType(ctx));
} }
return llvm::StructType::get(*ctx, llvmTypes); return lStructTypeMap[mname];
} }
@@ -1963,6 +2021,7 @@ StructType::GetDIType(llvm::DIDescriptor scope) const {
llvm::DIType eltType = GetElementType(i)->GetDIType(scope); llvm::DIType eltType = GetElementType(i)->GetDIType(scope);
uint64_t eltAlign = eltType.getAlignInBits(); uint64_t eltAlign = eltType.getAlignInBits();
uint64_t eltSize = eltType.getSizeInBits(); uint64_t eltSize = eltType.getSizeInBits();
Assert(eltAlign != 0);
// The alignment for the entire structure is the maximum of the // The alignment for the entire structure is the maximum of the
// required alignments of its elements // required alignments of its elements
@@ -1976,17 +2035,10 @@ StructType::GetDIType(llvm::DIDescriptor scope) const {
llvm::DIFile diFile = elementPositions[i].GetDIFile(); llvm::DIFile diFile = elementPositions[i].GetDIFile();
int line = elementPositions[i].first_line; int line = elementPositions[i].first_line;
#ifdef LLVM_2_9
llvm::DIType fieldType =
m->diBuilder->createMemberType(elementNames[i], diFile, line,
eltSize, eltAlign, currentSize, 0,
eltType);
#else
llvm::DIType fieldType = llvm::DIType fieldType =
m->diBuilder->createMemberType(scope, elementNames[i], diFile, m->diBuilder->createMemberType(scope, elementNames[i], diFile,
line, eltSize, eltAlign, line, eltSize, eltAlign,
currentSize, 0, eltType); currentSize, 0, eltType);
#endif // LLVM_2_9
elementLLVMTypes.push_back(fieldType); elementLLVMTypes.push_back(fieldType);
currentSize += eltSize; currentSize += eltSize;
@@ -1997,12 +2049,7 @@ StructType::GetDIType(llvm::DIDescriptor scope) const {
if (currentSize > 0 && (currentSize % align)) if (currentSize > 0 && (currentSize % align))
currentSize += align - (currentSize % align); currentSize += align - (currentSize % align);
#ifdef LLVM_2_9
llvm::DIArray elements = m->diBuilder->getOrCreateArray(&elementLLVMTypes[0],
elementLLVMTypes.size());
#else
llvm::DIArray elements = m->diBuilder->getOrCreateArray(elementLLVMTypes); llvm::DIArray elements = m->diBuilder->getOrCreateArray(elementLLVMTypes);
#endif
llvm::DIFile diFile = pos.GetDIFile(); llvm::DIFile diFile = pos.GetDIFile();
return m->diBuilder->createStructType(scope, name, diFile, pos.first_line, currentSize, return m->diBuilder->createStructType(scope, name, diFile, pos.first_line, currentSize,
align, 0, elements); align, 0, elements);
@@ -2014,6 +2061,10 @@ StructType::GetElementType(int i) const {
Assert(variability != Variability::Unbound); Assert(variability != Variability::Unbound);
Assert(i < (int)elementTypes.size()); Assert(i < (int)elementTypes.size());
const Type *ret = elementTypes[i]; const Type *ret = elementTypes[i];
if (ret == NULL) {
Assert(m->errorCount > 0);
return NULL;
}
// If the element has unbound variability, resolve its variability to // If the element has unbound variability, resolve its variability to
// the struct type's variability // the struct type's variability
@@ -2070,6 +2121,170 @@ StructType::checkIfCanBeSOA(const StructType *st) {
} }
///////////////////////////////////////////////////////////////////////////
// UndefinedStructType
UndefinedStructType::UndefinedStructType(const std::string &n,
const Variability var, bool ic,
SourcePos p)
: name(n), variability(var), isConst(ic), pos(p) {
Assert(name != "");
if (variability != Variability::Unbound) {
// Create a new opaque LLVM struct type for this struct name
std::string mname = lMangleStructName(name, variability);
if (lStructTypeMap.find(mname) == lStructTypeMap.end())
lStructTypeMap[mname] = llvm::StructType::create(*g->ctx, mname);
}
}
Variability
UndefinedStructType::GetVariability() const {
return variability;
}
bool
UndefinedStructType::IsBoolType() const {
return false;
}
bool
UndefinedStructType::IsFloatType() const {
return false;
}
bool
UndefinedStructType::IsIntType() const {
return false;
}
bool
UndefinedStructType::IsUnsignedType() const {
return false;
}
bool
UndefinedStructType::IsConstType() const {
return isConst;
}
const Type *
UndefinedStructType::GetBaseType() const {
return this;
}
const UndefinedStructType *
UndefinedStructType::GetAsVaryingType() const {
if (variability == Variability::Varying)
return this;
return new UndefinedStructType(name, Variability::Varying, isConst, pos);
}
const UndefinedStructType *
UndefinedStructType::GetAsUniformType() const {
if (variability == Variability::Uniform)
return this;
return new UndefinedStructType(name, Variability::Uniform, isConst, pos);
}
const UndefinedStructType *
UndefinedStructType::GetAsUnboundVariabilityType() const {
if (variability == Variability::Unbound)
return this;
return new UndefinedStructType(name, Variability::Unbound, isConst, pos);
}
const UndefinedStructType *
UndefinedStructType::GetAsSOAType(int width) const {
FATAL("UndefinedStructType::GetAsSOAType() shouldn't be called.");
return NULL;
}
const UndefinedStructType *
UndefinedStructType::ResolveUnboundVariability(Variability v) const {
if (variability != Variability::Unbound)
return this;
return new UndefinedStructType(name, v, isConst, pos);
}
const UndefinedStructType *
UndefinedStructType::GetAsConstType() const {
if (isConst)
return this;
return new UndefinedStructType(name, variability, true, pos);
}
const UndefinedStructType *
UndefinedStructType::GetAsNonConstType() const {
if (isConst == false)
return this;
return new UndefinedStructType(name, variability, false, pos);
}
std::string
UndefinedStructType::GetString() const {
std::string ret;
if (isConst) ret += "const ";
ret += variability.GetString();
ret += " struct ";
ret += name;
return ret;
}
std::string
UndefinedStructType::Mangle() const {
return lMangleStruct(variability, isConst, name);
}
std::string
UndefinedStructType::GetCDeclaration(const std::string &n) const {
std::string ret;
if (isConst) ret += "const ";
ret += std::string("struct ") + name;
if (lShouldPrintName(n))
ret += std::string(" ") + n;
return ret;
}
llvm::Type *
UndefinedStructType::LLVMType(llvm::LLVMContext *ctx) const {
Assert(variability != Variability::Unbound);
std::string mname = lMangleStructName(name, variability);
if (lStructTypeMap.find(mname) == lStructTypeMap.end()) {
Assert(m->errorCount > 0);
return NULL;
}
return lStructTypeMap[mname];
}
llvm::DIType
UndefinedStructType::GetDIType(llvm::DIDescriptor scope) const {
llvm::DIFile diFile = pos.GetDIFile();
llvm::DIArray elements;
return m->diBuilder->createStructType(scope, name, diFile, pos.first_line,
0 /* size */, 0 /* align */,
0 /* flags */, elements);
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// ReferenceType // ReferenceType
@@ -2290,14 +2505,14 @@ ReferenceType::GetCDeclaration(const std::string &name) const {
} }
LLVM_TYPE_CONST llvm::Type * llvm::Type *
ReferenceType::LLVMType(llvm::LLVMContext *ctx) const { ReferenceType::LLVMType(llvm::LLVMContext *ctx) const {
if (targetType == NULL) { if (targetType == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
} }
LLVM_TYPE_CONST llvm::Type *t = targetType->LLVMType(ctx); llvm::Type *t = targetType->LLVMType(ctx);
if (t == NULL) { if (t == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
@@ -2326,7 +2541,7 @@ FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a,
SourcePos p) SourcePos p)
: isTask(false), isExported(false), isExternC(false), returnType(r), : isTask(false), isExported(false), isExternC(false), returnType(r),
paramTypes(a), paramNames(std::vector<std::string>(a.size(), "")), paramTypes(a), paramNames(std::vector<std::string>(a.size(), "")),
paramDefaults(std::vector<ConstExpr *>(a.size(), NULL)), paramDefaults(std::vector<Expr *>(a.size(), NULL)),
paramPositions(std::vector<SourcePos>(a.size(), p)) { paramPositions(std::vector<SourcePos>(a.size(), p)) {
Assert(returnType != NULL); Assert(returnType != NULL);
isSafe = false; isSafe = false;
@@ -2336,7 +2551,7 @@ FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a,
FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a, FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a,
const std::vector<std::string> &an, const std::vector<std::string> &an,
const std::vector<ConstExpr *> &ad, const std::vector<Expr *> &ad,
const std::vector<SourcePos> &ap, const std::vector<SourcePos> &ap,
bool it, bool is, bool ec) bool it, bool is, bool ec)
: isTask(it), isExported(is), isExternC(ec), returnType(r), paramTypes(a), : isTask(it), isExported(is), isExternC(ec), returnType(r), paramTypes(a),
@@ -2450,32 +2665,19 @@ FunctionType::ResolveUnboundVariability(Variability v) const {
const Type * const Type *
FunctionType::GetAsConstType() const { FunctionType::GetAsConstType() const {
FATAL("FunctionType::GetAsConstType shouldn't be called"); return this;
return NULL;
} }
const Type * const Type *
FunctionType::GetAsNonConstType() const { FunctionType::GetAsNonConstType() const {
FATAL("FunctionType::GetAsNonConstType shouldn't be called"); return this;
return NULL;
} }
std::string std::string
FunctionType::GetString() const { FunctionType::GetString() const {
std::string ret; std::string ret = GetReturnTypeString();
if (isTask) ret += "task ";
if (isSafe) ret += "/*safe*/ ";
if (costOverride > 0) {
char buf[32];
sprintf(buf, "/*cost=%d*/ ", costOverride);
ret += buf;
}
if (returnType != NULL)
ret += returnType->GetString();
else
ret += "/* ERROR */";
ret += "("; ret += "(";
for (unsigned int i = 0; i < paramTypes.size(); ++i) { for (unsigned int i = 0; i < paramTypes.size(); ++i) {
if (paramTypes[i] == NULL) if (paramTypes[i] == NULL)
@@ -2535,7 +2737,7 @@ FunctionType::GetCDeclaration(const std::string &fname) const {
} }
LLVM_TYPE_CONST llvm::Type * llvm::Type *
FunctionType::LLVMType(llvm::LLVMContext *ctx) const { FunctionType::LLVMType(llvm::LLVMContext *ctx) const {
FATAL("FunctionType::LLVMType() shouldn't be called"); FATAL("FunctionType::LLVMType() shouldn't be called");
return NULL; return NULL;
@@ -2544,19 +2746,55 @@ FunctionType::LLVMType(llvm::LLVMContext *ctx) const {
llvm::DIType llvm::DIType
FunctionType::GetDIType(llvm::DIDescriptor scope) const { FunctionType::GetDIType(llvm::DIDescriptor scope) const {
// @todo need to implement FunctionType::GetDIType() std::vector<llvm::Value *> retArgTypes;
FATAL("need to implement FunctionType::GetDIType()");
return llvm::DIType(); retArgTypes.push_back(returnType->GetDIType(scope));
for (int i = 0; i < GetNumParameters(); ++i) {
const Type *t = GetParameterType(i);
if (t == NULL)
return llvm::DIType();
retArgTypes.push_back(t->GetDIType(scope));
}
llvm::DIArray retArgTypesArray =
m->diBuilder->getOrCreateArray(llvm::ArrayRef<llvm::Value *>(retArgTypes));
llvm::DIType diType =
// FIXME: DIFile
m->diBuilder->createSubroutineType(llvm::DIFile(), retArgTypesArray);
return diType;
} }
LLVM_TYPE_CONST llvm::FunctionType * const std::string
FunctionType::GetReturnTypeString() const {
if (returnType == NULL)
return "/* ERROR */";
std::string ret;
if (isTask)
ret += "task ";
if (isExported)
ret += "export ";
if (isExternC)
ret += "extern \"C\" ";
if (isSafe)
ret += "/*safe*/ ";
if (costOverride > 0) {
char buf[32];
sprintf(buf, "/*cost=%d*/ ", costOverride);
ret += buf;
}
return ret + returnType->GetString();
}
llvm::FunctionType *
FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask) const { FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask) const {
if (isTask == true) if (isTask == true)
Assert(includeMask == true); Assert(includeMask == true);
// Get the LLVM Type *s for the function arguments // Get the LLVM Type *s for the function arguments
std::vector<LLVM_TYPE_CONST llvm::Type *> llvmArgTypes; std::vector<llvm::Type *> llvmArgTypes;
for (unsigned int i = 0; i < paramTypes.size(); ++i) { for (unsigned int i = 0; i < paramTypes.size(); ++i) {
if (paramTypes[i] == NULL) { if (paramTypes[i] == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
@@ -2564,7 +2802,7 @@ FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask) const {
} }
Assert(Type::Equal(paramTypes[i], AtomicType::Void) == false); Assert(Type::Equal(paramTypes[i], AtomicType::Void) == false);
LLVM_TYPE_CONST llvm::Type *t = paramTypes[i]->LLVMType(ctx); llvm::Type *t = paramTypes[i]->LLVMType(ctx);
if (t == NULL) { if (t == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return NULL;
@@ -2576,7 +2814,7 @@ FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask) const {
if (includeMask) if (includeMask)
llvmArgTypes.push_back(LLVMTypes::MaskType); llvmArgTypes.push_back(LLVMTypes::MaskType);
std::vector<LLVM_TYPE_CONST llvm::Type *> callTypes; std::vector<llvm::Type *> callTypes;
if (isTask) { if (isTask) {
// Tasks take three arguments: a pointer to a struct that holds the // Tasks take three arguments: a pointer to a struct that holds the
// actual task arguments, the thread index, and the total number of // actual task arguments, the thread index, and the total number of
@@ -2610,7 +2848,7 @@ FunctionType::GetParameterType(int i) const {
} }
ConstExpr * Expr *
FunctionType::GetParameterDefault(int i) const { FunctionType::GetParameterDefault(int i) const {
Assert(i < (int)paramDefaults.size()); Assert(i < (int)paramDefaults.size());
return paramDefaults[i]; return paramDefaults[i];
@@ -2681,6 +2919,17 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
bool forceVarying, int vecSize) { bool forceVarying, int vecSize) {
Assert(reason != NULL); Assert(reason != NULL);
// First, if one or both types are function types, convert them to
// pointer to function types and then try again.
if (dynamic_cast<const FunctionType *>(t0) ||
dynamic_cast<const FunctionType *>(t1)) {
if (dynamic_cast<const FunctionType *>(t0))
t0 = PointerType::GetUniform(t0);
if (dynamic_cast<const FunctionType *>(t1))
t1 = PointerType::GetUniform(t1);
return MoreGeneralType(t0, t1, pos, reason, forceVarying, vecSize);
}
// First, if we need to go varying, promote both of the types to be // First, if we need to go varying, promote both of the types to be
// varying. // varying.
if (t0->IsVaryingType() || t1->IsVaryingType() || forceVarying) { if (t0->IsVaryingType() || t1->IsVaryingType() || forceVarying) {
@@ -2888,20 +3137,19 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
const StructType *sta = dynamic_cast<const StructType *>(a); const StructType *sta = dynamic_cast<const StructType *>(a);
const StructType *stb = dynamic_cast<const StructType *>(b); const StructType *stb = dynamic_cast<const StructType *>(b);
if (sta != NULL && stb != NULL) { const UndefinedStructType *usta =
if (sta->GetElementCount() != stb->GetElementCount()) dynamic_cast<const UndefinedStructType *>(a);
const UndefinedStructType *ustb =
dynamic_cast<const UndefinedStructType *>(b);
if ((sta != NULL || usta != NULL) && (stb != NULL || ustb != NULL)) {
// Report both defuned and undefined structs as equal if their
// names are the same.
if (a->GetVariability() != b->GetVariability())
return false; return false;
if (sta->GetStructName() != stb->GetStructName())
return false;
if (sta->GetVariability() != stb->GetVariability())
return false;
for (int i = 0; i < sta->GetElementCount(); ++i)
// FIXME: is this redundant now?
if (!lCheckTypeEquality(sta->GetElementType(i), stb->GetElementType(i),
ignoreConst))
return false;
return true; std::string namea = sta ? sta->GetStructName() : usta->GetStructName();
std::string nameb = stb ? stb->GetStructName() : ustb->GetStructName();
return (namea == nameb);
} }
const PointerType *pta = dynamic_cast<const PointerType *>(a); const PointerType *pta = dynamic_cast<const PointerType *>(a);

81
type.h
View File

@@ -187,7 +187,7 @@ public:
virtual std::string GetCDeclaration(const std::string &name) const = 0; virtual std::string GetCDeclaration(const std::string &name) const = 0;
/** Returns the LLVM type corresponding to this ispc type */ /** Returns the LLVM type corresponding to this ispc type */
virtual LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const = 0; virtual llvm::Type *LLVMType(llvm::LLVMContext *ctx) const = 0;
/** Returns the DIType (LLVM's debugging information structure), /** Returns the DIType (LLVM's debugging information structure),
corresponding to this type. */ corresponding to this type. */
@@ -269,7 +269,7 @@ public:
std::string Mangle() const; std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const; std::string GetCDeclaration(const std::string &name) const;
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const; llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const; llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
/** This enumerator records the basic types that AtomicTypes can be /** This enumerator records the basic types that AtomicTypes can be
@@ -343,7 +343,7 @@ public:
std::string Mangle() const; std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const; std::string GetCDeclaration(const std::string &name) const;
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const; llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const; llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
/** Provides the enumerators defined in the enum definition. */ /** Provides the enumerators defined in the enum definition. */
@@ -409,7 +409,6 @@ public:
const PointerType *GetAsSlice() const; const PointerType *GetAsSlice() const;
const PointerType *GetAsNonSlice() const; const PointerType *GetAsNonSlice() const;
const PointerType *GetAsFrozenSlice() const; const PointerType *GetAsFrozenSlice() const;
const StructType *GetSliceStructType() const;
const Type *GetBaseType() const; const Type *GetBaseType() const;
const PointerType *GetAsVaryingType() const; const PointerType *GetAsVaryingType() const;
@@ -425,7 +424,7 @@ public:
std::string Mangle() const; std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const; std::string GetCDeclaration(const std::string &name) const;
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const; llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const; llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
static PointerType *Void; static PointerType *Void;
@@ -523,7 +522,7 @@ public:
std::string GetCDeclaration(const std::string &name) const; std::string GetCDeclaration(const std::string &name) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const; llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
LLVM_TYPE_CONST llvm::ArrayType *LLVMType(llvm::LLVMContext *ctx) const; llvm::ArrayType *LLVMType(llvm::LLVMContext *ctx) const;
/** This method returns the total number of elements in the array, /** This method returns the total number of elements in the array,
including all dimensions if this is a multidimensional array. */ including all dimensions if this is a multidimensional array. */
@@ -589,7 +588,7 @@ public:
std::string Mangle() const; std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const; std::string GetCDeclaration(const std::string &name) const;
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const; llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const; llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
int GetElementCount() const; int GetElementCount() const;
@@ -639,7 +638,7 @@ public:
std::string Mangle() const; std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const; std::string GetCDeclaration(const std::string &name) const;
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const; llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const; llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
/** Returns the type of the structure element with the given name (if any). /** Returns the type of the structure element with the given name (if any).
@@ -668,7 +667,7 @@ public:
private: private:
static bool checkIfCanBeSOA(const StructType *st); static bool checkIfCanBeSOA(const StructType *st);
const std::string name; /*const*/ std::string name;
/** The types of the struct elements. Note that we store these with /** The types of the struct elements. Note that we store these with
uniform/varying exactly as they were declared in the source file. uniform/varying exactly as they were declared in the source file.
(In other words, even if this struct has a varying qualifier and (In other words, even if this struct has a varying qualifier and
@@ -690,6 +689,52 @@ private:
}; };
/** Type implementation representing a struct name that has been declared
but where the struct members haven't been defined (i.e. "struct Foo;").
This class doesn't do much besides serve as a placeholder that other
code can use to detect the presence of such as truct.
*/
class UndefinedStructType : public Type {
public:
UndefinedStructType(const std::string &name, const Variability variability,
bool isConst, SourcePos pos);
Variability GetVariability() const;
bool IsBoolType() const;
bool IsFloatType() const;
bool IsIntType() const;
bool IsUnsignedType() const;
bool IsConstType() const;
const Type *GetBaseType() const;
const UndefinedStructType *GetAsVaryingType() const;
const UndefinedStructType *GetAsUniformType() const;
const UndefinedStructType *GetAsUnboundVariabilityType() const;
const UndefinedStructType *GetAsSOAType(int width) const;
const UndefinedStructType *ResolveUnboundVariability(Variability v) const;
const UndefinedStructType *GetAsConstType() const;
const UndefinedStructType *GetAsNonConstType() const;
std::string GetString() const;
std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const;
llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
/** Returns the name of the structure type. (e.g. struct Foo -> "Foo".) */
const std::string &GetStructName() const { return name; }
private:
const std::string name;
const Variability variability;
const bool isConst;
const SourcePos pos;
};
/** @brief Type representing a reference to another (non-reference) type. /** @brief Type representing a reference to another (non-reference) type.
*/ */
class ReferenceType : public Type { class ReferenceType : public Type {
@@ -719,7 +764,7 @@ public:
std::string Mangle() const; std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const; std::string GetCDeclaration(const std::string &name) const;
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const; llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const; llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
private: private:
@@ -745,7 +790,7 @@ public:
FunctionType(const Type *returnType, FunctionType(const Type *returnType,
const std::vector<const Type *> &argTypes, const std::vector<const Type *> &argTypes,
const std::vector<std::string> &argNames, const std::vector<std::string> &argNames,
const std::vector<ConstExpr *> &argDefaults, const std::vector<Expr *> &argDefaults,
const std::vector<SourcePos> &argPos, const std::vector<SourcePos> &argPos,
bool isTask, bool isExported, bool isExternC); bool isTask, bool isExported, bool isExternC);
@@ -771,21 +816,23 @@ public:
std::string Mangle() const; std::string Mangle() const;
std::string GetCDeclaration(const std::string &fname) const; std::string GetCDeclaration(const std::string &fname) const;
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const; llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const; llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
const Type *GetReturnType() const { return returnType; } const Type *GetReturnType() const { return returnType; }
const std::string GetReturnTypeString() const;
/** This method returns the LLVM FunctionType that corresponds to this /** This method returns the LLVM FunctionType that corresponds to this
function type. The \c includeMask parameter indicates whether the function type. The \c includeMask parameter indicates whether the
llvm::FunctionType should have a mask as the last argument in its llvm::FunctionType should have a mask as the last argument in its
function signature. */ function signature. */
LLVM_TYPE_CONST llvm::FunctionType *LLVMFunctionType(llvm::LLVMContext *ctx, llvm::FunctionType *LLVMFunctionType(llvm::LLVMContext *ctx,
bool includeMask = false) const; bool includeMask = false) const;
int GetNumParameters() const { return (int)paramTypes.size(); } int GetNumParameters() const { return (int)paramTypes.size(); }
const Type *GetParameterType(int i) const; const Type *GetParameterType(int i) const;
ConstExpr * GetParameterDefault(int i) const; Expr * GetParameterDefault(int i) const;
const SourcePos &GetParameterSourcePos(int i) const; const SourcePos &GetParameterSourcePos(int i) const;
const std::string &GetParameterName(int i) const; const std::string &GetParameterName(int i) const;
@@ -818,7 +865,7 @@ private:
const std::vector<std::string> paramNames; const std::vector<std::string> paramNames;
/** Default values of the function's arguments. For arguments without /** Default values of the function's arguments. For arguments without
default values provided, NULL is stored. */ default values provided, NULL is stored. */
mutable std::vector<ConstExpr *> paramDefaults; mutable std::vector<Expr *> paramDefaults;
/** The names provided (if any) with the function arguments in the /** The names provided (if any) with the function arguments in the
function's signature. These should only be used for error messages function's signature. These should only be used for error messages
and the like and so not affect testing function types for equality, and the like and so not affect testing function types for equality,
@@ -826,4 +873,8 @@ private:
const std::vector<SourcePos> paramPositions; const std::vector<SourcePos> paramPositions;
}; };
inline bool IsReferenceType(const Type *t) {
return dynamic_cast<const ReferenceType *>(t) != NULL;
}
#endif // ISPC_TYPE_H #endif // ISPC_TYPE_H