diff --git a/rocclr/compiler/lib/backends/common/Disassembler.cpp b/rocclr/compiler/lib/backends/common/Disassembler.cpp new file mode 100644 index 0000000000..8030a52c6b --- /dev/null +++ b/rocclr/compiler/lib/backends/common/Disassembler.cpp @@ -0,0 +1,343 @@ +//===- Disassembler.cpp - Disassembler for hex strings --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements the disassembler of strings of bytes written in +// hexadecimal, from standard input or from a file. +// +//===----------------------------------------------------------------------===// + +#include "Disassembler.h" +#include "lib/MC/MCDisassembler/EDDisassembler.h" +#include "lib/MC/MCDisassembler/EDInst.h" +#include "lib/MC/MCDisassembler/EDOperand.h" +#include "lib/MC/MCDisassembler/EDToken.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +typedef std::vector > ByteArrayTy; + +namespace { +class VectorMemoryObject : public MemoryObject { +private: + const ByteArrayTy &Bytes; +public: + VectorMemoryObject(const ByteArrayTy &bytes) : Bytes(bytes) {} + + uint64_t getBase() const { return 0; } + uint64_t getExtent() const { return Bytes.size(); } + + int readByte(uint64_t Addr, uint8_t *Byte) const { + if (Addr >= getExtent()) + return -1; + *Byte = Bytes[Addr].first; + return 0; + } +}; +} + +static bool PrintInsts(const MCDisassembler &DisAsm, + const ByteArrayTy &Bytes, + SourceMgr &SM, raw_ostream &Out, + MCStreamer &Streamer) { + // Wrap the vector in a MemoryObject. + VectorMemoryObject memoryObject(Bytes); + + // Disassemble it to strings. + uint64_t Size; + uint64_t Index; + + for (Index = 0; Index < Bytes.size(); Index += Size) { + MCInst Inst; + + MCDisassembler::DecodeStatus S; + S = DisAsm.getInstruction(Inst, Size, memoryObject, Index, + /*REMOVE*/ nulls(), nulls()); + switch (S) { + case MCDisassembler::Fail: + SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second), + SourceMgr::DK_Warning, + "invalid instruction encoding"); + if (Size == 0) + Size = 1; // skip illegible bytes + break; + + case MCDisassembler::SoftFail: + SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second), + SourceMgr::DK_Warning, + "potentially undefined instruction encoding"); + // Fall through + + case MCDisassembler::Success: + Streamer.EmitInstruction(Inst); + break; + } + } + + return false; +} + +static bool ByteArrayFromString(ByteArrayTy &ByteArray, + StringRef &Str, + SourceMgr &SM) { + while (!Str.empty()) { + // Strip horizontal whitespace. + if (size_t Pos = Str.find_first_not_of(" \t\r")) { + Str = Str.substr(Pos); + continue; + } + + // If this is the end of a line or start of a comment, remove the rest of + // the line. + if (Str[0] == '\n' || Str[0] == '#') { + // Strip to the end of line if we already processed any bytes on this + // line. This strips the comment and/or the \n. + if (Str[0] == '\n') { + Str = Str.substr(1); + } else { + Str = Str.substr(Str.find_first_of('\n')); + if (!Str.empty()) + Str = Str.substr(1); + } + continue; + } + + // Get the current token. + size_t Next = Str.find_first_of(" \t\n\r#"); + StringRef Value = Str.substr(0, Next); + + // Convert to a byte and add to the byte vector. + unsigned ByteVal = 0; + if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) { + // If we have an error, print it and skip to the end of line. + SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error, + "invalid input token"); + Str = Str.substr(Str.find('\n')); + ByteArray.clear(); + continue; + } + + ByteArray.push_back(std::make_pair((unsigned char)ByteVal, Value.data())); + Str = Str.substr(Next); + } + + return false; +} + +int Disassembler::disassemble(const Target &T, + const std::string &Triple, + MCSubtargetInfo &STI, + MCStreamer &Streamer, + MemoryBuffer &Buffer, + SourceMgr &SM, + raw_ostream &Out) { + OwningPtr DisAsm(T.createMCDisassembler(STI)); + if (!DisAsm) { + errs() << "error: no disassembler for target " << Triple << "\n"; + return -1; + } + + // Set up initial section manually here + Streamer.InitSections(); + + bool ErrorOccurred = false; + + // Convert the input to a vector for disassembly. + ByteArrayTy ByteArray; + StringRef Str = Buffer.getBuffer(); + + ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM); + + if (!ByteArray.empty()) + ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer); + + return ErrorOccurred; +} + +static int byteArrayReader(uint8_t *B, uint64_t A, void *Arg) { + ByteArrayTy &ByteArray = *((ByteArrayTy*)Arg); + + if (A >= ByteArray.size()) + return -1; + + *B = ByteArray[A].first; + + return 0; +} + +static int verboseEvaluator(uint64_t *V, unsigned R, void *Arg) { + EDDisassembler &disassembler = *(EDDisassembler *)((void **)Arg)[0]; + raw_ostream &Out = *(raw_ostream *)((void **)Arg)[1]; + + if (const char *regName = disassembler.nameWithRegisterID(R)) + Out << "[" << regName << "/" << R << "]"; + + if (disassembler.registerIsStackPointer(R)) + Out << "(sp)"; + if (disassembler.registerIsProgramCounter(R)) + Out << "(pc)"; + + *V = 0; + return 0; +} + +int Disassembler::disassembleEnhanced(const std::string &TS, + MemoryBuffer &Buffer, + SourceMgr &SM, + raw_ostream &Out) { + ByteArrayTy ByteArray; + StringRef Str = Buffer.getBuffer(); + + if (ByteArrayFromString(ByteArray, Str, SM)) { + return -1; + } + + Triple T(TS); + EDDisassembler::AssemblySyntax AS; + + switch (T.getArch()) { + default: + errs() << "error: no default assembly syntax for " << TS.c_str() << "\n"; + return -1; + case Triple::arm: + case Triple::thumb: + AS = EDDisassembler::kEDAssemblySyntaxARMUAL; + break; + case Triple::x86: + case Triple::x86_64: + AS = EDDisassembler::kEDAssemblySyntaxX86ATT; + break; + } + + OwningPtr + disassembler(EDDisassembler::getDisassembler(TS.c_str(), AS)); + + if (disassembler == 0) { + errs() << "error: couldn't get disassembler for " << TS << '\n'; + return -1; + } + + while (ByteArray.size()) { + OwningPtr + inst(disassembler->createInst(byteArrayReader, 0, &ByteArray)); + + if (inst == 0) { + errs() << "error: Didn't get an instruction\n"; + return -1; + } + + ByteArray.erase (ByteArray.begin(), ByteArray.begin() + inst->byteSize()); + + unsigned numTokens = inst->numTokens(); + if ((int)numTokens < 0) { + errs() << "error: couldn't count the instruction's tokens\n"; + return -1; + } + + for (unsigned tokenIndex = 0; tokenIndex != numTokens; ++tokenIndex) { + EDToken *token; + + if (inst->getToken(token, tokenIndex)) { + errs() << "error: Couldn't get token\n"; + return -1; + } + + const char *buf; + if (token->getString(buf)) { + errs() << "error: Couldn't get string for token\n"; + return -1; + } + + Out << '['; + int operandIndex = token->operandID(); + + if (operandIndex >= 0) + Out << operandIndex << "-"; + + switch (token->type()) { + case EDToken::kTokenWhitespace: Out << "w"; break; + case EDToken::kTokenPunctuation: Out << "p"; break; + case EDToken::kTokenOpcode: Out << "o"; break; + case EDToken::kTokenLiteral: Out << "l"; break; + case EDToken::kTokenRegister: Out << "r"; break; + } + + Out << ":" << buf; + + if (token->type() == EDToken::kTokenLiteral) { + Out << "="; + if (token->literalSign()) + Out << "-"; + uint64_t absoluteValue; + if (token->literalAbsoluteValue(absoluteValue)) { + errs() << "error: Couldn't get the value of a literal token\n"; + return -1; + } + Out << absoluteValue; + } else if (token->type() == EDToken::kTokenRegister) { + Out << "="; + unsigned regID; + if (token->registerID(regID)) { + errs() << "error: Couldn't get the ID of a register token\n"; + return -1; + } + Out << "r" << regID; + } + + Out << "]"; + } + + Out << " "; + + if (inst->isBranch()) + Out << "
"; + if (inst->isMove()) + Out << " "; + + unsigned numOperands = inst->numOperands(); + + if ((int)numOperands < 0) { + errs() << "error: Couldn't count operands\n"; + return -1; + } + + for (unsigned operandIndex = 0; operandIndex != numOperands; + ++operandIndex) { + Out << operandIndex << ":"; + + EDOperand *operand; + if (inst->getOperand(operand, operandIndex)) { + errs() << "error: couldn't get operand\n"; + return -1; + } + + uint64_t evaluatedResult; + void *Arg[] = { disassembler.get(), &Out }; + if (operand->evaluate(evaluatedResult, verboseEvaluator, Arg)) { + errs() << "error: Couldn't evaluate an operand\n"; + return -1; + } + Out << "=" << evaluatedResult << " "; + } + + Out << '\n'; + } + + return 0; +} diff --git a/rocclr/compiler/lib/backends/common/Disassembler.h b/rocclr/compiler/lib/backends/common/Disassembler.h new file mode 100644 index 0000000000..17d622f1d9 --- /dev/null +++ b/rocclr/compiler/lib/backends/common/Disassembler.h @@ -0,0 +1,47 @@ +//===- Disassembler.h - Text File Disassembler ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements the disassembler of strings of bytes written in +// hexadecimal, from standard input or from a file. +// +//===----------------------------------------------------------------------===// + +#ifndef DISASSEMBLER_H +#define DISASSEMBLER_H + +#include + +namespace llvm { + +class MemoryBuffer; +class Target; +class raw_ostream; +class SourceMgr; +class MCSubtargetInfo; +class MCStreamer; + +class Disassembler { +public: + static int disassemble(const Target &T, + const std::string &Triple, + MCSubtargetInfo &STI, + MCStreamer &Streamer, + MemoryBuffer &Buffer, + SourceMgr &SM, + raw_ostream &Out); + + static int disassembleEnhanced(const std::string &tripleString, + MemoryBuffer &buffer, + SourceMgr &SM, + raw_ostream &Out); +}; + +} // namespace llvm + +#endif diff --git a/rocclr/compiler/lib/backends/common/codegen.cpp b/rocclr/compiler/lib/backends/common/codegen.cpp index ce6b243416..eebc61580d 100644 --- a/rocclr/compiler/lib/backends/common/codegen.cpp +++ b/rocclr/compiler/lib/backends/common/codegen.cpp @@ -5,7 +5,6 @@ #include "codegen.hpp" #include "utils/libUtils.h" #include "os/os.hpp" -#include "jit/src/jit.hpp" #include "utils/target_mappings.h" #ifdef _MSC_VER /* for disabling warning in llvm/ADT/Statistic.h */ @@ -15,15 +14,20 @@ #ifdef _MSC_VER #pragma warning(default:4146) #endif +#include "llvm/DataLayout.h" +#include "llvm/Module.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/TargetSelect.h" -#include "llvm/DataLayout.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/ObjectImage.h" #include #include #include @@ -50,6 +54,301 @@ AdjustCGOptLevel(Module& M, CodeGenOpt::Level OrigOLvl) return OrigOLvl; } +//!--------------------------------------------------------------------------!// +// JIT Memory manager +//!--------------------------------------------------------------------------!// +OCLMCJITMemoryManager::~OCLMCJITMemoryManager() { + for (llvm::SmallVectorImpl::iterator + I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end(); + I != E; ++I) + llvm::sys::Memory::releaseMappedMemory(I->first); + for (llvm::SmallVectorImpl::iterator + I = AllocatedDataMem.begin(), E = AllocatedDataMem.end(); + I != E; ++I) + llvm::sys::Memory::releaseMappedMemory(I->first); +} + +void +OCLMCJITMemoryManager::deallocateSection(uint8_t* BasePtr) { + for (llvm::SmallVectorImpl::iterator + I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end(); + I != E; ++I) + if (I->first.base() == BasePtr) { + llvm::sys::Memory::releaseMappedMemory(I->first); + AllocatedCodeMem.erase(I); + return; + } + for (llvm::SmallVectorImpl::iterator + I = AllocatedDataMem.begin(), E = AllocatedDataMem.end(); + I != E; ++I) + if (I->first.base() == BasePtr) { + llvm::sys::Memory::releaseMappedMemory(I->first); + AllocatedDataMem.erase(I); + return; + } +} + +void OCLMCJITMemoryManager::reserveMemory(uint64_t Size) { + llvm::sys::MemoryBlock Block = allocateSection(Size); + AllocatedCodeMem.push_back(Allocation(Block, 64)); + allocPtr = (uint8_t*)Block.base(); + allocMaxPtr = allocPtr + Block.size(); +} + +uint8_t *OCLMCJITMemoryManager:: +allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { + // The recording memory manager is just a local copy of the remote target. + // The alignment requirement is just stored here for later use. Regular + // heap storage is sufficient here, but we're using mapped memory to work + // around a bug in MCJIT. + uint8_t* address = reservedAlloc(Size, Alignment); + if(address != NULL) { + return address; + } else { + llvm::sys::MemoryBlock Block = allocateSection(Size); + AllocatedCodeMem.push_back(Allocation(Block, Alignment)); + return (uint8_t*)Block.base(); + } +} + +uint8_t *OCLMCJITMemoryManager:: +allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, bool isReasOnly) { + bool IsReadOnly = false; + // The recording memory manager is just a local copy of the remote target. + // The alignment requirement is just stored here for later use. Regular + // heap storage is sufficient here, but we're using mapped memory to work + // around a bug in MCJIT. + uint8_t* address = reservedAlloc(Size, Alignment); + if(address != NULL) { + return address; + } else { + llvm::sys::MemoryBlock Block = allocateSection(Size); + AllocatedDataMem.push_back(Allocation(Block, Alignment)); + return (uint8_t*)Block.base(); + } +} + +uint8_t * OCLMCJITMemoryManager::reservedAlloc(uintptr_t Size, unsigned Alignment) { + if(allocPtr != NULL) { + uint8_t *allocPtrAligned = + (uint8_t*)(((uintptr_t)allocPtr + + ((uintptr_t)Alignment-1)) & ~((uintptr_t)Alignment-1)); + uint8_t *allocPtrNext = allocPtrAligned + Size; + if(allocPtrNext < allocMaxPtr) { + allocPtr = allocPtrNext; + return allocPtrAligned; + } + } + return NULL; +} + +llvm::sys::MemoryBlock OCLMCJITMemoryManager::allocateSection(uintptr_t Size) { + llvm::error_code ec; + llvm::sys::MemoryBlock MB = + llvm::sys::Memory::allocateMappedMemory(Size, + &Near, + llvm::sys::Memory::MF_READ | + llvm::sys::Memory::MF_WRITE | + llvm::sys::Memory::MF_EXEC, + ec); + assert(!ec && MB.base()); + + // FIXME: This is part of a work around to keep sections near one another + // when MCJIT performs relocations after code emission but before + // the generated code is moved to the remote target. + // Save this address as the basis for our next request + Near = MB; + return MB; +} + +void OCLMCJITMemoryManager::setMemoryWritable() { + assert(!"Unexpected"); +} + +void OCLMCJITMemoryManager::setMemoryExecutable() { + assert(!"Unexpected"); +} + +void OCLMCJITMemoryManager::setPoisonMemory(bool poison) { + assert(!"Unexpected"); +} + +void OCLMCJITMemoryManager::AllocateGOT() { + assert(!"Unexpected"); +} + +uint8_t *OCLMCJITMemoryManager::getGOTBase() const { + assert(!"Unexpected"); + return 0; +} +uint8_t *OCLMCJITMemoryManager::startFunctionBody(const llvm::Function *F, + uintptr_t &ActualSize) { + assert(!"Unexpected"); + return 0; +} +uint8_t *OCLMCJITMemoryManager::allocateStub(const llvm::GlobalValue* F, + unsigned StubSize, + unsigned Alignment) { + assert(!"Unexpected"); + return 0; +} +void OCLMCJITMemoryManager::endFunctionBody(const llvm::Function *F, + uint8_t *FunctionStart, + uint8_t *FunctionEnd) { + assert(!"Unexpected"); +} +uint8_t *OCLMCJITMemoryManager::allocateSpace(intptr_t Size, + unsigned Alignment) { + assert(!"Unexpected"); + return 0; +} +uint8_t *OCLMCJITMemoryManager::allocateGlobal(uintptr_t Size, + unsigned Alignment) { + assert(!"Unexpected"); + return 0; +} +void OCLMCJITMemoryManager::deallocateFunctionBody(void *Body) { + assert(!"Unexpected"); +} +uint8_t* OCLMCJITMemoryManager::startExceptionTable(const llvm::Function* F, + uintptr_t &ActualSize) { + assert(!"Unexpected"); + return 0; +} +void OCLMCJITMemoryManager::endExceptionTable(const llvm::Function *F, + uint8_t *TableStart, + uint8_t *TableEnd, + uint8_t* FrameRegister) { + assert(!"Unexpected"); +} +void OCLMCJITMemoryManager::deallocateExceptionTable(void *ET) { + assert(!"Unexpected"); +} + +static int jit_noop() { + return 0; +} + +void *OCLMCJITMemoryManager::getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure) { + // We should not invoke parent's ctors/dtors from generated main()! + // On Mingw and Cygwin, the symbol __main is resolved to + // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors + // (and register wrong callee's dtors with atexit(3)). + // We expect ExecutionEngine::runStaticConstructorsDestructors() + // is called before ExecutionEngine::runFunctionAsMain() is called. + if (Name == "__main") return (void*)(intptr_t)&jit_noop; + + return NULL; +} + +//!--------------------------------------------------------------------------!// +// JIT Event Listener +//!--------------------------------------------------------------------------!// +class OclJITEventListener : public llvm::JITEventListener +{ +private: + std::string* output_; + +public: + OclJITEventListener(std::string &output) { + output_ = &output; + } + + virtual void NotifyObjectEmitted(const llvm::ObjectImage &Obj) { + encodeObjectImage(Obj.getData(), *output_); + } + + // Encoding and decoding are used to eliminate 0x00 ('\0') from the + // string so it is safe to use it as a null terminated c string. + // Translate: + // 0x00 -> 0xaa 0x55 + // 0xaa -> 0xaa 0xaa + static void encodeObjectImage(std::string objectImage, std::string &encodedObjectImage) { + size_t length = objectImage.length(); + for (size_t i = 0; i < length; ++i) { + unsigned char c = objectImage[i]; + switch (c) { + case 0x00U: + encodedObjectImage.push_back(0xaaU); + encodedObjectImage.push_back(0x55U); + break; + case 0xaaU: + encodedObjectImage.push_back(0xaaU); + encodedObjectImage.push_back(0xaaU); + break; + default: + encodedObjectImage.push_back(c); + break; + } + } + } + + // Translate: + // 0xaa 0x55 -> 0x00 + // 0xaa 0xaa -> 0xaa + static void decodeObjectImage(std::string encodedObjectImage, std::string &decodedObjectImage) { + size_t length = encodedObjectImage.length(); + for (size_t i = 0; i < length; ++i) { + unsigned char c = encodedObjectImage[i]; + switch (c) { + case 0xaaU: + { + i = i + 1; // Increment to advance two characters + unsigned char cnext = encodedObjectImage[i]; + if (cnext == 0xaaU) { + decodedObjectImage.push_back(0xaaU); + } else if (cnext == 0x55U) { + decodedObjectImage.push_back(0x00U); + } else { + assert(!"Bad encoding encountered"); + } + } + break; + default: + decodedObjectImage.push_back(c); + break; + } + } + } + +}; + +void decodeObjectImage(std::string encodedObjectImage, std::string &decodedObjectImage) { + OclJITEventListener::decodeObjectImage(encodedObjectImage, decodedObjectImage); +} + +// Returns empty string if code generation was successful, +// otherwise the return string contains the error the MCJIT encountered. +std::string +jitCodeGen(llvm::Module* Composite, + llvm::TargetMachine* TargetMachine, + llvm::CodeGenOpt::Level OLvl, + std::string& output) { + std::string ErrStr; + OclJITEventListener Listener(output); + llvm::InitializeNativeTargetAsmParser(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::JITMemoryManager* MemMgr = new OCLMCJITMemoryManager(); + llvm::EngineBuilder builder(Composite); + builder.setOptLevel(OLvl); + builder.setErrorStr(&ErrStr); + builder.setJITMemoryManager(MemMgr); + builder.setUseMCJIT(true); + // builder.setRelocationModel(llvm::Reloc::PIC_) + // builder.setCodeModel(llvm::CodeModel::Large) +#ifndef ANDROID + std::unique_ptr + TheExecutionEngine(builder.create(TargetMachine)); + + TheExecutionEngine->RegisterJITEventListener(&Listener); + TheExecutionEngine->finalizeObject(); + TheExecutionEngine->removeModule(Composite); +#endif + return ErrStr; +} + int llvmCodeGen( Module* Composite, @@ -231,7 +530,7 @@ llvmCodeGen( // MCJIT(Jan) if(!isGPU && OptionsObj->oVariables->UseJIT) { TargetMachine* jittarget(TheTarget->createTargetMachine(TheTriple.getTriple(), - aclutGetCodegenName(binary->target), FeatureStr, targetOptions, + aclutGetCodegenName(binary->target), FeatureStr, targetOptions, WINDOWS_SWITCH(Reloc::DynamicNoPIC, Reloc::PIC_), CodeModel::Default, OLvl)); diff --git a/rocclr/compiler/lib/backends/common/codegen.hpp b/rocclr/compiler/lib/backends/common/codegen.hpp index e8581e19ce..cb17a11251 100644 --- a/rocclr/compiler/lib/backends/common/codegen.hpp +++ b/rocclr/compiler/lib/backends/common/codegen.hpp @@ -4,6 +4,7 @@ #ifndef _BE_CODEGEN_HPP_ #define _BE_CODEGEN_HPP_ #include "compiler_stage.hpp" +#include "llvm/ExecutionEngine/JITMemoryManager.h" namespace amdcl { @@ -84,4 +85,77 @@ namespace amdcl /*@}*/ #endif } // amdcl namespace + +//!--------------------------------------------------------------------------!// +// JIT Memory manager +//!--------------------------------------------------------------------------!// +class OCLMCJITMemoryManager : public llvm::JITMemoryManager { +public: + typedef std::pair Allocation; + +private: + llvm::SmallVector AllocatedDataMem; + llvm::SmallVector AllocatedCodeMem; + + // FIXME: This is part of a work around to keep sections near one another + // when MCJIT performs relocations after code emission but before + // the generated code is moved to the remote target. + llvm::sys::MemoryBlock Near; + uint8_t * reservedAlloc(uintptr_t Size, unsigned Alignment); + llvm::sys::MemoryBlock allocateSection(uintptr_t Size); + + uint8_t *allocPtr; + uint8_t *allocMaxPtr; + +public: + OCLMCJITMemoryManager() : allocPtr(NULL), allocMaxPtr(NULL) {} + virtual ~OCLMCJITMemoryManager(); + + typedef llvm::SmallVectorImpl::const_iterator const_data_iterator; + typedef llvm::SmallVectorImpl::const_iterator const_code_iterator; + + const_data_iterator data_begin() const { return AllocatedDataMem.begin(); } + const_data_iterator data_end() const { return AllocatedDataMem.end(); } + const_code_iterator code_begin() const { return AllocatedCodeMem.begin(); } + const_code_iterator code_end() const { return AllocatedCodeMem.end(); } + + virtual void reserveMemory(uint64_t size); + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID); + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, bool isReadOnly); + + void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true); + + bool applyPermissions(std::string *ErrMsg) { return false; } + + // The following obsolete JITMemoryManager calls are stubbed out for + // this model. + void setMemoryWritable(); + void setMemoryExecutable(); + void setPoisonMemory(bool poison); + void AllocateGOT(); + uint8_t *getGOTBase() const; + uint8_t *startFunctionBody(const llvm::Function *F, uintptr_t &ActualSize); + uint8_t *allocateStub(const llvm::GlobalValue* F, unsigned StubSize, + unsigned Alignment); + void endFunctionBody(const llvm::Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd); + uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); + uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); + void deallocateFunctionBody(void *Body); + uint8_t* startExceptionTable(const llvm::Function* F, uintptr_t &ActualSize); + void endExceptionTable(const llvm::Function *F, uint8_t *TableStart, + uint8_t *TableEnd, uint8_t* FrameRegister); + void deallocateExceptionTable(void *ET); + void deallocateSection(uint8_t* BasePtr); +}; + +// The jitCodeGen function creates a string where the '\0' characters +// have been encoded. decodeObjectImage puts the '\0' characters back. +void decodeObjectImage(std::string encodedObjectImage, std::string &decodedObjectImage); + #endif // _BE_CODEGEN_HPP_ diff --git a/rocclr/compiler/lib/backends/common/v0_8/if_acl.cpp b/rocclr/compiler/lib/backends/common/v0_8/if_acl.cpp index c3ffe81ab3..f0459d82a6 100644 --- a/rocclr/compiler/lib/backends/common/v0_8/if_acl.cpp +++ b/rocclr/compiler/lib/backends/common/v0_8/if_acl.cpp @@ -35,22 +35,42 @@ #include "llvm/LLVMContext.h" #include "llvm/Analysis/Passes.h" +#if defined(LEGACY_COMPLIB) +#include "Disassembler.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/OwningPtr.h" +#endif +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/IRReader.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/ExecutionEngine/ObjectBuffer.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" #include #include #include #include #include +#include aclLoaderData * ACL_API_ENTRY if_aclCompilerInit(aclCompiler *cl, aclBinary *bin, @@ -58,7 +78,7 @@ if_aclCompilerInit(aclCompiler *cl, aclBinary *bin, { amdcl::acquire_global_lock(); char* timing = ::getenv("AMD_DEBUG_HLC_ENABLE_TIMING"); - if (timing && (timing[0] == '1')) + if (timing && (timing[0] == '1')) llvm::TimePassesIsEnabled = true; else llvm::TimePassesIsEnabled = false; @@ -2208,7 +2228,7 @@ void deserializeCLMetadata(const char* ptr, aclMetadata * const md, const size_t tmp_ptr += fmtPtr->fmtStrSize + 1; } assert(md->data_size == size && "The size and data size calculations are off!"); - assert((size_t)(tmp_ptr - reinterpret_cast(md)) + assert((size_t)(tmp_ptr - reinterpret_cast(md)) == size && "Size of data and calculated sizes differ!"); } @@ -2903,6 +2923,258 @@ if_aclDbgRemoveArgument(aclCompiler *cl, return error_code; } +static OCLMCJITMemoryManager* memMgr = NULL; + +OCLMCJITMemoryManager* createJITMemoryManager() { + if (!memMgr) { + memMgr = new OCLMCJITMemoryManager(); + } + return memMgr; +} + +aclJITObjectImage ACL_API_ENTRY +if_aclJITObjectImageCreate(const void* buffer, size_t length, + aclBinary* bin, acl_error* error_code) { + llvm::StringRef dataString((const char*)buffer, length); + llvm::MemoryBuffer* memBuf = llvm::MemoryBuffer::getMemBufferCopy(dataString); + llvm::ObjectBuffer* objBuf = new llvm::ObjectBuffer(memBuf); + llvm::RuntimeDyld rtdyld(createJITMemoryManager()); + llvm::ObjectImage* objectImage = rtdyld.loadObject(objBuf); + rtdyld.resolveRelocations(); + amd::option::Options* options = reinterpret_cast(bin->options); + if (options && options->isDumpFlagSet(amd::option::DUMP_O)) { + llvm::StringRef finalData = objectImage->getData(); + std::string finalDataString = finalData.str(); + std::string objname = options->getDumpFileName(".elf"); + std::ofstream out(objname.c_str(), std::fstream::binary | std::fstream::trunc); + out << finalDataString; + out.close(); + } + return objectImage; +} + +aclJITObjectImage ACL_API_ENTRY +if_aclJITObjectImageCopy(const void* buffer, size_t length, acl_error* error_code) { + llvm::StringRef dataString((const char*)buffer, length); + llvm::MemoryBuffer* memBuf = llvm::MemoryBuffer::getMemBufferCopy(dataString); + llvm::ObjectBuffer* objBuf = new llvm::ObjectBuffer(memBuf); + llvm::RuntimeDyld rtdyld(createJITMemoryManager()); + llvm::ObjectImage* objectImage = rtdyld.loadObject(objBuf); + rtdyld.resolveRelocations(); + return objectImage; +} + +acl_error ACL_API_ENTRY +if_aclJITObjectImageDestroy(aclJITObjectImage image) { + llvm::ObjectImage* objectImage(reinterpret_cast(image)); + llvm::object::section_iterator end = objectImage->end_sections(); + llvm::error_code err; + for (llvm::object::section_iterator iter = objectImage->begin_sections(); + iter != end; iter.increment(err)) { + llvm::object::SectionRef sectionRef = *iter; + uint64_t address; + sectionRef.getAddress(address); + memMgr->deallocateSection((uint8_t*)address); + } + delete objectImage; + return ACL_SUCCESS; +} + +size_t ACL_API_ENTRY +if_aclJITObjectImageSize(aclJITObjectImage image, acl_error* error_code) { + return (reinterpret_cast(image))->getData().size(); +} + +const char* ACL_API_ENTRY +if_aclJITObjectImageData(aclJITObjectImage image, acl_error* error_code) { + return (reinterpret_cast(image))->getData().data(); +} + +acl_error ACL_API_ENTRY +if_aclJITObjectImageFinalize(aclJITObjectImage image) { + // TODO: Implement + return ACL_SUCCESS; +} + +size_t ACL_API_ENTRY +if_aclJITObjectImageGetGlobalsSize(aclJITObjectImage image, acl_error* error_code) { + size_t totalSize = 0; + llvm::ObjectImage* objectImage(reinterpret_cast(image)); + llvm::object::section_iterator end = objectImage->end_sections(); + llvm::error_code err; + for (llvm::object::section_iterator iter = objectImage->begin_sections(); + iter != end; iter.increment(err)) { + llvm::object::SectionRef sectionRef = *iter; + llvm::StringRef name; + uint64_t size; + bool isBSS, isData, isText; + sectionRef.getName(name); + sectionRef.getSize(size); + sectionRef.isBSS(isBSS); + sectionRef.isData(isData); + sectionRef.isText(isText); + if ((isBSS || isData) && !isText) { + totalSize += (size_t)size; + } + } + return totalSize; +} + +acl_error ACL_API_ENTRY +if_aclJITObjectImageIterateSymbols(aclJITObjectImage image, + JITSymbolCallback jit_callback, void* data) { + llvm::ObjectImage* objectImage(reinterpret_cast(image)); + llvm::object::symbol_iterator end = objectImage->end_symbols(); + llvm::StringRef name; + uint64_t address; + llvm::error_code err; + for (llvm::object::symbol_iterator iter = objectImage->begin_symbols(); + iter != end; iter.increment(err)) { + llvm::object::SymbolRef symRef = *iter; + symRef.getName(name); + symRef.getAddress(address); + jit_callback(name.str().c_str(), (const void*)address, data); + } + return ACL_SUCCESS; +} + +#if defined(LEGACY_COMPLIB) +#if 0 +static std::string getFeaturesString(llvm::StringMap& Features) +{ + std::string FeatureString; + llvm::raw_string_ostream FeatureStream(FeatureString); + llvm::SubtargetFeatures TargetFeatures(""); + llvm::StringMapConstIterator iterEnd = Features.end(); + for(llvm::StringMapConstIterator I = Features.begin(); + I != iterEnd; ++I) { + const llvm::StringMapEntry entry = *I; + TargetFeatures.AddFeature(entry.getKey(), entry.getValue()); + } + TargetFeatures.print(FeatureStream); + return FeatureString; +} +#endif + +static std::string getTripleName() +{ +#ifdef _WIN32 + return LP64_SWITCH("i686-pc-mingw32-amdopencl", + "x86_64-pc-mingw32-amdopencl"); +#else + return LP64_SWITCH("i686-pc-linux-amdopencl", + "x86_64-pc-linux-amdopencl"); +#endif +} + +static std::string bytesToHexString(const char* data, size_t size) { + std::stringstream hexstring; + hexstring << std::hex << std::setfill('0'); + for(size_t i = 0; i < size; ++i) { + hexstring << "0x" << std::setw(2) << unsigned((unsigned char)data[i]) + << std::endl; + } + hexstring << std::endl; + return hexstring.str(); +} + +char* ACL_API_ENTRY +if_aclJITObjectImageDisassembleKernel(constAclJITObjectImage image, + const char* kernel, acl_error* error_code) { + const llvm::ObjectImage* objectImage(reinterpret_cast(image)); + llvm::object::symbol_iterator end = objectImage->end_symbols(); + llvm::error_code err; + llvm::StringRef name; + std::stringstream disas; + for (llvm::object::symbol_iterator iter = objectImage->begin_symbols(); + iter != end; iter.increment(err)) { + llvm::object::SymbolRef symRef = *iter; + symRef.getName(name); + std::string kernelStr(kernel); + if(name == kernelStr) { + uint64_t start; + uint64_t size; + symRef.getSize(size); + symRef.getAddress(start); + const char *bytes = (const char *)start; + const uint64_t extent = 0x10000; + uint64_t max_pc = 0; + + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllDisassemblers(); + + std::string TripleName = getTripleName(); + std::string Error; + const llvm::Target *TheTarget = + llvm::TargetRegistry::lookupTarget(TripleName, Error); + + std::string hexstring = bytesToHexString(bytes, size); + llvm::StringRef kernelMem(hexstring); + llvm::MemoryBuffer *Buffer = + llvm::MemoryBuffer::getMemBuffer(kernelMem, "", false); + llvm::SourceMgr SrcMgr; + + SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); + + llvm::OwningPtr + MAI(TheTarget->createMCAsmInfo(TripleName)); + assert(MAI && "Unable to create target asm info!"); + + llvm::OwningPtr + MRI(TheTarget->createMCRegInfo(TripleName)); + assert(MRI && "Unable to create target register info!"); + + llvm::OwningPtr + MOFI(new llvm::MCObjectFileInfo()); + llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); + MOFI->InitMCObjectFileInfo(TripleName, llvm::Reloc::Default, + llvm::CodeModel::Default, Ctx); + + Ctx.setAllowTemporaryLabels(true); + Ctx.setGenDwarfForAssembly(true); + + std::string MCPU = "corei7-avx"; + std::string FeaturesStr; + + std::string DisasResultString; + llvm::raw_string_ostream OutputStream(DisasResultString); + OutputStream.SetUnbuffered(); + llvm::formatted_raw_ostream FOS(OutputStream); + llvm::OwningPtr Str; + llvm::OwningPtr MCII(TheTarget->createMCInstrInfo()); + llvm::OwningPtr + STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); + llvm::MCInstPrinter *IP = + TheTarget->createMCInstPrinter(0 /* OutputAsmVariant */, *MAI, *MCII, *MRI, + *STI); + llvm::MCCodeEmitter *CE = 0; + llvm::MCAsmBackend *MAB = 0; + if (false) { + CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); + MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); + } + Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true, + /*useLoc*/ true, + /*useCFI*/ true, + /*useDwarfDirectory*/ true, + IP, CE, MAB, false)); + // int Res = llvm::Disassembler::disassemble(*TheTarget, + // TripleName, *STI, *Str, + // *Buffer, SrcMgr, OutputStream); + + int Res = + llvm::Disassembler::disassembleEnhanced(TripleName, *Buffer, SrcMgr, + OutputStream); + const char* result = DisasResultString.c_str(); + return strdup(result); + } + } + return NULL; +} +#endif + void myLogFunc(const char * msg, size_t size) { printf("%s\n", msg); @@ -2979,15 +3251,15 @@ bool aclRenderscriptCompile( return false; aclTargetInfo target = aclGetTargetInfo("hsail", "Bonaire", &error_code); - if (error_code != ACL_SUCCESS) + if (error_code != ACL_SUCCESS) return false; - + aclBinary *aoe = aclBinaryInit(sizeof(aclBinary), &target, NULL, &error_code); - if (error_code != ACL_SUCCESS) + if (error_code != ACL_SUCCESS) return false; - + error_code = aclInsertSection(aoc, aoe, source, size, aclLLVMIR); - if (error_code != ACL_SUCCESS) + if (error_code != ACL_SUCCESS) return false; #if 1 @@ -2996,7 +3268,7 @@ bool aclRenderscriptCompile( #else error_code = aclCompile(aoc, aoe, NULL, ACL_TYPE_RSLLVMIR_BINARY, ACL_TYPE_ISA, myLogFunc); #endif - + if (error_code == ACL_FRONTEND_FAILURE) { printf("ACL_FRONTEND_FAILURE.\n"); return true; @@ -3007,11 +3279,11 @@ bool aclRenderscriptCompile( if ((aoe == NULL) || (aoe->bin == NULL)) return false; - + char *buffer = NULL; size_t len; acl_error errCode = aclWriteToMem(aoe, reinterpret_cast(&buffer), &len); - if (errCode != ACL_SUCCESS) + if (errCode != ACL_SUCCESS) return false; *outLen = len; diff --git a/rocclr/compiler/lib/backends/common/v0_8/if_acl.h b/rocclr/compiler/lib/backends/common/v0_8/if_acl.h index 7250f550d8..fe44b05b49 100644 --- a/rocclr/compiler/lib/backends/common/v0_8/if_acl.h +++ b/rocclr/compiler/lib/backends/common/v0_8/if_acl.h @@ -129,4 +129,44 @@ if_aclDbgRemoveArgument(aclCompiler *cl, acl_error ACL_API_ENTRY if_aclSetupLoaderObject(aclCompiler *cl) ACL_API_0_8; +void* ACL_API_ENTRY +if_aclJITObjectImageCreate(const void* buffer, + size_t length, + aclBinary* bin, + acl_error* error_code) ACL_API_0_8; + +void* ACL_API_ENTRY +if_aclJITObjectImageCopy(const void* buffer, + size_t length, + acl_error* error_code) ACL_API_0_8; + +acl_error ACL_API_ENTRY +if_aclJITObjectImageDestroy(aclJITObjectImage buffer) ACL_API_0_8; + +size_t ACL_API_ENTRY +if_aclJITObjectImageSize(aclJITObjectImage image, + acl_error* error_code) ACL_API_0_8; + +const char* ACL_API_ENTRY +if_aclJITObjectImageData(aclJITObjectImage image, + acl_error* error_code) ACL_API_0_8; + +acl_error ACL_API_ENTRY +if_aclJITObjectImageFinalize(aclJITObjectImage image) ACL_API_0_8; + +size_t ACL_API_ENTRY +if_aclJITObjectImageGetGlobalsSize(aclJITObjectImage image, + acl_error* error_code) ACL_API_0_8; + +acl_error ACL_API_ENTRY +if_aclJITObjectImageIterateSymbols(aclJITObjectImage image, + JITSymbolCallback jit_callback, void* data) ACL_API_0_8; + +#if defined(LEGACY_COMPLIB) +char* ACL_API_ENTRY +if_aclJITObjectImageDisassembleKernel(constAclJITObjectImage image, + const char* kernel, + acl_error* error_code) ACL_API_0_8; +#endif + #endif // _IF_ACL_0_8_H_ diff --git a/rocclr/compiler/lib/include/v0_8/acl.h b/rocclr/compiler/lib/include/v0_8/acl.h index f7a93ad38d..35fafd5435 100644 --- a/rocclr/compiler/lib/include/v0_8/acl.h +++ b/rocclr/compiler/lib/include/v0_8/acl.h @@ -230,11 +230,53 @@ const void* ACL_API_ENTRY size_t *size, acl_error *error_code) ACL_API_0_8; +//!--------------------------------------------------------------------------!// +// Functions that deal with aclJITObjectImage objects. +//!--------------------------------------------------------------------------!// +aclJITObjectImage ACL_API_ENTRY +aclJITObjectImageCreate(aclCompiler *cl, const void* buffer, + size_t length, aclBinary* bin, acl_error* error_code); + +aclJITObjectImage ACL_API_ENTRY +aclJITObjectImageCopy(aclCompiler *cl, const void* buffer, + size_t length, acl_error* error_code); + +acl_error ACL_API_ENTRY +aclJITObjectImageDestroy(aclCompiler *cl, aclJITObjectImage buffer); + +acl_error ACL_API_ENTRY +aclJITObjectImageFinalize(aclCompiler *cl, aclJITObjectImage image); + +size_t ACL_API_ENTRY +aclJITObjectImageSize(aclCompiler *cl, aclJITObjectImage image, + acl_error* error_code); + +const char* ACL_API_ENTRY +aclJITObjectImageData(aclCompiler *cl, aclJITObjectImage image, + acl_error* error_code); + +size_t ACL_API_ENTRY +aclJITObjectImageGetGlobalsSize(aclCompiler *cl, aclJITObjectImage image, + acl_error* error_code); + +acl_error ACL_API_ENTRY +aclJITObjectImageIterateSymbols(aclCompiler *cl, aclJITObjectImage image, + aclJITSymbolCallback callback, void* data); + +#if defined(LEGACY_COMPLIB) +char* ACL_API_ENTRY +aclJITObjectImageDisassembleKernel(aclCompiler *cl, constAclJITObjectImage image, + const char* kernel, acl_error* error_code); +#endif + //!--------------------------------------------------------------------------!// // Debug functionality //!--------------------------------------------------------------------------!// void aclDumpBinary(const aclBinary *bin); -// Functions to retrieve kernel information + +//!--------------------------------------------------------------------------!// +// Functions that deal with kenel statistics. +//!--------------------------------------------------------------------------!// void aclGetKstatsR800(const void* shader, aclKernelStats &kstats, const char* chip_id); void aclGetKstatsSI(const void* shader, diff --git a/rocclr/compiler/lib/include/v0_8/aclFunctors.h b/rocclr/compiler/lib/include/v0_8/aclFunctors.h index 2aeba9dc63..382482d504 100644 --- a/rocclr/compiler/lib/include/v0_8/aclFunctors.h +++ b/rocclr/compiler/lib/include/v0_8/aclFunctors.h @@ -9,6 +9,10 @@ // information on what errors occur. typedef void (*aclLogFunction_0_8)(const char *msg, size_t size); +typedef bool (*aclJITSymbolCallback)(const char*, const void*, void*); +typedef void* aclJITObjectImage; +typedef const void* constAclJITObjectImage; + typedef acl_error (ACL_API_ENTRY *InsertSec_0_8)(aclCompiler *cl, aclBinary *binary, @@ -176,6 +180,47 @@ typedef acl_error typedef acl_error (ACL_API_ENTRY *SetupLoaderObject_0_8)(aclCompiler *cl) ACL_API_0_8; +typedef aclJITObjectImage +(ACL_API_ENTRY *JITObjectImageCreate_0_8)(const void* buffer, + size_t length, + aclBinary* bin, + acl_error* error_code) ACL_API_0_8; + +typedef aclJITObjectImage +(ACL_API_ENTRY *JITObjectImageCopy_0_8)(const void* buffer, + size_t length, + acl_error* error_code) ACL_API_0_8; + +typedef acl_error +(ACL_API_ENTRY *JITObjectImageDestroy_0_8)(aclJITObjectImage image) ACL_API_0_8; + +typedef size_t +(ACL_API_ENTRY *JITObjectImageSize_0_8)(aclJITObjectImage image, + acl_error* error_code) ACL_API_0_8; + +typedef const char * +(ACL_API_ENTRY *JITObjectImageData_0_8)(aclJITObjectImage image, + acl_error* error_code) ACL_API_0_8; + +typedef acl_error +(ACL_API_ENTRY *JITObjectImageFinalize_0_8)(aclJITObjectImage image) ACL_API_0_8; + +typedef size_t +(ACL_API_ENTRY *JITObjectImageGetGlobalsSize_0_8)(aclJITObjectImage image, + acl_error* error_code) ACL_API_0_8; + +typedef bool (*JITSymbolCallback_0_8)(const char*, const void*, void*); + +typedef acl_error +(ACL_API_ENTRY *JITObjectImageIterateSymbols_0_8)(aclJITObjectImage image, + JITSymbolCallback_0_8 jit_callback, + void* data) ACL_API_0_8; + +typedef char* +(ACL_API_ENTRY *JITObjectImageDisassembleKernel_0_8)(constAclJITObjectImage image, + const char* kernel, + acl_error* error_code) ACL_API_0_8; + typedef void* (*AllocFunc_0_8)(size_t size) ACL_API_0_8; diff --git a/rocclr/compiler/lib/include/v0_8/aclStructs.h b/rocclr/compiler/lib/include/v0_8/aclStructs.h index db2da24753..8586955aec 100644 --- a/rocclr/compiler/lib/include/v0_8/aclStructs.h +++ b/rocclr/compiler/lib/include/v0_8/aclStructs.h @@ -210,6 +210,15 @@ typedef struct _acl_cl_loader_rec_0_8 { AddDbgArg addDbg; RemoveDbgArg removeDbg; SetupLoaderObject setupLoaderObject; + JITObjectImageCreate jitOICreate; + JITObjectImageCopy jitOICopy; + JITObjectImageDestroy jitOIDestroy; + JITObjectImageSize jitOISize; + JITObjectImageData jitOIData; + JITObjectImageFinalize jitOIFinalize; + JITObjectImageGetGlobalsSize jitOIGlobalSize; + JITObjectImageIterateSymbols jitOIIterateSymbols; + JITObjectImageDisassembleKernel jitOIDisassembleKernel; } aclCLLoader_0_8; //! Structure that holds the required functions diff --git a/rocclr/compiler/lib/include/v0_8/aclTypes.h b/rocclr/compiler/lib/include/v0_8/aclTypes.h index 0a0061e9ff..e500a1d46e 100644 --- a/rocclr/compiler/lib/include/v0_8/aclTypes.h +++ b/rocclr/compiler/lib/include/v0_8/aclTypes.h @@ -83,6 +83,16 @@ typedef CGPhase_0_8 CGPhase; typedef DisasmISA_0_8 DisasmISA; typedef AllocFunc_0_8 AllocFunc; typedef FreeFunc_0_8 FreeFunc; +typedef JITObjectImageCreate_0_8 JITObjectImageCreate; +typedef JITObjectImageCopy_0_8 JITObjectImageCopy; +typedef JITObjectImageDestroy_0_8 JITObjectImageDestroy; +typedef JITObjectImageSize_0_8 JITObjectImageSize; +typedef JITObjectImageData_0_8 JITObjectImageData; +typedef JITObjectImageFinalize_0_8 JITObjectImageFinalize; +typedef JITObjectImageGetGlobalsSize_0_8 JITObjectImageGetGlobalsSize; +typedef JITSymbolCallback_0_8 JITSymbolCallback; +typedef JITObjectImageIterateSymbols_0_8 JITObjectImageIterateSymbols; +typedef JITObjectImageDisassembleKernel_0_8 JITObjectImageDisassembleKernel; #include "aclStructs.h" diff --git a/rocclr/runtime/device/cpu/cpubinary.cpp b/rocclr/runtime/device/cpu/cpubinary.cpp index 6af382fb6f..b35d70b3bb 100644 --- a/rocclr/runtime/device/cpu/cpubinary.cpp +++ b/rocclr/runtime/device/cpu/cpubinary.cpp @@ -173,9 +173,12 @@ ClBinary::loadX86JIT(Program& program, bool& hasJITBinary) // force recompiling return true; } - - program.setJITBinary(aclJITObjectImageCopy(section, sz)); - + acl_error err = ACL_SUCCESS; + program.setJITBinary(aclJITObjectImageCopy(program.compiler(), section, sz, &err)); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageCopy failed"); + return false; + } hasJITBinary = true; return true; } @@ -192,10 +195,18 @@ bool ClBinary::storeX86JIT(Program& program) { if (saveISA()) { + acl_error err = ACL_SUCCESS; aclJITObjectImage objectImage = program.getJITBinary(); - const char* x86CodePtr = aclJITObjectImageData(objectImage); - size_t x86CodeSize = aclJITObjectImageSize(objectImage); - + size_t x86CodeSize = aclJITObjectImageSize(program.compiler(), objectImage, &err); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageSize failed"); + return false; + } + const char* x86CodePtr = aclJITObjectImageData(program.compiler(), objectImage, &err); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageData failed"); + return false; + } elfOut_->addSection(amd::OclElf::JITBINARY, x86CodePtr, x86CodeSize); } return true; diff --git a/rocclr/runtime/device/cpu/cpuprogram.cpp b/rocclr/runtime/device/cpu/cpuprogram.cpp index 5511aef197..1c81261cfa 100644 --- a/rocclr/runtime/device/cpu/cpuprogram.cpp +++ b/rocclr/runtime/device/cpu/cpuprogram.cpp @@ -26,9 +26,6 @@ #include "amdrt.inc" #endif -#include "acl.h" -#include "jit.h" - //CLC_IN_PROCESS_CHANGE extern int openclFrontEnd(const char* cmdline, std::string*, std::string* typInfo = NULL); @@ -416,9 +413,11 @@ setSymbolsCallbackCStr(const char* symbol, const void* value, void* data) { struct DisasData { public: DisasData(std::stringstream *stream, - aclJITObjectImage im) : asmstream(stream), image(im) {}; + aclJITObjectImage im, aclCompiler* cmpl) + : asmstream(stream), image(im), compiler(cmpl) {}; std::stringstream *asmstream; aclJITObjectImage image; + aclCompiler* compiler; }; #if defined(LEGACY_COMPLIB) @@ -428,6 +427,7 @@ disasSymbolsCallback(std::string symbol, const void* value, void* data) DisasData* disasData = (DisasData*) data; std::stringstream &asmstream = *(disasData->asmstream); aclJITObjectImage image = disasData->image; + aclCompiler* compiler = disasData->compiler; const char __OpenCL_[] = "__OpenCL_"; const char _stub[] = "_stub"; const char _kernel[] = "_kernel"; @@ -445,8 +445,13 @@ disasSymbolsCallback(std::string symbol, const void* value, void* data) if ((symbol.compare(suffixPos, sizeof(_stub) - 1, _stub) == 0) || (symbol.compare(suffixPos, sizeof(_kernel) - 1, _kernel) == 0)) { + acl_error err = ACL_SUCCESS; char* kernelDisas = - aclJITObjectImageDisassembleKernel(image, symbol.c_str()); + aclJITObjectImageDisassembleKernel(compiler, image, symbol.c_str(), &err); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageDisassembleKernel failed"); + return false; + } asmstream << kernelDisas; free(kernelDisas); } @@ -471,9 +476,9 @@ Program::compileBinaryToISA(amd::option::Options* options) std::string tempName = amd::Os::getTempFileName(); dllFileName_ = tempName + "." IF(IS_WINDOWS, "dll", "so"); - acl_error err; + acl_error err = ACL_SUCCESS; aclTargetInfo aclinfo = info(has_avx ? - /*has_fma4 ? "Bulldozer" :*/ + /*has_fma4 ? "Bulldozer" :*/ "Corei7_AVX" : "Athlon64"); @@ -554,8 +559,18 @@ Program::compileBinaryToISA(amd::option::Options* options) if (options->oVariables->UseJIT) { // printf("Using the jit!\n"); - aclJITObjectImage objectImage = aclJITObjectImageCreate(isa, len, bin); - aclJITObjectImageFinalize(objectImage); + aclJITObjectImage objectImage = aclJITObjectImageCreate(compiler(), isa, len, bin, &err); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageCreate failed"); + aclBinaryFini(bin); + return false; + } + err = aclJITObjectImageFinalize(compiler(), objectImage); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageFinalize failed"); + aclBinaryFini(bin); + return false; + } setJITBinary(objectImage); aclBinaryFini(bin); @@ -568,10 +583,14 @@ Program::compileBinaryToISA(amd::option::Options* options) #if 0 // Debug stuff. Try and disassemble all kernels and stubs std::stringstream asmtext; - DisasData disasData(&asmtext, objectImage); - aclJITObjectImageIterateSymbols(objectImage, + DisasData disasData(&asmtext, objectImage, compiler()); + err = aclJITObjectImageIterateSymbols(compiler(), objectImage, disasSymbolsCallbackCStr, &disasData); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageIterateSymbols failed"); + return false; + } printf("DisasSize: %d\nDisas: %s\n", (int)asmtext.str().size(), asmtext.str().c_str()); @@ -696,7 +715,7 @@ Program::compileImpl( f.close(); } - acl_error err; + acl_error err = ACL_SUCCESS; aclTargetInfo aclinfo = info(); aclBinaryOptions binOpts = {0}; @@ -830,12 +849,26 @@ bool Program::loadDllCode(amd::option::Options* options, bool addElfSymbols) { if(options->oVariables->UseJIT) { + acl_error err = ACL_SUCCESS; aclJITObjectImage objectImage = getJITBinary(); - aclJITObjectImageIterateSymbols(objectImage, setKernelInfoCallbackCStr, - this); - aclJITObjectImageIterateSymbols(objectImage, setSymbolsCallbackCStr, - clBinary()); - setGlobalVariableTotalSize(aclJITObjectImageGetGlobalsSize(objectImage)); + err = aclJITObjectImageIterateSymbols(compiler(), objectImage, + setKernelInfoCallbackCStr, this); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageIterateSymbols failed"); + return false; + } + err = aclJITObjectImageIterateSymbols(compiler(), objectImage, + setSymbolsCallbackCStr, clBinary()); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageIterateSymbols failed"); + return false; + } + size_t size = aclJITObjectImageGetGlobalsSize(compiler(), objectImage, &err); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageGetGlobalsSize failed"); + return false; + } + setGlobalVariableTotalSize(size); return true; } // Check if we have a URI @@ -888,10 +921,24 @@ Program::linkImpl(amd::option::Options* options) return false; } else if (hasJITBinary) { aclJITObjectImage objectImage = getJITBinary(); - aclJITObjectImageIterateSymbols(objectImage, setKernelInfoCallbackCStr, this); - aclJITObjectImageIterateSymbols(objectImage, setSymbolsCallbackCStr, clBinary()); - setGlobalVariableTotalSize(aclJITObjectImageGetGlobalsSize(objectImage)); - + acl_error err = aclJITObjectImageIterateSymbols(compiler(), objectImage, + setKernelInfoCallbackCStr, this); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageIterateSymbols failed"); + return false; + } + err = aclJITObjectImageIterateSymbols(compiler(), objectImage, + setSymbolsCallbackCStr, clBinary()); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageIterateSymbols failed"); + return false; + } + size_t size = aclJITObjectImageGetGlobalsSize(compiler(), objectImage, &err); + if (err != ACL_SUCCESS) { + LogWarning("aclJITObjectImageGetGlobalsSize failed"); + return false; + } + setGlobalVariableTotalSize(size); return true; } // Fall-through to recompile @@ -1184,7 +1231,7 @@ Program::createBinary(amd::option::Options* options) const aclTargetInfo & Program::info(const char * str) { - acl_error err; + acl_error err = ACL_SUCCESS; info_ = aclGetTargetInfo(LP64_SWITCH("x86", "x86-64"), ( str && str[0] == '\0' ? "Generic" : str ), &err); if (err != ACL_SUCCESS) { LogWarning("aclGetTargetInfo failed"); @@ -1195,7 +1242,7 @@ Program::info(const char * str) { Program::~Program() { if(getJITBinary() != NULL) { - aclJITObjectImageDestroy(getJITBinary()); + aclJITObjectImageDestroy(compiler(), getJITBinary()); } if (!sourceFileName_.empty()) { diff --git a/rocclr/runtime/device/cpu/cpuprogram.hpp b/rocclr/runtime/device/cpu/cpuprogram.hpp index 59a1f21dda..47fec428ba 100644 --- a/rocclr/runtime/device/cpu/cpuprogram.hpp +++ b/rocclr/runtime/device/cpu/cpuprogram.hpp @@ -10,8 +10,6 @@ #include "device/cpu/cpubinary.hpp" #include -#include "jit.h" - // forward declaration namespace amd { namespace option { @@ -95,9 +93,12 @@ public: aclJITObjectImage getJITBinary() { return this->JITBinary; } void setJITBinary(aclJITObjectImage JITBinary) { this->JITBinary = JITBinary; } -private: + //! Returns the pointer to the Compiler struct + //! Became public (prev. private) due to use in cpubinary for aclJIT functionality aclCompiler* compiler() { return static_cast(device()).compiler(); } +private: + //! Disable default copy constructor Program(const Program&);