diff options
author | Gil Pitney <gil.pitney@linaro.org> | 2014-10-28 18:00:42 -0700 |
---|---|---|
committer | Gil Pitney <gil.pitney@linaro.org> | 2014-10-28 18:00:42 -0700 |
commit | 61b2c94d9e64758e55730be6a3fc9006c171db85 (patch) | |
tree | f564f09ebf93ba293dfa225bd374df6f1f37aa01 /clocl |
Initial Commit: Based on TI OpenCL v0.8, originally based on clover.shamrock_v0.8
This is a continuation of the clover OpenCL project:
http://people.freedesktop.org/~steckdenis/clover
based on the contributions from Texas Instruments for Keystone II DSP device:
git.ti.com/opencl
and adding contributions from Linaro for ARM CPU-only support.
See README.txt for more info, and build instructions.
Signed-off-by: Gil Pitney <gil.pitney@linaro.org>
Diffstat (limited to 'clocl')
-rw-r--r-- | clocl/.gitignore | 1 | ||||
-rw-r--r-- | clocl/CMakeLists.txt | 14 | ||||
-rw-r--r-- | clocl/Makefile | 100 | ||||
-rw-r--r-- | clocl/compiler.cpp | 270 | ||||
-rw-r--r-- | clocl/compiler.h | 126 | ||||
-rw-r--r-- | clocl/file_manip.cpp | 46 | ||||
-rw-r--r-- | clocl/file_manip.h | 12 | ||||
-rw-r--r-- | clocl/main.cpp | 396 | ||||
-rw-r--r-- | clocl/options.cpp | 223 | ||||
-rw-r--r-- | clocl/options.h | 24 | ||||
-rw-r--r-- | clocl/program.cpp | 189 |
11 files changed, 1401 insertions, 0 deletions
diff --git a/clocl/.gitignore b/clocl/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/clocl/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/clocl/CMakeLists.txt b/clocl/CMakeLists.txt new file mode 100644 index 0000000..e5eec38 --- /dev/null +++ b/clocl/CMakeLists.txt @@ -0,0 +1,14 @@ +if (SHANNON_BUILD OR HAWKING_CROSS_COMPILE) + add_custom_command(OUTPUT x86/clocl COMMAND make -j4 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_custom_target(x86_clocl DEPENDS x86/clocl) + set(CROSS_TARGET cross) + install(PROGRAMS x86/clocl DESTINATION bin/x86 ${OCL_BPERMS}) +endif() + +if (HAWKING_BUILD) + add_custom_command(OUTPUT arm/clocl COMMAND make -j4 ${CROSS_TARGET} TARGET=arm + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_custom_target(arm_clocl DEPENDS arm/clocl) + install(PROGRAMS arm/clocl DESTINATION bin/arm ${OCL_BPERMS}) +endif() diff --git a/clocl/Makefile b/clocl/Makefile new file mode 100644 index 0000000..4ffccb7 --- /dev/null +++ b/clocl/Makefile @@ -0,0 +1,100 @@ +# If not specified, pick a default location for dependent llvm libraries +LLVM_VERSION = 33 + +ifeq ($(DEFAULT_DEV_INSTALL_DIR),) + DEFAULT_DEV_INSTALL_DIR = /opt/ti +endif + +ifeq ($(ARM_LLVM_DIR),) + ARM_LLVM_DIR = $(DEFAULT_DEV_INSTALL_DIR)/llvm$(LLVM_VERSION)-install-arm +endif + +ifeq ($(X86_LLVM_DIR),) + X86_LLVM_DIR = $(DEFAULT_DEV_INSTALL_DIR)/llvm$(LLVM_VERSION)-install-x86 +endif + +CLANG_LIBS = -lclangFrontendTool +CLANG_LIBS += -lclangFrontend +CLANG_LIBS += -lclangDriver +CLANG_LIBS += -lclangSerialization +CLANG_LIBS += -lclangCodeGen +CLANG_LIBS += -lclangParse +CLANG_LIBS += -lclangSema +CLANG_LIBS += -lclangEdit +CLANG_LIBS += -lclangAnalysis +CLANG_LIBS += -lclangAST +CLANG_LIBS += -lclangLex +CLANG_LIBS += -lclangBasic + + +EXE = clocl + +UNAME_M :=$(shell uname -m) +ifneq (,$(findstring 86, $(UNAME_M))) + BUILD_PROCESSOR := x86 + TARGET := x86 + LLVM_DIR := $(X86_LLVM_DIR) + CXX := g++ -m32 +else ifneq (,$(findstring arm, $(UNAME_M))) + BUILD_PROCESSOR := arm + TARGET := arm + LLVM_DIR := $(ARM_LLVM_DIR) + CXX := g++ +endif + +LLVM_CONFIG_EXECUTABLE = $(LLVM_DIR)/bin/llvm-config +LLVM_CXXFLAGS = `${LLVM_CONFIG_EXECUTABLE} --cxxflags ` +LLVM_LDFLAGS = -L $(LLVM_DIR)/lib -lpthread -lrt -ldl -lm +LLVM_LIBS = `${LLVM_CONFIG_EXECUTABLE} --libs ${TARGET} asmparser bitwriter tablegen mcjit debuginfo interpreter irreader jit linker instrumentation ipo mcdisassembler` + +# If Cross Compiling for ARM override some make variables +cross: override CXX=arm-linux-gnueabihf-g++ +cross: override TARGET=arm +cross: override LLVM_CONFIG_EXECUTABLE=$(ARM_LLVM_DIR)/bin/llvm-config-host +cross: override LLVM_LDFLAGS=-L $(ARM_LLVM_DIR)/lib -lpthread -lrt -ldl -lm +# Need to explicitly add /usr/include when cross compiling to pick up +# dependent 3rd party non-system headers +cross: override HOST_USR_INCLUDE=-I/usr/include + + +WGADIR = ../src/core/dsp +POCLDIR = ../src/llvmopencl +OBJS = AllocasToEntry.o BarrierBlock.o BarrierTailReplication.o \ + BreakConstantGEPs.o CanonicalizeBarriers.o Flatten.o \ + GenerateHeader.o ImplicitLoopBarriers.o IsolateRegions.o \ + Kernel.o LLVMUtils.o LoopBarriers.o ParallelRegion.o \ + PHIsToAllocas.o TargetAddressSpaces.o \ + VariableUniformityAnalysis.o WIVectorize.o Workgroup.o \ + WorkItemAliasAnalysis.o WorkitemHandler.o \ + WorkitemHandlerChooser.o WorkitemLoops.o WorkitemReplication.o\ + main.o compiler.o wga.o program.o file_manip.o options.o + +OBJS := $(patsubst %.o, $(TARGET)/%.o, $(OBJS)) + +CXXFLAGS = ${LLVM_CXXFLAGS} -I${WGADIR} -I${POCLDIR} \ + ${HOST_USR_INCLUDE} -O3 -fexceptions +LIBS = ${CLANG_LIBS} ${LLVM_LIBS} +LDFLAGS = ${LLVM_LDFLAGS} + +$(EXE): ${OBJS} + $(CXX) $^ $(LIBS) $(LDFLAGS) -o $(TARGET)/$@ + +cross: $(EXE) + +$(TARGET)/%.o: %.cpp | $(TARGET)/ + $(CXX) $(CXXFLAGS) -c $< -o $@ + +$(TARGET)/%.o: ${WGADIR}/%.cpp | $(TARGET)/ + $(CXX) $(CXXFLAGS) -c $< -o $@ + +$(TARGET)/%.o: ${POCLDIR}/%.cpp | $(TARGET)/ + $(CXX) $(CXXFLAGS) -c $< -o $@ + +$(TARGET)/%.o: ${POCLDIR}/%.cc | $(TARGET)/ + $(CXX) $(CXXFLAGS) -c $< -o $@ + +$(TARGET)/: + mkdir -p $@ + +clean: + rm -f x86/* arm/* diff --git a/clocl/compiler.cpp b/clocl/compiler.cpp new file mode 100644 index 0000000..90ff0ae --- /dev/null +++ b/clocl/compiler.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2011, Denis Steckelmacher <steckdenis@yahoo.fr> + * Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file compiler.cpp + * \brief Compiler wrapper around Clang + */ + +#include "compiler.h" +#include "options.h" + +#include <cstring> +#include <string> +#include <sstream> +#include <iostream> +#include <clang/Frontend/CompilerInvocation.h> +#include <clang/Frontend/TextDiagnosticPrinter.h> +#include <clang/Frontend/LangStandard.h> +#include <clang/Basic/Diagnostic.h> +#include <clang/CodeGen/CodeGenAction.h> +#include <llvm/ADT/SmallVector.h> +#include <llvm/Support/Host.h> +#include <llvm/Support/MemoryBuffer.h> // ASW +#include <llvm/IR/Module.h> +#include <llvm/IR/LLVMContext.h> + +std::string get_ocl_dsp(); + +Compiler::Compiler() +: p_module(0), p_optimize(true), p_log_stream(p_log), + p_log_printer(0) +{ +} + +Compiler::~Compiler() +{ + +} + +bool Compiler::compile(const std::string &options, + llvm::MemoryBuffer *source, + std::string filename) +{ + /* Set options */ + p_options = options; + + clang::CodeGenOptions &codegen_opts = p_compiler.getCodeGenOpts(); + clang::DiagnosticOptions &diag_opts = p_compiler.getDiagnosticOpts(); + clang::FrontendOptions &frontend_opts = p_compiler.getFrontendOpts(); + clang::HeaderSearchOptions &header_opts = p_compiler.getHeaderSearchOpts(); + clang::LangOptions &lang_opts = p_compiler.getLangOpts(); + clang::TargetOptions &target_opts = p_compiler.getTargetOpts(); + clang::PreprocessorOptions &prep_opts = p_compiler.getPreprocessorOpts(); + clang::CompilerInvocation &invocation = p_compiler.getInvocation(); + + // Set codegen options + codegen_opts.setDebugInfo(clang::CodeGenOptions::NoDebugInfo); + codegen_opts.AsmVerbose = true; + + // level 3 is too much for the pocl transformations. + codegen_opts.OptimizationLevel = 2; + + // Set diagnostic options + diag_opts.Pedantic = true; + diag_opts.ShowColumn = true; + diag_opts.ShowLocation = true; + diag_opts.ShowCarets = false; + diag_opts.ShowFixits = true; + diag_opts.ShowColors = false; + diag_opts.ErrorLimit = 19; + diag_opts.MessageLength = 0; + + // Set frontend options + frontend_opts.ProgramAction = clang::frontend::EmitLLVMOnly; + frontend_opts.DisableFree = true; + + // Set header search options + header_opts.Verbose = false; + header_opts.UseBuiltinIncludes = false; + header_opts.UseStandardSystemIncludes = false; + header_opts.UseStandardCXXIncludes = false; + + // Set preprocessor options + prep_opts.RetainRemappedFileBuffers = true; + if (!opt_builtin) + { + prep_opts.Includes.push_back("clc.h"); + prep_opts.Includes.push_back("dsp.h"); + } + + // Set lang options + lang_opts.NoBuiltin = true; + lang_opts.OpenCL = true; + lang_opts.CPlusPlus = false; + + // Set target options + // For 6X, use the 'spir' target as it implements opencl specs + target_opts.Triple = "spir-unknown-unknown-unknown"; + + // Currently, llp6x does not handle fused multiply and add + // llvm intrinsics (llvm.fmuladd.*). Disable generating these + // intrinsics using clang -ffp-contract=off option + codegen_opts.setFPContractMode(clang::CodeGenOptions::FPC_Off); + + // Parse the user options + std::istringstream options_stream(options); + std::string token; + bool Werror = false, inI = false, inD = false; + + /*------------------------------------------------------------------------- + * Add OpenCL C header path as a default location for searching for headers + *------------------------------------------------------------------------*/ + header_opts.AddPath(get_ocl_dsp(), clang::frontend::Angled, false, false); + + while (options_stream >> token) + { + if (inI) + { + // token is an include path + header_opts.AddPath(token, clang::frontend::Angled, false, false); + inI = false; + continue; + } + else if (inD) + { + // token is name or name=value + prep_opts.addMacroDef(token); + } + + if (token == "-I") + { + inI = true; + } + else if (token == "-D") + { + inD = true; + } + else if (token == "-cl-single-precision-constant") + { + lang_opts.SinglePrecisionConstants = true; + } + else if (token == "-cl-opt-disable") + { + p_optimize = false; + codegen_opts.OptimizationLevel = 0; + } + else if (token == "-cl-mad-enable") + { + codegen_opts.LessPreciseFPMAD = true; + } + else if (token == "-cl-unsafe-math-optimizations") + { + codegen_opts.UnsafeFPMath = true; + } + else if (token == "-cl-finite-math-only") + { + codegen_opts.NoInfsFPMath = true; + codegen_opts.NoNaNsFPMath = true; + } + else if (token == "-cl-fast-relaxed-math") + { + codegen_opts.UnsafeFPMath = true; + codegen_opts.NoInfsFPMath = true; + codegen_opts.NoNaNsFPMath = true; + lang_opts.FastRelaxedMath = true; + } + else if (token == "-w") + { + diag_opts.IgnoreWarnings = true; + } + else if (token == "-Werror") + { + Werror = true; + } + } + + // Set invocation options + //invocation.setLangDefaults(lang_opts,clang::IK_OpenCL); + invocation.setLangDefaults(lang_opts,clang::IK_OpenCL, clang::LangStandard::lang_opencl12); + + // Create the diagnostics engine + p_log_printer = new clang::TextDiagnosticPrinter(p_log_stream, &diag_opts); + p_compiler.createDiagnostics(p_log_printer); + + if (!p_compiler.hasDiagnostics()) + return false; + + p_compiler.getDiagnostics().setWarningsAsErrors(Werror); + + // Feed the compiler with source + frontend_opts.Inputs.push_back(clang::FrontendInputFile(filename.c_str(), clang::IK_OpenCL)); + + std::string srcc = source->getBuffer(); + const llvm::StringRef s_data(srcc); + const llvm::StringRef s_name("<source>"); + llvm::MemoryBuffer *buffer = + llvm::MemoryBuffer::getMemBuffer(s_data, s_name); + + prep_opts.addRemappedFile(filename.c_str(), buffer); + + // Compile + llvm::OwningPtr<clang::CodeGenAction> act( + new clang::EmitLLVMOnlyAction(&llvm::getGlobalContext()) + ); + + if (!p_compiler.ExecuteAction(*act)) + { + // DEBUG + std::cout << log() << std::endl; + return false; + } + + p_log_stream.flush(); + p_module = act->takeModule(); + + // uncomment to debug the llvm IR + // p_module->dump(); + + return true; +} + +const std::string &Compiler::log() const +{ + return p_log; +} + +const std::string &Compiler::options() const +{ + return p_options; +} + +bool Compiler::optimize() const +{ + return p_optimize; +} + +llvm::Module *Compiler::module() const +{ + return p_module; +} + +void Compiler::appendLog(const std::string &log) +{ + p_log += log; +} diff --git a/clocl/compiler.h b/clocl/compiler.h new file mode 100644 index 0000000..2195cc2 --- /dev/null +++ b/clocl/compiler.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2011, Denis Steckelmacher <steckdenis@yahoo.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file compiler.h + * \brief Compiler wrapped around Clang + */ + +#ifndef __COMPILER_H__ +#define __COMPILER_H__ + +#include <string> + +#include <clang/Frontend/CompilerInstance.h> +#include <llvm/Support/raw_ostream.h> + +namespace llvm +{ + class MemoryBuffer; + class Module; +} + +namespace clang +{ + class TextDiagnosticPrinter; +} + + +/** + * \brief Compiler using Clang + * + * This class builds a Clang instance, runs it and then retains compilation logs + * and produced data. + */ +class Compiler +{ + public: + /** + * \brief Constructor + */ + Compiler(); + ~Compiler(); + + /** + * \brief Compile \p source to produce a LLVM module + * \param options options given to the compiler, described in the OpenCL spec + * \param source source to be compiled + * \return true if the compilation is successful, false otherwise + * \sa module() + * \sa log() + */ + bool compile(const std::string &options, llvm::MemoryBuffer *source, + std::string filename); + + /** + * \brief Compilation log + * \note \c appendLog() can also be used to append custom info at the end + * of the log, for instance to keep compilation and linking logs + * in the same place + * \return log + */ + const std::string &log() const; + + /** + * \brief Options given at \c compile() + * \return options used during compilation + */ + const std::string &options() const; + + /** + * \brief Optimization enabled + * \return true if -cl-opt-disable was given in the options, false otherwise + */ + bool optimize() const; + + /** + * \brief LLVM module generated + * \return LLVM module generated by the compilation, 0 if an error occured + */ + llvm::Module *module() const; + + /** + * \brief Append a string to the log + * + * This function can be used to append linking or code-gen logs to the + * internal compilation log kept by this class + * + * \param log log to be appended + */ + void appendLog(const std::string &log); + + private: + clang::CompilerInstance p_compiler; + llvm::Module *p_module; + bool p_optimize; + + std::string p_log, p_options; + llvm::raw_string_ostream p_log_stream; + clang::TextDiagnosticPrinter *p_log_printer; +}; + +#endif diff --git a/clocl/file_manip.cpp b/clocl/file_manip.cpp new file mode 100644 index 0000000..5a51f16 --- /dev/null +++ b/clocl/file_manip.cpp @@ -0,0 +1,46 @@ +#include "file_manip.h" +#include <unistd.h> + +bool fs_exists(std::string path) +{ + return (access(path.c_str(), F_OK) == 0); +} + +std::string fs_filename(std::string path) +{ + int name_begin = path.rfind("/"); + if (name_begin == std::string::npos) return path; + return path.substr(name_begin+1, path.size()-name_begin+1); +} + +std::string fs_stem(std::string path) +{ + path = fs_filename(path); + int ext_begin = path.rfind("."); + if (ext_begin == std::string::npos) return path; + return path.substr(0, ext_begin); +} + +std::string fs_ext(std::string path) +{ + int ext_begin = path.rfind("."); + if (ext_begin == std::string::npos) return ""; + return path.substr(ext_begin, path.size()-ext_begin); +} + +std::string fs_path(std::string path) +{ + int path_end = path.rfind("/"); + if (path_end == std::string::npos) return ""; + return path.substr(0, path_end+1); +} + +std::string fs_replace_extension(std::string path, std::string ext) +{ + if (fs_ext(path) == "") return path; + + path = fs_path(path) + fs_stem(path); + + if (ext[0] == '.') return path + ext; + else return path + "." + ext; +} diff --git a/clocl/file_manip.h b/clocl/file_manip.h new file mode 100644 index 0000000..7084239 --- /dev/null +++ b/clocl/file_manip.h @@ -0,0 +1,12 @@ +#ifndef _FILE_MANIP_H_ +#define _FILE_MANIP_H_ +#include <string> + +bool fs_exists (std::string path); +std::string fs_filename (std::string path); +std::string fs_stem (std::string path); +std::string fs_ext (std::string path); +std::string fs_path (std::string path); +std::string fs_replace_extension(std::string path, std::string ext); + +#endif // _FILE_MANIP_H_ diff --git a/clocl/main.cpp b/clocl/main.cpp new file mode 100644 index 0000000..05f0925 --- /dev/null +++ b/clocl/main.cpp @@ -0,0 +1,396 @@ +/****************************************************************************** + * Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Texas Instruments Incorporated nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#include <iostream> +#include <iomanip> +#include <string> +#include <fstream> +#include <sstream> +#include <cstdlib> +#include <sys/stat.h> + +#include <llvm/Bitcode/ReaderWriter.h> +#include <llvm/PassManager.h> +#include <llvm/Analysis/Passes.h> +#include <llvm/Analysis/Verifier.h> +#include <llvm/Transforms/Scalar.h> +#include <llvm/Transforms/IPO.h> +#include <llvm/Transforms/Utils/UnifyFunctionExitNodes.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/ADT/StringRef.h> +#include <llvm/ADT/SmallVector.h> +#include <llvm/Support/MemoryBuffer.h> +#include <llvm/Support/Casting.h> +#include <llvm/Bitcode/ReaderWriter.h> +#include <llvm/IR/LLVMContext.h> +#include <llvm/IR/Module.h> +#include <llvm/Linker.h> +#include <llvm/IR/Metadata.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/Instructions.h> +#include <llvm/Support/InstIterator.h> + +#include "compiler.h" +#include "wga.h" +#include "file_manip.h" +#include "options.h" + +#include <WorkitemHandlerChooser.h> +#include <BreakConstantGEPs.h> +#include <Flatten.h> +#include <PHIsToAllocas.h> +#include <IsolateRegions.h> +#include <VariableUniformityAnalysis.h> +#include <ImplicitLoopBarriers.h> +#include <LoopBarriers.h> +#include <BarrierTailReplication.h> +#include <CanonicalizeBarriers.h> +#include <WorkItemAliasAnalysis.h> +#include <WorkitemReplication.h> +#include <WorkitemLoops.h> +#include <AllocasToEntry.h> +#include <Workgroup.h> +#include <TargetAddressSpaces.h> + +using namespace std; +using llvm::Module; + +bool prepend_headers(string filename, string& source); +bool run_clang (string filename, string source, Compiler &compiler, + Module **module, string& binary); +bool llvm_xforms (Module *module, bool optimize); +bool cl6x (string& filename, string &binary_str); + +int run_cl6x (string filename, string *llvm_bitcode, string options); +void write_binary (string filename, const char *buf, int size); +void write_text (string filename); + + +void write_bitcode(string filename, Module* module) +{ + string bc_file(fs_filename(fs_replace_extension(filename, ".bc"))); + string err_info; + + llvm::raw_fd_ostream file_ostream(bc_file.c_str(), err_info); + llvm::WriteBitcodeToFile(module, file_ostream); + file_ostream.flush(); +} + +/****************************************************************************** +* main +******************************************************************************/ +int main(int argc, char *argv[]) +{ + process_options(argc, argv); + + if (files_clc.empty()) return 0; + + string filename = files_clc[0]; + string source; // OpenCL C program source + string binary; // Untransformed LLVM bitcode (still per workitem) + Module *module; // module, evolves during transformation + Compiler compiler; + + if (!prepend_headers(filename, source)) exit(-1); + if (!run_clang (filename, source, compiler, &module, binary)) exit(-1); + if (!llvm_xforms (module, compiler.optimize())) exit(-1); + + write_bitcode(filename, module); + + if (!cl6x (filename, binary)) exit(-1); + + if (opt_txt) write_text(filename); +} + + + +/****************************************************************************** +* prepend_headers +******************************************************************************/ +bool prepend_headers(string filename, string& source) +{ + /*--------------------------------------------------------------------- + * Compile the Kernel Source for the device + *--------------------------------------------------------------------*/ + if (!fs_exists(filename)) + { cout << "File " << filename << " doesn't exist" << endl; return false; } + + stringstream userSrc; + userSrc << ifstream(filename.c_str()).rdbuf(); + + /*------------------------------------------------------------------------- + * Prepend OpenCL header info into the source + *------------------------------------------------------------------------*/ + source = userSrc.str(); + return true; +} + +/****************************************************************************** +* run_clang +******************************************************************************/ +bool run_clang(string filename, string source, Compiler &compiler, + Module **module, string& binary) +{ + using llvm::MemoryBuffer; + using llvm::StringRef; + + const StringRef s_data(source); + const StringRef s_name("<source>"); + + MemoryBuffer *buffer = MemoryBuffer::getMemBuffer(s_data, s_name); + + if (opt_verbose) cout << "clang options: " << cl_options << endl; + if (!compiler.compile(cl_options, buffer, filename)) + return false; + + *module = compiler.module(); + + llvm::raw_string_ostream str_ostream(binary); + llvm::WriteBitcodeToFile(*module, str_ostream); + str_ostream.flush(); + + return true; +} + +/****************************************************************************** +* llvm_xforms +******************************************************************************/ +bool llvm_xforms(Module *module, bool optimize) +{ + // Get list of kernels to strip other unused functions + vector<const char *> api; + vector<string> api_s; // Needed to keep valid data in api + + llvm::NamedMDNode *kern_meta = module->getNamedMetadata("opencl.kernels"); + + for (unsigned int i=0; kern_meta && i < kern_meta->getNumOperands(); ++i) + { + llvm::MDNode *node = kern_meta->getOperand(i); + llvm::Value *value = node->getOperand(0); + if (!llvm::isa<llvm::Function>(value)) continue; + + llvm::Function *f = llvm::cast<llvm::Function>(value); + string s = f->getName().str(); + api_s.push_back(s); + api.push_back(s.c_str()); + } + + // determine if module has barrier() function calls + bool hasBarrier = false; + llvm::CallInst* call; + for (Module::iterator F = module->begin(), + EF = module->end(); !hasBarrier && F != EF; ++F) + for (llvm::inst_iterator I = inst_begin(*F), + E = inst_end(*F); I != E; ++I) + { + if (!(call = llvm::dyn_cast<llvm::CallInst>(&*I))) continue; + if (!call->getCalledFunction()) continue; + string name(call->getCalledFunction()->getName()); + if (name == "barrier") + { + hasBarrier = true; + break; + } + } + + // Optimize code + llvm::PassManager *manager = new llvm::PassManager(); + + // Common passes (primary goal : remove unused stdlib functions) + manager->add(llvm::createTypeBasedAliasAnalysisPass()); + manager->add(llvm::createBasicAliasAnalysisPass()); + + /*------------------------------------------------------------------------- + * Do not run this for lib mode as it will result in all functions + * being removed if main not found. + *------------------------------------------------------------------------*/ + if (!opt_lib) manager->add(llvm::createInternalizePass(api)); + + manager->add(llvm::createIPSCCPPass()); + manager->add(llvm::createGlobalOptimizerPass()); + manager->add(llvm::createConstantMergePass()); + manager->add(llvm::createAlwaysInlinerPass()); + + // pocl barrier transformation + if (hasBarrier) + { + manager->add(new llvm::DominatorTree()); + manager->add(new pocl::WorkitemHandlerChooser()); + manager->add(new BreakConstantGEPs()); // from pocl + // add(new GenerateHeader()); // no need + manager->add(new pocl::Flatten()); + manager->add( llvm::createAlwaysInlinerPass()); + manager->add( llvm::createGlobalDCEPass()); + manager->add( llvm::createCFGSimplificationPass()); + manager->add( llvm::createLoopSimplifyPass()); + manager->add(new pocl::PHIsToAllocas()); + manager->add( llvm::createRegionInfoPass()); + manager->add(new pocl::IsolateRegions()); + manager->add(new pocl::VariableUniformityAnalysis()); // TODO + manager->add(new pocl::ImplicitLoopBarriers()); + manager->add(new pocl::LoopBarriers()); + manager->add(new pocl::BarrierTailReplication()); + manager->add(new pocl::CanonicalizeBarriers()); + manager->add(new pocl::IsolateRegions()); + manager->add(new pocl::WorkItemAliasAnalysis()); + // add(new pocl::WorkitemReplication()); // no need + manager->add(new pocl::WorkitemLoops()); + manager->add(new pocl::AllocasToEntry()); + // add(new pocl::Workgroup()); // no need + manager->add(new pocl::TargetAddressSpaces()); + } + + if (optimize) + { + /*--------------------------------------------------------------------- + * Inspired by code from "The LLVM Compiler Infrastructure" + *--------------------------------------------------------------------*/ + manager->add(llvm::createDeadArgEliminationPass()); + manager->add(llvm::createInstructionCombiningPass()); + manager->add(llvm::createFunctionInliningPass()); + manager->add(llvm::createPruneEHPass()); // Remove dead EH info. + manager->add(llvm::createGlobalOptimizerPass()); + manager->add(llvm::createGlobalDCEPass()); // Remove dead functions. + manager->add(llvm::createArgumentPromotionPass()); + manager->add(llvm::createInstructionCombiningPass()); + manager->add(llvm::createJumpThreadingPass()); + + //ASW TODO maybe turn off re: pete. might gen bad xlator input + //manager->add(llvm::createScalarReplAggregatesPass()); + + manager->add(llvm::createFunctionAttrsPass()); // Add nocapture. + manager->add(llvm::createGlobalsModRefPass()); // IP alias analysis. + manager->add(llvm::createLICMPass()); // Hoist loop invariants. + manager->add(llvm::createGVNPass()); // Remove redundancies. + manager->add(llvm::createMemCpyOptPass()); // Remove dead memcpys. + manager->add(llvm::createDeadStoreEliminationPass()); + manager->add(llvm::createInstructionCombiningPass()); + manager->add(llvm::createJumpThreadingPass()); + manager->add(llvm::createCFGSimplificationPass()); + } + + /*------------------------------------------------------------------------- + * Builtins will not have workitem functions and do not need wga + *------------------------------------------------------------------------*/ + if (!opt_builtin) + { + manager->add(llvm::createUnifyFunctionExitNodesPass()); + manager->add(llvm::createTIOpenclWorkGroupAggregationPass(hasBarrier)); + + /*--------------------------------------------------------------------- + * Borrow the pocl alloca hoister for the TI simplistic WGA pass as well + *--------------------------------------------------------------------*/ + if (!hasBarrier) + manager->add(new pocl::AllocasToEntry()); + } + + manager->add(llvm::createGlobalDCEPass()); + manager->run(*module); + delete manager; + + return true; +} + + +/****************************************************************************** +* cl6x +******************************************************************************/ +bool cl6x(string& filename, string &binary_str) +{ + string bc_file_full(fs_replace_extension(filename, ".bc")); + string bc_file (fs_filename(bc_file_full)); + + run_cl6x(bc_file, &binary_str, files_other); + + /*------------------------------------------------------------------------- + * Clean up temporary files + *------------------------------------------------------------------------*/ + struct stat statbuf; + if (!opt_keep) + { + const char *name = bc_file_full.c_str(); + + unlink(name); + + if (!opt_lib) + { + name = fs_replace_extension(bc_file_full, ".obj").c_str(); + unlink(name); + } + + string bitasm_name(fs_stem(bc_file_full)); + bitasm_name += "_bc.asm"; + name = bitasm_name.c_str(); + + unlink(name); + + bitasm_name =fs_stem(bc_file_full); + bitasm_name += "_bc.obj"; + name = bitasm_name.c_str(); + + unlink(name); + } + + return true; +} + +/****************************************************************************** +* write_text +******************************************************************************/ +void write_text(string filename) +{ + filename = fs_filename(filename); + string outfile(fs_replace_extension(filename, ".out")); + string hfile (fs_replace_extension(filename, ".dsp_h")); + + stringstream bufss; + bufss << ifstream(outfile.c_str()).rdbuf(); + + string buf(bufss.str()); + + ofstream header(hfile.c_str(), ios::out); + + header << "unsigned int " << fs_stem(filename) + << "_dsp_bin_len = " << buf.length() << ";" + << endl; + + header << "char " << fs_stem(filename) << "_dsp_bin[] = { "; + + int val = buf[0] & 0xff; + header << "0x"<< hex << setfill('0') << setw(2) << nouppercase <<val<<endl; + + for (int i = 1; i < buf.length(); i++) + { + val = buf[i] & 0xff; + header << ", 0x"<< hex << setfill('0') << setw(2) << nouppercase <<val; + if (i % 13 == 0) header << endl; + } + + header << endl << "};" << endl; + header.close(); +} + diff --git a/clocl/options.cpp b/clocl/options.cpp new file mode 100644 index 0000000..a6d9a87 --- /dev/null +++ b/clocl/options.cpp @@ -0,0 +1,223 @@ +#include <stdio.h> /* for printf */ +#include <stdlib.h> /* for exit */ +#include <getopt.h> + +#include <string> +#include <vector> +#include <iostream> +#include <iterator> +#include <algorithm> + +#include "file_manip.h" + +using std::cout; +using std::endl; +using std::string; +using std::vector; +using std::ostream_iterator; + +int opt_help = 0; +int opt_verbose = 0; +int opt_keep = 0; +int opt_debug = 0; +int opt_lib = 0; +int opt_txt = 0; +int opt_w = 0; +int opt_Werror = 0; +int opt_builtin = 0; + +string cl_options; +string cl_incdef; +string opts_other; +vector<string> files_clc; +vector<string> files_c; +string files_other; + +/****************************************************************************** +* void print_options() +******************************************************************************/ +void print_options() +{ + cout << endl; + + if (opt_keep) printf ("Option keep : on\n"); + if (opt_debug) printf ("Option debug : on\n"); + if (opt_lib) printf ("Option lib : on\n"); + if (opt_txt) printf ("Option txt : on\n"); + if (opt_w) printf ("Option w : on\n"); + if (opt_Werror) printf ("Option Werror : on\n"); + //if (opt_builtin) printf ("Option builtin: on\n"); + + cout << endl; + + cout << "CL C Options : " << cl_options << endl; + cout << "Incls/Defines : " << cl_incdef << endl; + cout << "CL C file : " << files_clc[0] << endl; + cout << "Link Files : " << files_other << endl; + + cout << endl; + + cout << "Ignored Opts : " << opts_other << endl; + cout << "Ignored Files : "; + if (files_clc.size() > 1) + copy(files_clc.begin()+1, files_clc.end(), ostream_iterator<string>(cout, " ")); + + copy(files_c.begin(), files_c.end(), ostream_iterator<string>(cout, " ")); + cout << endl << endl; +} + +/****************************************************************************** +* void print_help() +******************************************************************************/ +void print_help() +{ + cout << endl; + cout << "Usage: clocl [options] <OpenCL C file> [<link files>]" << endl; + cout << endl; + + cout << "Options passed to clocl are either options to control" << endl; + cout << "clocl behavior or they are documented OpenCL 1.1 build" << endl; + cout << "options." << endl; + cout << endl; + cout << "The clocl behavior options are: " << endl; + cout << " -h, --help : Print this help screen" << endl; + cout << " -v, --verbose : Print verbose messages" << endl; + cout << " -k, --keep : Do not delete temp compilation files" << endl; + cout << " -g, --debug : Generate debug symbols" << endl; + cout << " -t, --txt : Generate object in header form" << endl; + cout << " -l, --lib : Do not link. Stop after compilation." << endl; + cout << endl; + cout << "The OpenCL 1.1 build options. Refer to 1.1 spec for desc:" << endl; + cout << " -D<name>" << endl; + cout << " -D<name>=<val>" << endl; + cout << " -I<dir>" << endl; + cout << " -w" << endl; + cout << " -Werror" << endl; + cout << " -cl-single-precision-constant" << endl; + cout << " -cl-denorms-are-zero" << endl; + cout << " -cl-opt-disable" << endl; + cout << " -cl-mad-enable" << endl; + cout << " -cl-no-signed-zeros" << endl; + cout << " -cl-unsafe-math-optimizations" << endl; + cout << " -cl-finite-math-only" << endl; + cout << " -cl-fast-relaxed-math" << endl; + cout << " -cl-std=<val>" << endl; + cout << endl; + exit(-1); +} + +/****************************************************************************** +* void process_options(int argc, char **argv) +******************************************************************************/ +void process_options(int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + static struct option long_options[] = { + + /*----------------------------------------------------------------- + * clocl options + *----------------------------------------------------------------*/ + {"help", no_argument, &opt_help, 'h' }, + {"verbose", no_argument, &opt_verbose, 'v' }, + {"keep", no_argument, &opt_keep, 'k' }, + {"debug", no_argument, &opt_debug, 'g' }, + {"lib", no_argument, &opt_lib, 'l' }, + {"txt", no_argument, &opt_txt, 't' }, + {"builtin", no_argument, &opt_builtin, 'b' }, + + /*----------------------------------------------------------------- + * opencl 1.1 options + *----------------------------------------------------------------*/ + {"Werror", no_argument, 0, 0 }, + {"cl-std", required_argument, 0, 0 }, + {"cl-single-precision-constant", no_argument, 0, 0 }, + {"cl-denorms-are-zero", no_argument, 0, 0 }, + {"cl-opt-disable", no_argument, 0, 0 }, + {"cl-mad-enable", no_argument, 0, 0 }, + {"cl-no-signed-zeros", no_argument, 0, 0 }, + {"cl-unsafe-math-optimizations", no_argument, 0, 0 }, + {"cl-finite-math-only", no_argument, 0, 0 }, + {"cl-fast-relaxed-math", no_argument, 0, 0 }, + {0, 0, 0, 0 } + }; + + int this_option_optind = optind ? optind : 1; + int option_index = 0; + + opterr = 0; // prevent getopt from printing warnings + + c = getopt_long_only(argc, argv, "-gwI:D:", long_options, + &option_index); + if (c == -1) break; + + switch (c) + { + case 0: + { + string name(long_options[option_index].name); + + if (name == "help" || name == "verbose" || + name == "keep" || name == "debug" || + name == "lib" || name == "txt" || + name == "builtin") break; + + if (name == "cl-std") + { + cl_options += " -cl-std="; + cl_options += optarg; + break; + } + + if (name == "Werror") opt_Werror = 1; // fall-through + if (name == "cl-opt-disable") opt_debug = 1; // fall-through + + cl_options += " "; + cl_options += argv[this_option_optind]; + break; + } + + case 1: + { + string fname(argv[this_option_optind]); + string ext(fs_ext(fname)); + + if (ext == ".clc") files_clc.push_back(fname); + else if (ext == ".cl") files_clc.push_back(fname); + else if (ext == ".c") files_c.push_back(fname); + else { files_other += fname; files_other += " "; } + + break; + } + + case 'g': opt_debug = 1; break; + case 'w': opt_w = 1; cl_options += " -w"; break; + + case 'D': + case 'I': + cl_incdef += " -"; + cl_incdef += c; + cl_incdef += optarg; + break; + + case '?': + opts_other += " "; + opts_other += argv[this_option_optind]; + break; + + default: + opts_other += " -"; + opts_other += c; + break; + } + } + + if (opt_verbose) print_options(); + if (opt_help) print_help(); + + cl_options += " "; + cl_options += cl_incdef; +} diff --git a/clocl/options.h b/clocl/options.h new file mode 100644 index 0000000..086e49c --- /dev/null +++ b/clocl/options.h @@ -0,0 +1,24 @@ +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +#include <string> + +extern int opt_help; +extern int opt_verbose; +extern int opt_keep; +extern int opt_debug; +extern int opt_lib; +extern int opt_txt; +extern int opt_w; +extern int opt_Werror; +extern int opt_builtin; + +extern std::string cl_options; +extern std::string cl_incdef; +extern std::vector<std::string> files_clc; +extern std::vector<std::string> files_c; +extern std::string files_other; + +void process_options(int argc, char **argv); + +#endif //_OPTIONS_H_ diff --git a/clocl/program.cpp b/clocl/program.cpp new file mode 100644 index 0000000..0674bbe --- /dev/null +++ b/clocl/program.cpp @@ -0,0 +1,189 @@ +/****************************************************************************** + * Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Texas Instruments Incorporated nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#include <llvm/PassManager.h> +#include <llvm/Analysis/Passes.h> +#include <llvm/Analysis/Verifier.h> +#include <llvm/Transforms/Scalar.h> +#include <llvm/Transforms/IPO.h> +#include <llvm/Transforms/Utils/UnifyFunctionExitNodes.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/Bitcode/ReaderWriter.h> +#include "wga.h" +#include "file_manip.h" +#include "options.h" + +#include <string> +#include <iostream> +#include <fstream> +#include <sstream> +#include <stdio.h> +#include <stdlib.h> +#include <vector> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <elf.h> + +using namespace std; + +/****************************************************************************** +* Find the C6000 CGT installation +******************************************************************************/ +char *get_cgt_install() +{ + char *install = getenv("TI_OCL_CGT_INSTALL"); + if (!install) + { + std::cout << + "The environment variable TI_OCL_CGT_INSTALL must be set to a " + << std::endl << + "directory path where the C6000 compiler tools are installed. " + << std::endl; + + abort(); + } + + return install; +} + +/****************************************************************************** +* Find the OpenCL installation +******************************************************************************/ +char *get_ocl_install() +{ + char *install = getenv("TI_OCL_INSTALL"); + if (!install) + { + std::cout << + "The environment variable TI_OCL_INSTALL must be set to a " + << std::endl << + "directory path where the TI OpenCL product is installed. " + << std::endl; + + abort(); + } + + return install; +} + +std::string get_ocl_dsp() +{ + const char *stdpath = "/usr/share/ti/opencl/dsp"; + + struct stat st; + stat(stdpath, &st); + if (S_ISDIR(st.st_mode)) return stdpath; + + std::string sinstall = string(get_ocl_install()) + "/dsp"; + return sinstall; +} + +/****************************************************************************** +* run_cl6x +******************************************************************************/ +int run_cl6x(string filename, string *llvm_bitcode, string addl_files) +{ + string command("cl6x --f -q --abi=eabi --use_g3 -mv6600 -mt -mo "); + + if (opt_keep) command += "-mw -k --z "; + + command += "--disable:sploop "; + + if (opt_debug) command += "-g -o0 "; + else command += "-o3 "; + + const char *cgt_install = get_cgt_install(); + + command += "-I"; command += cgt_install; command += "/include "; + command += "-I"; command += cgt_install; command += "/lib "; + command += "-I"; command += get_ocl_dsp().c_str(); command += " "; + + command += "--bc_file="; command += filename; command += " "; + + /*------------------------------------------------------------------------- + * Encode LLVM bitcode as bytes in the .llvmir section of the .asm file + *------------------------------------------------------------------------*/ + if (llvm_bitcode != NULL) + { + string bitasm_name(fs_stem(filename)); + bitasm_name += "_bc.asm"; + + ofstream outasmfile(bitasm_name.c_str(), ios::out); + outasmfile << "\t.sect \".llvmir\"\n" << "\t.retain"; + int nbytes = llvm_bitcode->size(); + for (int i = 0; i < nbytes; i++) + if (i % 10 == 0) + outasmfile << "\n\t.byte " << (int) llvm_bitcode->at(i); + else + outasmfile << ", " << (int) llvm_bitcode->at(i); + outasmfile.close(); + + command += bitasm_name; command += " "; + } + + if (opt_lib) + { + if (opt_verbose) cout << command << endl; + int x = system(command.c_str()); + return true; + } + + string outfile(fs_replace_extension(filename, ".out")); + + command += "-z "; + command += "-o "; + command += outfile; + command += " "; + + if (opt_keep) + { + command += "-m "; + command += fs_replace_extension(filename, ".map"); + command += " "; + } + + /*------------------------------------------------------------------------- + * Any libraries or object files need to go last to resolve references + *------------------------------------------------------------------------*/ + command += addl_files; + command += " -ldsp.syms "; + + if (opt_verbose) cout << command << endl; + int x = system(command.c_str()); + + if (!opt_debug) + { + string strip_command("strip6x "); + strip_command += outfile; + if (opt_verbose) cout << strip_command << endl; + x = system(strip_command.c_str()); + } +} |