diff --git a/Makefile b/Makefile index 3b55b25a..e9422564 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ ARCH_TYPE = $(shell arch) ifeq ($(shell $(LLVM_CONFIG) --version), 3.1svn) LLVM_LIBS=-lLLVMAsmParser -lLLVMInstrumentation -lLLVMLinker \ -lLLVMArchive -lLLVMBitReader -lLLVMDebugInfo -lLLVMJIT -lLLVMipo \ - -lLLVMBitWriter -lLLVMTableGen -lLLVMCBackendInfo \ + -lLLVMBitWriter -lLLVMTableGen \ -lLLVMX86Disassembler -lLLVMX86CodeGen -lLLVMSelectionDAG \ -lLLVMAsmPrinter -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info \ -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCDisassembler -lLLVMMCParser \ diff --git a/cbackend.cpp b/cbackend.cpp index e39f8461..c3f6d0f7 100644 --- a/cbackend.cpp +++ b/cbackend.cpp @@ -16,6 +16,8 @@ #warning "The C++ backend isn't supported when building with LLVM 2.9" #else +#include + #ifndef _MSC_VER #include #endif @@ -933,6 +935,20 @@ void CWriter::printConstantDataSequential(ConstantDataSequential *CDS, } #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 ""; // error +} +#endif // LLVM_3_1svn + // 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 // variable). We decide this by converting CFP to a string and back into a diff --git a/docs/faq.rst b/docs/faq.rst index 3fc9f9e2..a3517bea 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -14,6 +14,12 @@ distribution. + `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?`_ +* 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 + `How can I supply an initial execution mask in the call from the application?`_ @@ -214,6 +220,125 @@ easier to understand: 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 ================ diff --git a/llvmutil.cpp b/llvmutil.cpp index 2ba60dbb..9f4fc658 100644 --- a/llvmutil.cpp +++ b/llvmutil.cpp @@ -1443,7 +1443,10 @@ lExtractFirstVectorElement(llvm::Value *v, llvm::Instruction *insertBefore, llvm::Instruction *phiInsertPos = phi->getParent()->begin(); llvm::PHINode *scalarPhi = llvm::PHINode::Create(vt->getElementType(), - phi->getNumIncomingValues(), newName, +#ifndef LLVM_2_9 + phi->getNumIncomingValues(), +#endif // !LLVM_2_9 + newName, phiInsertPos); phiMap[phi] = scalarPhi; diff --git a/main.cpp b/main.cpp index 8c231b60..cc6fd778 100644 --- a/main.cpp +++ b/main.cpp @@ -44,7 +44,6 @@ #ifdef ISPC_IS_WINDOWS #include #endif // ISPC_IS_WINDOWS -#include #include #if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn) #include @@ -202,17 +201,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 argc; char *argv[128]; lGetAllArgs(Argc, Argv, argc, argv); -#if 0 - // Use LLVM's little utility function to print out nice stack traces if - // we crash - llvm::sys::PrintStackTraceOnErrorSignal(); - llvm::PrettyStackTraceProgram X(argc, argv); -#endif + llvm::sys::AddSignalHandler(lSignal, NULL); // initialize available LLVM targets LLVMInitializeX86TargetInfo(); diff --git a/opt.cpp b/opt.cpp index 1ebfd4a4..5bc3737e 100644 --- a/opt.cpp +++ b/opt.cpp @@ -286,6 +286,8 @@ Optimize(llvm::Module *module, int optLevel) { llvm::PassManager optPM; llvm::FunctionPassManager funcPM(module); + optPM.add(llvm::createVerifierPass()); + if (g->target.isa != Target::GENERIC) { llvm::TargetLibraryInfo *targetLibraryInfo = new llvm::TargetLibraryInfo(llvm::Triple(module->getTargetTriple())); @@ -1130,7 +1132,11 @@ lExtractFromInserts(llvm::Value *v, unsigned int index) { return NULL; Assert(iv->hasIndices() && iv->getNumIndices() == 1); +#ifdef LLVM_2_9 + if (*(iv->idx_begin()) == index) +#else if (iv->getIndices()[0] == index) +#endif return iv->getInsertedValueOperand(); else return lExtractFromInserts(iv->getAggregateOperand(), index); @@ -1260,7 +1266,11 @@ lGetBasePtrAndOffsets(llvm::Value *ptrs, llvm::Value **offsets, llvm::ExtractValueInst *ev = llvm::dyn_cast(ptrs); if (ev != NULL) { Assert(ev->getNumIndices() == 1); +#ifdef LLVM_2_9 + int index = *(ev->idx_begin()); +#else int index = ev->getIndices()[0]; +#endif ptrs = lExtractFromInserts(ev->getAggregateOperand(), index); if (ptrs != NULL) return lGetBasePtrAndOffsets(ptrs, offsets, insertBefore);