C++程序  |  202行  |  6.5 KB

/****************************************************************************
* Copyright (C) 2014-2015 Intel Corporation.   All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* @file JitManager.h
*
* @brief JitManager contains the LLVM data structures used for JIT generation
*
* Notes:
*
******************************************************************************/
#pragma once

#include "jit_pch.hpp"
#include "common/isa.hpp"


//////////////////////////////////////////////////////////////////////////
/// JitInstructionSet
/// @brief Subclass of InstructionSet that allows users to override
/// the reporting of support for certain ISA features.  This allows capping
/// the jitted code to a certain feature level, e.g. jit AVX level code on 
/// a platform that supports AVX2.
//////////////////////////////////////////////////////////////////////////
class JitInstructionSet : public InstructionSet
{
public:
    JitInstructionSet(const char* requestedIsa) : isaRequest(requestedIsa)
    {
        std::transform(isaRequest.begin(), isaRequest.end(), isaRequest.begin(), ::tolower);

        if(isaRequest == "avx")
        {
            bForceAVX = true;
            bForceAVX2 = false;
            bForceAVX512 = false;
        }
        else if(isaRequest == "avx2")
        {
            bForceAVX = false;
            bForceAVX2 = true;
            bForceAVX512 = false;
        }
        else if(isaRequest == "avx512")
        {
            bForceAVX = false;
            bForceAVX2 = false;
            bForceAVX512 = true;
        }
    };

    bool AVX2(void) { return bForceAVX ? 0 : InstructionSet::AVX2(); }
    bool AVX512F(void) { return (bForceAVX | bForceAVX2) ? 0 : InstructionSet::AVX512F(); }
    bool BMI2(void) { return bForceAVX ? 0 : InstructionSet::BMI2(); }

private:
    bool bForceAVX = false;
    bool bForceAVX2 = false;
    bool bForceAVX512 = false;
    std::string isaRequest;
};



struct JitLLVMContext : llvm::LLVMContext
{
};


//////////////////////////////////////////////////////////////////////////
/// JitCache
//////////////////////////////////////////////////////////////////////////
struct JitManager; // Forward Decl
class JitCache : public llvm::ObjectCache
{
public:
    /// constructor
    JitCache();
    virtual ~JitCache() {}

    void Init(
        JitManager* pJitMgr,
        const llvm::StringRef& cpu,
        llvm::CodeGenOpt::Level level)
    {
        mCpu = cpu.str();
        mpJitMgr = pJitMgr;
        mOptLevel = level;
    }

    /// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
    virtual void notifyObjectCompiled(const llvm::Module *M, llvm::MemoryBufferRef Obj);

    /// Returns a pointer to a newly allocated MemoryBuffer that contains the
    /// object which corresponds with Module M, or 0 if an object is not
    /// available.
    virtual std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* M);

private:
    std::string mCpu;
    llvm::SmallString<MAX_PATH> mCacheDir;
    uint32_t mCurrentModuleCRC = 0;
    JitManager* mpJitMgr = nullptr;
    llvm::CodeGenOpt::Level mOptLevel = llvm::CodeGenOpt::None;
};

//////////////////////////////////////////////////////////////////////////
/// JitManager
//////////////////////////////////////////////////////////////////////////
struct JitManager
{
    JitManager(uint32_t w, const char* arch, const char* core);
    ~JitManager(){};

    JitLLVMContext          mContext;   ///< LLVM compiler
    llvm::IRBuilder<>       mBuilder;   ///< LLVM IR Builder
    llvm::ExecutionEngine*  mpExec;
    JitCache                mCache;

    // Need to be rebuilt after a JIT and before building new IR
    llvm::Module* mpCurrentModule;
    bool mIsModuleFinalized;
    uint32_t mJitNumber;

    uint32_t                 mVWidth;


    // Built in types.
    llvm::Type*                mInt8Ty;
    llvm::Type*                mInt32Ty;
    llvm::Type*                mInt64Ty;
    llvm::Type*                mFP32Ty;

    llvm::Type* mSimtFP32Ty;
    llvm::Type* mSimtInt32Ty;

    llvm::Type* mSimdVectorInt32Ty;
    llvm::Type* mSimdVectorTy;

#if USE_SIMD16_SHADERS
    llvm::Type* mSimd16FP32Ty;
    llvm::Type* mSimd16Int32Ty;

    llvm::Type* mSimd16VectorFP32Ty;
    llvm::Type* mSimd16VectorInt32Ty;

#endif
    // fetch shader types
    llvm::FunctionType*        mFetchShaderTy;

    JitInstructionSet mArch;
    std::string mCore;

    // Debugging support
    std::unordered_map<llvm::StructType*, llvm::DIType*> mDebugStructMap;

    void SetupNewModule();

    void DumpAsm(llvm::Function* pFunction, const char* fileName);
    static void DumpToFile(llvm::Function *f, const char *fileName);
    static void DumpToFile(llvm::Module *M, const char *fileName);
    static std::string GetOutputDir();

    // Debugging support methods
    llvm::DIType* GetDebugType(llvm::Type* pTy);
    llvm::DIType* GetDebugIntegerType(llvm::Type* pTy);
    llvm::DIType* GetDebugArrayType(llvm::Type* pTy);
    llvm::DIType* GetDebugVectorType(llvm::Type* pTy);
    llvm::DIType* GetDebugFunctionType(llvm::Type* pTy);

    llvm::DIType* GetDebugStructType(llvm::Type* pType)
    {
        llvm::StructType* pStructTy = llvm::cast<llvm::StructType>(pType);
        if (mDebugStructMap.find(pStructTy) == mDebugStructMap.end())
        {
            return nullptr;
        }
        return mDebugStructMap[pStructTy];
    }

    llvm::DIType* CreateDebugStructType(llvm::StructType* pType, const std::string& name, llvm::DIFile* pFile, uint32_t lineNum,
        const std::vector<std::pair<std::string, uint32_t>>& members);
};