Home | History | Annotate | Download | only in radeon
      1 /*
      2  * Copyright 2011 Advanced Micro Devices, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  *
     23  * Authors: Tom Stellard <thomas.stellard (at) amd.com>
     24  *
     25  */
     26 #include "radeon_llvm_emit.h"
     27 
     28 #include <llvm/LLVMContext.h>
     29 #include <llvm/Module.h>
     30 #include <llvm/PassManager.h>
     31 #include <llvm/ADT/Triple.h>
     32 #include <llvm/Support/FormattedStream.h>
     33 #include <llvm/Support/Host.h>
     34 #include <llvm/Support/IRReader.h>
     35 #include <llvm/Support/SourceMgr.h>
     36 #include <llvm/Support/TargetRegistry.h>
     37 #include <llvm/Support/TargetSelect.h>
     38 #include <llvm/Support/Threading.h>
     39 #include <llvm/Target/TargetData.h>
     40 #include <llvm/Target/TargetMachine.h>
     41 
     42 #include <llvm/Transforms/Scalar.h>
     43 
     44 #include <llvm-c/Target.h>
     45 
     46 #include <iostream>
     47 #include <stdlib.h>
     48 #include <stdio.h>
     49 
     50 using namespace llvm;
     51 
     52 #ifndef EXTERNAL_LLVM
     53 extern "C" {
     54 
     55 void LLVMInitializeAMDGPUAsmPrinter(void);
     56 void LLVMInitializeAMDGPUTargetMC(void);
     57 void LLVMInitializeAMDGPUTarget(void);
     58 void LLVMInitializeAMDGPUTargetInfo(void);
     59 }
     60 #endif
     61 
     62 namespace {
     63 
     64 class LLVMEnsureMultithreaded {
     65 public:
     66    LLVMEnsureMultithreaded()
     67    {
     68       llvm_start_multithreaded();
     69    }
     70 };
     71 
     72 static LLVMEnsureMultithreaded lLVMEnsureMultithreaded;
     73 
     74 }
     75 
     76 /**
     77  * Compile an LLVM module to machine code.
     78  *
     79  * @param bytes This function allocates memory for the byte stream, it is the
     80  * caller's responsibility to free it.
     81  */
     82 extern "C" unsigned
     83 radeon_llvm_compile(LLVMModuleRef M, unsigned char ** bytes,
     84                  unsigned * byte_count, const char * gpu_family,
     85                  unsigned dump) {
     86 
     87    Triple AMDGPUTriple(sys::getDefaultTargetTriple());
     88 
     89 #ifdef EXTERNAL_LLVM
     90    /* XXX: Can we just initialize the AMDGPU target here? */
     91    InitializeAllTargets();
     92    InitializeAllTargetMCs();
     93 #else
     94    LLVMInitializeAMDGPUTargetInfo();
     95    LLVMInitializeAMDGPUTarget();
     96    LLVMInitializeAMDGPUTargetMC();
     97    LLVMInitializeAMDGPUAsmPrinter();
     98 #endif
     99    std::string err;
    100    const Target * AMDGPUTarget = TargetRegistry::lookupTarget("r600", err);
    101    if(!AMDGPUTarget) {
    102       fprintf(stderr, "Can't find target: %s\n", err.c_str());
    103       return 1;
    104    }
    105 
    106    Triple::ArchType Arch = Triple::getArchTypeForLLVMName("r600");
    107    if (Arch == Triple::UnknownArch) {
    108       fprintf(stderr, "Unknown Arch\n");
    109    }
    110    AMDGPUTriple.setArch(Arch);
    111 
    112    Module * mod = unwrap(M);
    113    std::string FS;
    114    TargetOptions TO;
    115 
    116    if (dump) {
    117       mod->dump();
    118       FS += "+DumpCode";
    119    }
    120 
    121    std::auto_ptr<TargetMachine> tm(AMDGPUTarget->createTargetMachine(
    122                      AMDGPUTriple.getTriple(), gpu_family, FS,
    123                      TO, Reloc::Default, CodeModel::Default,
    124                      CodeGenOpt::Default
    125                      ));
    126    TargetMachine &AMDGPUTargetMachine = *tm.get();
    127    PassManager PM;
    128    PM.add(new TargetData(*AMDGPUTargetMachine.getTargetData()));
    129    PM.add(createPromoteMemoryToRegisterPass());
    130    AMDGPUTargetMachine.setAsmVerbosityDefault(true);
    131 
    132    std::string CodeString;
    133    raw_string_ostream oStream(CodeString);
    134    formatted_raw_ostream out(oStream);
    135 
    136    /* Optional extra paramater true / false to disable verify */
    137    if (AMDGPUTargetMachine.addPassesToEmitFile(PM, out, TargetMachine::CGFT_ObjectFile,
    138                                                true)){
    139       fprintf(stderr, "AddingPasses failed.\n");
    140       return 1;
    141    }
    142    PM.run(*mod);
    143 
    144    out.flush();
    145    std::string &data = oStream.str();
    146 
    147    *bytes = (unsigned char*)malloc(data.length() * sizeof(unsigned char));
    148    memcpy(*bytes, data.c_str(), data.length() * sizeof(unsigned char));
    149    *byte_count = data.length();
    150 
    151    return 0;
    152 }
    153