diff --git a/lex.ll b/lex.ll index d999d8bb..ff1e8c25 100644 --- a/lex.ll +++ b/lex.ll @@ -49,6 +49,7 @@ static void lCppComment(SourcePos *); static void lHandleCppHash(SourcePos *); static void lStringConst(YYSTYPE *, SourcePos *); static double lParseHexFloat(const char *ptr); +extern void RegisterDependency(const std::string &fileName); #define YY_USER_ACTION \ yylloc.first_line = yylloc.last_line; \ @@ -662,6 +663,7 @@ static void lHandleCppHash(SourcePos *pos) { ++src; } pos->name = strdup(filename.c_str()); + RegisterDependency(filename); } diff --git a/main.cpp b/main.cpp index c80429c2..23825e2d 100644 --- a/main.cpp +++ b/main.cpp @@ -89,6 +89,7 @@ usage(int ret) { printf(" [--cpu=]\t\t\tSelect target CPU type\n"); printf(" ={%s}\n", Target::SupportedTargetCPUs().c_str()); printf(" [-D]\t\t\t\t#define given value when running preprocessor\n"); + printf(" [--dev-stub ]\t\tEmit device-side offload stub functions to file\n"); printf(" [--emit-asm]\t\t\tGenerate assembly language file as output\n"); printf(" [--emit-c++]\t\t\tEmit a C++ source file as output\n"); printf(" [--emit-llvm]\t\t\tEmit LLVM bitode file as output\n"); @@ -96,6 +97,7 @@ usage(int ret) { printf(" [-g]\t\t\t\tGenerate debugging information\n"); printf(" [--help]\t\t\t\tPrint help\n"); printf(" [--help-dev]\t\t\tPrint help for developer options\n"); + printf(" [--host-stub ]\t\tEmit host-side offload stub functions to file\n"); printf(" [-h /--header-outfile=]\tOutput filename for header\n"); printf(" [-I ]\t\t\t\tAdd to #include file search path\n"); printf(" [--instrument]\t\t\tEmit instrumentation to gather performance data\n"); @@ -104,6 +106,7 @@ usage(int ret) { printf(" fast\t\t\t\tUse high-performance but lower-accuracy math functions\n"); printf(" svml\t\t\t\tUse the Intel(r) SVML math libraries\n"); printf(" system\t\t\t\tUse the system's math library (*may be quite slow*)\n"); + printf(" [-MMM \t\t\t\tWrite #include dependencies to given file.\n"); printf(" [--nostdlib]\t\t\tDon't make the ispc standard library available\n"); printf(" [--nocpp]\t\t\t\tDon't run the C preprocessor\n"); printf(" [-o /--outfile=]\tOutput filename (may be \"-\" for standard output)\n"); @@ -221,7 +224,9 @@ int main(int Argc, char *Argv[]) { const char *headerFileName = NULL; const char *outFileName = NULL; const char *includeFileName = NULL; - + const char *depsFileName = NULL; + const char *hostStubFileName = NULL; + const char *devStubFileName = NULL; // Initiailize globals early so that we can set various option values // as we're parsing below g = new Globals; @@ -413,6 +418,27 @@ int main(int Argc, char *Argv[]) { extern int yydebug; yydebug = 1; } + else if (!strcmp(argv[i], "-MMM")) { + if (++i == argc) { + fprintf(stderr, "No output file name specified after -MMM option.\n"); + usage(1); + } + depsFileName = argv[i]; + } + else if (!strcmp(argv[i], "--dev-stub")) { + if (++i == argc) { + fprintf(stderr, "No output file name specified after --dev-stub option.\n"); + usage(1); + } + devStubFileName = argv[i]; + } + else if (!strcmp(argv[i], "--host-stub")) { + if (++i == argc) { + fprintf(stderr, "No output file name specified after --host-stub option.\n"); + usage(1); + } + hostStubFileName = argv[i]; + } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { lPrintVersion(); return 0; @@ -456,12 +482,21 @@ int main(int Argc, char *Argv[]) { #endif } - if (outFileName == NULL && headerFileName == NULL) - Warning(SourcePos(), "No output file or header file name specified. " - "Program will be compiled and warnings/errors will " - "be issued, but no output will be generated."); + if (outFileName == NULL && + headerFileName == NULL && + depsFileName == NULL && + hostStubFileName == NULL && + devStubFileName == NULL) + Warning(SourcePos(), "No output file or header file name specified. " + "Program will be compiled and warnings/errors will " + "be issued, but no output will be generated."); return Module::CompileAndOutput(file, arch, cpu, target, generatePIC, - ot, outFileName, headerFileName, - includeFileName); + ot, + outFileName, + headerFileName, + includeFileName, + depsFileName, + hostStubFileName, + devStubFileName); } diff --git a/module.cpp b/module.cpp index 220ecd49..e751f6ed 100644 --- a/module.cpp +++ b/module.cpp @@ -56,6 +56,8 @@ #include #include #include +#include +#include #ifdef ISPC_IS_WINDOWS #include #include @@ -88,6 +90,18 @@ #include #include +/*! list of files encountered by the parser. this allows emitting of + the module file's dependencies via the -MMM option */ +std::set registeredDependencies; + +/*! this is where the parser tells us that it has seen the given file + name in the CPP hash */ +void RegisterDependency(const std::string &fileName) +{ + if (fileName[0] != '<' && fileName != "stdlib.ispc") + registeredDependencies.insert(fileName); +} + static void lDeclareSizeAndPtrIntTypes(SymbolTable *symbolTable) { const Type *ptrIntType = (g->target.is32Bit) ? AtomicType::VaryingInt32 : @@ -880,6 +894,23 @@ Module::writeOutput(OutputType outputType, const char *outFileName, strcasecmp(suffix, "hpp")) fileType = "header"; break; + case Deps: + break; + case DevStub: + if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") && + strcasecmp(suffix, "c++") && strcasecmp(suffix, "cxx") && + strcasecmp(suffix, "cpp")) + fileType = "dev-side offload stub"; + break; + case HostStub: + if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") && + strcasecmp(suffix, "c++") && strcasecmp(suffix, "cxx") && + strcasecmp(suffix, "cpp")) + fileType = "host-side offload stub"; + break; + default: + Assert(0 /* swtich case not handled */); + return 1; } if (fileType != NULL) fprintf(stderr, "Warning: emitting %s file, but filename \"%s\" " @@ -887,7 +918,13 @@ Module::writeOutput(OutputType outputType, const char *outFileName, } if (outputType == Header) - return writeHeader(outFileName); + return writeHeader(outFileName); + else if (outputType == Deps) + return writeDeps(outFileName); + else if (outputType == HostStub) + return writeHostStub(outFileName); + else if (outputType == DevStub) + return writeDevStub(outFileName); else if (outputType == Bitcode) return writeBitcode(module, outFileName); else if (outputType == CXX) { @@ -1187,18 +1224,28 @@ lGetExportedParamTypes(const std::vector &funcs, static void -lPrintFunctionDeclarations(FILE *file, const std::vector &funcs) { - fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n"); - for (unsigned int i = 0; i < funcs.size(); ++i) { - const FunctionType *ftype = CastType(funcs[i]->type); - Assert(ftype); - std::string decl = ftype->GetCDeclaration(funcs[i]->name); - fprintf(file, " extern %s;\n", decl.c_str()); - } - fprintf(file, "#ifdef __cplusplus\n}\n#endif // __cplusplus\n"); +lPrintFunctionDeclarations(FILE *file, const std::vector &funcs, + bool useExternC=1) { + if (useExternC) + fprintf(file, "#if defined(__cplusplus) && !defined(__ISPC_NO_EXTERN_C)\nextern \"C\" {\n#endif // __cplusplus\n"); + // fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n"); + for (unsigned int i = 0; i < funcs.size(); ++i) { + const FunctionType *ftype = CastType(funcs[i]->type); + Assert(ftype); + std::string decl = ftype->GetCDeclaration(funcs[i]->name); + fprintf(file, " extern %s;\n", decl.c_str()); + } + if (useExternC) + + fprintf(file, "#if defined(__cplusplus) && !defined(__ISPC_NO_EXTERN_C)\n} /* end extern C */\n#endif // __cplusplus\n"); + // fprintf(file, "#ifdef __cplusplus\n} /* end extern C */\n#endif // __cplusplus\n"); } + + + + static bool lIsExported(const Symbol *sym) { const FunctionType *ft = CastType(sym->type); @@ -1215,6 +1262,312 @@ lIsExternC(const Symbol *sym) { } +bool +Module::writeDeps(const char *fn) { + std::cout << "writing dependencies to file " << fn << std::endl; + FILE *file = fopen(fn,"w"); + if (!file) { + perror("fopen"); + return false; + } + + for (std::set::const_iterator it=registeredDependencies.begin(); + it != registeredDependencies.end(); + ++it) + fprintf(file,"%s\n",it->c_str()); + return true; +} + + +std::string emitOffloadParamStruct(const std::string ¶mStructName, + const Symbol *sym, + const FunctionType *fct) +{ + std::stringstream out; + out << "struct " << paramStructName << " {" << std::endl; + + for (int i=0;iGetNumParameters();i++) { + const Type *orgParamType = fct->GetParameterType(i); + if (orgParamType->IsPointerType() || orgParamType->IsArrayType()) { + /* we're passing pointers separately -- no pointers in that struct... */ + continue; + } + + // const reference parameters can be passed as copies. + const Type *paramType; + if (orgParamType->IsReferenceType()) { + if (!orgParamType->IsConstType()) { + Error(sym->pos,"When emitting offload-stubs, \"export\"ed functions cannot have non-const reference-type parameters.\n"); + } + const ReferenceType *refType + = dynamic_cast(orgParamType); + paramType = refType->GetReferenceTarget()->GetAsNonConstType(); + } else { + paramType = orgParamType->GetAsNonConstType(); + } + std::string paramName = fct->GetParameterName(i); + std::string paramTypeName = paramType->GetString(); + + std::string tmpArgDecl = paramType->GetCDeclaration(paramName); + out << " " << tmpArgDecl << ";" << std::endl; + } + + out << "};" << std::endl; + return out.str(); +} + +bool +Module::writeDevStub(const char *fn) +{ + FILE *file = fopen(fn, "w"); + if (!file) { + perror("fopen"); + return false; + } + fprintf(file, "//\n// %s\n// (device stubs automatically generated by the ispc compiler.)\n", fn); + fprintf(file, "// DO NOT EDIT THIS FILE.\n//\n\n"); + fprintf(file,"#include \"ispc/dev/offload.h\"\n\n"); + + fprintf(file, "#include \n\n"); + + // Collect single linear arrays of the *exported* functions (we'll + // treat those as "__kernel"s in IVL -- "extern" functions will only + // be used for dev-dev function calls; only "export" functions will + // get exported to the host + std::vector exportedFuncs; + m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs); + + // Get all of the struct, vector, and enumerant types used as function + // parameters. These vectors may have repeats. + std::vector exportedStructTypes; + std::vector exportedEnumTypes; + std::vector exportedVectorTypes; + lGetExportedParamTypes(exportedFuncs, &exportedStructTypes, + &exportedEnumTypes, &exportedVectorTypes); + + // And print them + lEmitVectorTypedefs(exportedVectorTypes, file); + lEmitEnumDecls(exportedEnumTypes, file); + lEmitStructDecls(exportedStructTypes, file); + + fprintf(file, "#ifdef __cplusplus\n"); + fprintf(file, "namespace ispc {\n"); + fprintf(file, "#endif // __cplusplus\n"); + + fprintf(file, "\n"); + fprintf(file, "///////////////////////////////////////////////////////////////////////////\n"); + fprintf(file, "// Functions exported from ispc code\n"); + fprintf(file, "// (so the dev stub knows what to call)\n"); + fprintf(file, "///////////////////////////////////////////////////////////////////////////\n"); + lPrintFunctionDeclarations(file, exportedFuncs, true); + + fprintf(file, "#ifdef __cplusplus\n"); + fprintf(file, "}/* end namespace */\n"); + fprintf(file, "#endif // __cplusplus\n"); + + fprintf(file, "\n"); + fprintf(file, "///////////////////////////////////////////////////////////////////////////\n"); + fprintf(file, "// actual dev stubs\n"); + fprintf(file, "///////////////////////////////////////////////////////////////////////////\n"); + + fprintf(file, "// note(iw): due to some linking issues offload stubs *only* work under C++\n"); + fprintf(file, "extern \"C\" {\n\n"); + for (unsigned int i = 0; i < exportedFuncs.size(); ++i) { + const Symbol *sym = exportedFuncs[i]; + Assert(sym); + const FunctionType *fct = CastType(sym->type); + Assert(fct); + + if (!fct->GetReturnType()->IsVoidType()) { + Error(sym->pos,"When emitting offload-stubs, \"export\"ed functions cannot have non-void return types.\n"); + } + + // ------------------------------------------------------- + // first, emit a struct that holds the parameters + // ------------------------------------------------------- + std::string paramStructName = std::string("__ispc_dev_stub_")+sym->name; + std::string paramStruct = emitOffloadParamStruct(paramStructName,sym,fct); + fprintf(file,"%s\n",paramStruct.c_str()); + // ------------------------------------------------------- + // then, emit a fct stub that unpacks the parameters and pointers + // ------------------------------------------------------- + fprintf(file,"void __ispc_dev_stub_%s(\n" + " uint32_t in_BufferCount,\n" + " void** in_ppBufferPointers,\n" + " uint64_t* in_pBufferLengths,\n" + " void* in_pMiscData,\n" + " uint16_t in_MiscDataLength,\n" + " void* in_pReturnValue,\n" + " uint16_t in_ReturnValueLength)\n", + sym->name.c_str() + ); + fprintf(file,"{\n"); + fprintf(file," struct %s args;\n memcpy(&args,in_pMiscData,sizeof(args));\n", + paramStructName.c_str()); + std::stringstream funcall; + + funcall << "ispc::" << sym->name << "("; + for (int i=0;iGetNumParameters();i++) { + // get param type and make it non-const, so we can write while unpacking + // const Type *paramType = fct->GetParameterType(i)->GetAsNonConstType(); + const Type *paramType;// = fct->GetParameterType(i)->GetAsNonConstType(); + const Type *orgParamType = fct->GetParameterType(i); + if (orgParamType->IsReferenceType()) { + if (!orgParamType->IsConstType()) { + Error(sym->pos,"When emitting offload-stubs, \"export\"ed functions cannot have non-const reference-type parameters.\n"); + } + const ReferenceType *refType + = dynamic_cast(orgParamType); + paramType = refType->GetReferenceTarget()->GetAsNonConstType(); + } else { + paramType = orgParamType->GetAsNonConstType(); + } + + std::string paramName = fct->GetParameterName(i); + std::string paramTypeName = paramType->GetString(); + + if (i) funcall << ", "; + std::string tmpArgName = std::string("_")+paramName; + if (paramType->IsPointerType() || paramType->IsArrayType()) { + std::string tmpArgDecl = paramType->GetCDeclaration(tmpArgName); + fprintf(file," %s;\n", + tmpArgDecl.c_str()); + fprintf(file," (void *&)%s = ispc_dev_translate_pointer(*in_ppBufferPointers++);\n", + tmpArgName.c_str()); + funcall << tmpArgName; + } else { + funcall << "args." << paramName; + } + } + funcall << ");"; + fprintf(file," %s\n",funcall.str().c_str()); + fprintf(file,"}\n\n"); + } + + // end extern "C" + fprintf(file, "}/* end extern C */\n"); + + fclose(file); + return true; +} + + + +bool +Module::writeHostStub(const char *fn) +{ + FILE *file = fopen(fn, "w"); + if (!file) { + perror("fopen"); + return false; + } + fprintf(file, "//\n// %s\n// (device stubs automatically generated by the ispc compiler.)\n", fn); + fprintf(file, "// DO NOT EDIT THIS FILE.\n//\n\n"); + fprintf(file,"#include \"ispc/host/offload.h\"\n\n"); + fprintf(file,"// note(iw): Host stubs do not get extern C linkage -- dev-side already uses that for the same symbols.\n\n"); + //fprintf(file,"#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n"); + + fprintf(file, "#ifdef __cplusplus\nnamespace ispc {\n#endif // __cplusplus\n\n"); + + // Collect single linear arrays of the *exported* functions (we'll + // treat those as "__kernel"s in IVL -- "extern" functions will only + // be used for dev-dev function calls; only "export" functions will + // get exported to the host + std::vector exportedFuncs; + m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs); + + // Get all of the struct, vector, and enumerant types used as function + // parameters. These vectors may have repeats. + std::vector exportedStructTypes; + std::vector exportedEnumTypes; + std::vector exportedVectorTypes; + lGetExportedParamTypes(exportedFuncs, &exportedStructTypes, + &exportedEnumTypes, &exportedVectorTypes); + + // And print them + lEmitVectorTypedefs(exportedVectorTypes, file); + lEmitEnumDecls(exportedEnumTypes, file); + lEmitStructDecls(exportedStructTypes, file); + + fprintf(file, "\n"); + fprintf(file, "///////////////////////////////////////////////////////////////////////////\n"); + fprintf(file, "// host-side stubs for dev-side ISPC fucntion(s)\n"); + fprintf(file, "///////////////////////////////////////////////////////////////////////////\n"); + for (unsigned int i = 0; i < exportedFuncs.size(); ++i) { + const Symbol *sym = exportedFuncs[i]; + Assert(sym); + const FunctionType *fct = CastType(sym->type); + Assert(fct); + + // ------------------------------------------------------- + // first, emit a struct that holds the parameters + // ------------------------------------------------------- + std::string paramStructName = std::string("__ispc_dev_stub_")+sym->name; + std::string paramStruct = emitOffloadParamStruct(paramStructName,sym,fct); + fprintf(file,"%s\n",paramStruct.c_str()); + // ------------------------------------------------------- + // then, emit a fct stub that unpacks the parameters and pointers + // ------------------------------------------------------- + + std::string decl = fct->GetCDeclaration(sym->name); + fprintf(file, "extern %s {\n", decl.c_str()); + int numPointers = 0; + fprintf(file, " %s __args;\n",paramStructName.c_str()); + + // ------------------------------------------------------------------ + // write args, and save pointers for later + // ------------------------------------------------------------------ + std::stringstream pointerArgs; + for (int i=0;iGetNumParameters();i++) { + const Type *orgParamType = fct->GetParameterType(i); + std::string paramName = fct->GetParameterName(i); + if (orgParamType->IsPointerType() || orgParamType->IsArrayType()) { + /* we're passing pointers separately -- no pointers in that struct... */ + if (numPointers) + pointerArgs << ","; + pointerArgs << "(void*)" << paramName; + numPointers++; + continue; + } + + fprintf(file," __args.%s = %s;\n", + paramName.c_str(),paramName.c_str()); + } + // ------------------------------------------------------------------ + // writer pointer list + // ------------------------------------------------------------------ + if (numPointers == 0) + pointerArgs << "NULL"; + fprintf(file," void *ptr_args[] = { %s };\n" ,pointerArgs.str().c_str()); + + // ------------------------------------------------------------------ + // ... and call the kernel with those args + // ------------------------------------------------------------------ + fprintf(file," static ispc_kernel_handle_t kernel_handle = NULL;\n"); + fprintf(file," if (!kernel_handle) kernel_handle = ispc_host_get_kernel_handle(\"__ispc_dev_stub_%s\");\n", + sym->name.c_str()); + fprintf(file," assert(kernel_handle);\n"); + fprintf(file, + " ispc_host_call_kernel(kernel_handle,\n" + " &__args, sizeof(__args),\n" + " ptr_args,%i);\n", + numPointers); + fprintf(file,"}\n\n"); + } + + // end extern "C" + fprintf(file, "#ifdef __cplusplus\n"); + fprintf(file, "}/* namespace */\n"); + fprintf(file, "#endif // __cplusplus\n"); + // fprintf(file, "#ifdef __cplusplus\n"); + // fprintf(file, "}/* end extern C */\n"); + // fprintf(file, "#endif // __cplusplus\n"); + + fclose(file); + return true; +} + + bool Module::writeHeader(const char *fn) { FILE *f = fopen(fn, "w"); @@ -1242,8 +1595,6 @@ Module::writeHeader(const char *fn) { fprintf(f, "#include \n\n"); - fprintf(f, "#ifdef __cplusplus\nnamespace ispc {\n#endif // __cplusplus\n\n"); - if (g->emitInstrumentation) { fprintf(f, "#define ISPC_INSTRUMENTATION 1\n"); fprintf(f, "extern \"C\" {\n"); @@ -1251,6 +1602,11 @@ Module::writeHeader(const char *fn) { fprintf(f, "}\n"); } + // end namespace + fprintf(f, "\n"); + fprintf(f, "\n#ifdef __cplusplus\nnamespace ispc { /* namespace */\n#endif // __cplusplus\n"); + + // Collect single linear arrays of the exported and extern "C" // functions std::vector exportedFuncs, externCFuncs; @@ -1303,7 +1659,8 @@ Module::writeHeader(const char *fn) { #endif // end namespace - fprintf(f, "\n#ifdef __cplusplus\n}\n#endif // __cplusplus\n"); + fprintf(f, "\n"); + fprintf(f, "\n#ifdef __cplusplus\n} /* namespace */\n#endif // __cplusplus\n"); // end guard fprintf(f, "\n#endif // %s\n", guard.c_str()); @@ -1775,10 +2132,19 @@ lCreateDispatchModule(std::map &functions) int -Module::CompileAndOutput(const char *srcFile, const char *arch, const char *cpu, - const char *target, bool generatePIC, OutputType outputType, - const char *outFileName, const char *headerFileName, - const char *includeFileName) { +Module::CompileAndOutput(const char *srcFile, + const char *arch, + const char *cpu, + const char *target, + bool generatePIC, + OutputType outputType, + const char *outFileName, + const char *headerFileName, + const char *includeFileName, + const char *depsFileName, + const char *hostStubFileName, + const char *devStubFileName) +{ if (target == NULL || strchr(target, ',') == NULL) { // We're only compiling to a single target if (!Target::GetTarget(arch, cpu, target, generatePIC, &g->target)) @@ -1792,6 +2158,15 @@ Module::CompileAndOutput(const char *srcFile, const char *arch, const char *cpu, if (headerFileName != NULL) if (!m->writeOutput(Module::Header, headerFileName)) return 1; + if (depsFileName != NULL) + if (!m->writeOutput(Module::Deps,depsFileName)) + return 1; + if (hostStubFileName != NULL) + if (!m->writeOutput(Module::HostStub,hostStubFileName)) + return 1; + if (devStubFileName != NULL) + if (!m->writeOutput(Module::DevStub,devStubFileName)) + return 1; } else ++m->errorCount; diff --git a/module.h b/module.h index f08a19d3..d3290fd2 100644 --- a/module.h +++ b/module.h @@ -91,9 +91,12 @@ public: Bitcode, /** Generate LLVM IR bitcode output */ Object, /** Generate a native object file */ CXX, /** Generate a C++ file */ - Header /** Generate a C/C++ header file with + Header, /** Generate a C/C++ header file with declarations of 'export'ed functions, global variables, and the types used by them. */ + Deps, /** generate dependencies */ + DevStub, /** generate device-side offload stubs */ + HostStub /** generate host-side offload stubs */ }; /** Compile the given source file, generating assembly, object file, or @@ -128,10 +131,14 @@ public: */ static int CompileAndOutput(const char *srcFile, const char *arch, const char *cpu, const char *targets, - bool generatePIC, OutputType outputType, + bool generatePIC, + OutputType outputType, const char *outFileName, - const char *headerFileName, - const char *includeFileName); + const char *headerFileName, + const char *includeFileName, + const char *depsFileName, + const char *hostStubFileName, + const char *devStubFileName); /** Total number of errors encountered during compilation. */ int errorCount; @@ -159,6 +166,9 @@ private: bool writeOutput(OutputType ot, const char *filename, const char *includeFileName = NULL); bool writeHeader(const char *filename); + bool writeDeps(const char *filename); + bool writeDevStub(const char *filename); + bool writeHostStub(const char *filename); bool writeObjectFileOrAssembly(OutputType outputType, const char *filename); static bool writeObjectFileOrAssembly(llvm::TargetMachine *targetMachine, llvm::Module *module, OutputType outputType, diff --git a/type.cpp b/type.cpp index d007ec72..d7da461e 100644 --- a/type.cpp +++ b/type.cpp @@ -196,12 +196,32 @@ AtomicType::GetVariability() const { } +bool +Type::IsPointerType() const { + return (CastType(this) != NULL); +} + + +bool +Type::IsArrayType() const { + return (CastType(this) != NULL); +} + +bool +Type::IsReferenceType() const { + return (CastType(this) != NULL); +} + +bool +Type::IsVoidType() const { + return this == AtomicType::Void; +} + bool AtomicType::IsFloatType() const { return (basicType == TYPE_FLOAT || basicType == TYPE_DOUBLE); } - bool AtomicType::IsIntType() const { return (basicType == TYPE_INT8 || basicType == TYPE_UINT8 || diff --git a/type.h b/type.h index ebd69af9..75c5e6e6 100644 --- a/type.h +++ b/type.h @@ -115,6 +115,18 @@ public: integer types. */ virtual bool IsUnsignedType() const = 0; + /** Returns true if the underlying type is either a pointer type */ + bool IsPointerType() const; + + /** Returns true if the underlying type is a array type */ + bool IsArrayType() const; + + /** Returns true if the underlying type is a array type */ + bool IsReferenceType() const; + + /** Returns true if the underlying type is either a pointer or an array */ + bool IsVoidType() const; + /** Returns true if this type is 'const'-qualified. */ virtual bool IsConstType() const = 0;