// // Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved. // #include "OpenCLFE.h" #include "bif/bifbase.hpp" #include "frontend.hpp" #include "os/os.hpp" #include "top.hpp" #include "utils/libUtils.h" #include "utils/options.hpp" #include "utils/target_mappings.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/ADT/StringRef.h" #include #include #include amdcl::ClangOCLFrontend::ClangOCLFrontend(aclCompiler* cl, aclBinary* elf, aclLogFunction log) : Frontend(cl, elf, log){} /// @brief This function generates the required command-line options to /// call the ClangOCLFE library. int amdcl::ClangOCLFrontend::compileCommand(const std::string& src) { std::vector argsToClang; std::string tempFileName = amd::Os::getTempFileName(); std::string logFileName = tempFileName + ".log"; std::string inpCLFileName = tempFileName + ".cl"; std::string logFromClang; int ret = 0; aclBinary *elf = Elf(); amd::option::Options* amdOpts = (amd::option::Options*)elf->options; // Following are the options passed to the ClangOCLFE library // and then to Clang itself. // Passing the compiler FE options to clang. if (amdOpts) { for (std::vector::const_iterator it = amdOpts->clangOptions.begin(); it != amdOpts->clangOptions.end(); ++it) { argsToClang.push_back((*it).c_str()); } } if (Options()->oVariables->ImageSupport) { argsToClang.push_back ("-D__IMAGE_SUPPORT__=1 "); } if (Options()->oVariables->FastFMA) { argsToClang.push_back ("-DFP_FAST_FMA=1 "); } if (Options()->oVariables->FastFMAF) { argsToClang.push_back ("-DFP_FAST_FMAF=1 "); } argsToClang.push_back ("-D__AMD__=1 "); // Other options are passed using OptionsInfo structure. clc2::OptionsInfo ClangOptions; ClangOptions.InFilename = inpCLFileName; // Generate target triple. // TODO: Refine the triple as necessary. uint32_t chipName = elf->target.chip_id; assert(chipName < familySet[elf->target.arch_id].children_size && "Cannot index past end of array!"); switch (elf->target.arch_id) { default: log_ += "\nerror: Unknown target device ID!\n"; ret |= 1; return ret; break; case aclX86: case aclAMDIL: case aclHSAIL: // See bug: http://ocltc.amd.com/bugs/show_bug.cgi?id=9631 if (sizeof(void*) != 4) { log_ += "\nerror: 32-bit kernels not supported on a 64-bit executable\n"; ret |= 1; return ret; } ClangOptions.TargetArch = llvm::Triple::spir; break; case aclX64: case aclAMDIL64: case aclHSAIL64: // See bug: http://ocltc.amd.com/bugs/show_bug.cgi?id=9631 if (sizeof(void*) != 8) { log_ += "\nerror: 64-bit kernels not supported on a 32-bit executable\n"; ret |= 1; return ret; } ClangOptions.TargetArch = llvm::Triple::spir64; break; }; // Copy the source to a buffer. Note that the input // file itself is not passed to the ClangOCLFE library. It is a passed // as a string for compilation. llvm::MemoryBuffer *srcBuffer = llvm::MemoryBuffer::getMemBuffer(src, inpCLFileName.c_str(), true); llvm::OwningPtr srcBufferPtr(srcBuffer); ClangOptions.Src.swap(srcBufferPtr); assert(ClangOptions.Src.get() && "ClangOCLFE: Memory Buffer" " initialization error\n"); // Set Pre-processor output if user asks for it. if (amdOpts && amdOpts->isDumpFlagSet(amd::option::DUMP_I)) { ClangOptions.PreProcOut = amdOpts->getDumpFileName(".i"); } // Set the LLVMContext for the front-end compilation. ClangOptions.CompilerContext = &Context(); if (amdOpts && amdOpts->isDumpFlagSet(amd::option::DUMP_CL)) { std::string inpCLFileName = amdOpts->getDumpFileName(".cl"); std::fstream f; f.open(inpCLFileName.c_str(), (std::fstream::out | std::fstream::binary)); f.write(src.data(), src.length()); f.close(); } //Start the compilation uint64_t start_time = 0, stop_time = 0; if (Options()->oVariables->EnableBuildTiming) { start_time = amd::Os::timeNanos(); } if ( #if WITH_VERSION_0_8 !checkFlag(aclutGetCaps(Elf()), capSaveSOURCE) #elif WITH_VERSION_0_9 !Options()->oVariables->BinSOURCE #else #error "The current version was not handled correctly here." #endif ) { CL()->clAPI.remSec(CL(), Elf(), aclSOURCE); } // Pass OpenCL version option to Clang llvm::StringRef OCLVer(amdOpts->oVariables->CLStd); if (OCLVer.equals("CL1.2")) { ClangOptions.OCLVer = clc2::OCL_12; } else if (OCLVer.equals("CL2.0")) { ClangOptions.OCLVer = clc2::OCL_20; } else { llvm_unreachable("Unknown OpenCL version"); } // Call the Clang Front-end to generate serialized llvm::Module // from the OpenCL source. #ifdef ANDROID // We will not exercise Clang for RenderScript. log_ += "\nerror: Clang front-end compilation unsupported on Android!\n"; ret |= 1; return ret; #else if (!parseOCLSource(ClangOptions, argsToClang, &Source(), &logFromClang)) { log_ += logFromClang; log_ += "\nerror: Clang front-end compilation failed!\n"; ret |= 1; return ret; } #endif if (Options()->oVariables->EnableBuildTiming) { stop_time = amd::Os::timeNanos(); std::stringstream tmp_ss; tmp_ss << " OpenCL FE time: " << (stop_time - start_time)/1000ULL << "us\n"; appendLogToCL(CL(), tmp_ss.str()); } llvmbinary_ = loadBitcode(Source()); if (!llvmbinary_) { ret |= 1; } if (!ret) { CL()->clAPI.insSec(CL(), Elf(), Source().data(), Source().size(), aclLLVMIR); } log_ += logFromClang; if (isCpuTarget(Elf()->target) && Options()->oVariables->EnableDebug) { Options()->sourceFileName_ = inpCLFileName; } else { amd::Os::unlink(inpCLFileName.c_str()); } return ret; }