summaryrefslogtreecommitdiffstats
path: root/llvm/include/llvm-opc.h
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/include/llvm-opc.h')
-rw-r--r--llvm/include/llvm-opc.h494
1 files changed, 494 insertions, 0 deletions
diff --git a/llvm/include/llvm-opc.h b/llvm/include/llvm-opc.h
new file mode 100644
index 0000000..9454dac
--- /dev/null
+++ b/llvm/include/llvm-opc.h
@@ -0,0 +1,494 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_OPC_H
+#define __LLVM_OPC_H
+
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "qemu-types.h"
+#include "llvm-types.h"
+#include "llvm-translator.h"
+#include "llvm.h"
+
+//#define ASSERT
+//#define VERIFY_TB
+
+
+#define IRDebug(idx) \
+ do { \
+ dbg() << DEBUG_ENTRY << "op_" << llvm_op_defs[idx].name << ": " \
+ << llvm_op_defs[idx].nb_oargs << " " \
+ << llvm_op_defs[idx].nb_iargs << " " \
+ << llvm_op_defs[idx].nb_cargs << "\n"; \
+ } while (0)
+#define IRError(fmt,args...) hqemu_error(fmt,##args)
+
+#ifdef ASSERT
+#define AssertType(t) \
+ do { \
+ if (!(t)) \
+ hqemu_error("invalid type.\n"); \
+ } while(0)
+#else
+#define AssertType(t)
+#endif
+
+#define IRAbort() \
+ do { \
+ if (!LLEnv->isTraceMode()) { \
+ Func->dump(); \
+ hqemu_error("fixme.\n"); \
+ } \
+ Builder->Abort(); \
+ } while (0)
+
+
+class LLVMTranslator;
+class NotifyInfo;
+class OptimizationInfo;
+
+
+/* Patch flags.
+ * NOTE: patch flags must be synchronized with those in the LLVM backend. */
+enum {
+ PATCH_HQEMU = 0x4182U,
+ PATCH_DUMMY,
+ PATCH_EXIT_TB,
+ PATCH_DIRECT_JUMP,
+ PATCH_TRACE_BLOCK_CHAINING,
+ PATCH_QMMU,
+};
+
+/*
+ * Register is used to describe the pseudo registers used by QEMU TCG op.
+ */
+struct Register {
+ /* Status of the register. */
+ enum {
+ STATE_NONE = 0x0,
+ STATE_REV = 0x1, /* Register is reserved */
+ STATE_REG = 0x2, /* Register is promoted */
+ STATE_MEM = 0x4, /* Register is in CPUArchState memory */
+ STATE_LOC = 0x8, /* Register is a local register */
+ STATE_TMP = 0x10, /* Register is a tmp register */
+ };
+
+ int State; /* State of the register */
+ int Base;
+ intptr_t Off; /* Register offset of CPUArchState */
+ int Size; /* Register size */
+ std::string Name; /* Name string of this register */
+ bool Dirty; /* This register is updated or not */
+ Type *Ty; /* Register type in LLVM */
+ Value *Data; /* Data value if this regisrer is promoted */
+ Value *AI; /* Register as Alloca */
+ Register *Alias;
+
+ Register() : State(STATE_NONE), Off(-1), Dirty(false), Ty(nullptr),
+ Data(nullptr), AI(nullptr), Alias(nullptr) {}
+
+ void set(int base, intptr_t off, std::string name) {
+ Base = base;
+ Off = off;
+ Name = name;
+ }
+ void reset(int state, int size, Type *ty) {
+ State = state;
+ Size = size;
+ Ty = ty;
+ Dirty = false;
+ Data = AI = nullptr;
+ }
+
+ void Promote() { State |= STATE_REG; }
+ void Demote() { State &= ~STATE_REG; }
+
+ Value *getData() { return Data; }
+ Register &getAlias() { return *Alias; }
+
+ void setState(int state) { State = state; }
+ void setData(Value *data, bool dirty = false) {
+ if (Alias) {
+ Alias->setData(data, dirty);
+ return;
+ }
+ Data = data;
+ Dirty = dirty;
+ Promote();
+ }
+ bool isRev() { return State & STATE_REV; }
+ bool isReg() { return State & STATE_REG; }
+ bool isMem() { return State & STATE_MEM; }
+ bool isLocal() { return State & STATE_LOC; }
+ bool isDirty() { return Dirty; }
+ bool isAlias() { return Alias != nullptr; }
+};
+
+/*
+ * TraceBuilder provides the facilities to build a trace in IRFactory.
+ */
+class TraceBuilder {
+ typedef std::map<target_ulong,
+ std::pair<GraphNode*, BasicBlock*> > NodeBuildMap;
+ typedef std::vector<std::pair<BranchInst*, GraphNode*> > BranchList;
+
+ IRFactory *IF;
+ OptimizationInfo *Opt;
+ GraphNode *CurrNode; /* The current CFG node to process */
+ NodeBuildMap Nodes;
+ BranchList Branches;
+ NodeVec NodeQueue; /* CFG nodes to be translated */
+ NodeSet NodeVisisted;
+ NodeVec NodeUsed;
+ bool Aborted;
+ uint32_t Attribute;
+
+ TraceInfo *Trace;
+
+public:
+ TraceBuilder(IRFactory *IRF, OptimizationInfo *Opt);
+ ~TraceBuilder() {}
+
+ void ConvertToTCGIR(CPUArchState *env);
+ void ConvertToLLVMIR();
+ void Abort();
+ void Finalize();
+ bool isAborted() { return Aborted; }
+
+ OptimizationInfo *getOpt() { return Opt; }
+ TraceInfo *getTrace() { return Trace; }
+ GraphNode *getEntryNode() { return Opt->getCFG(); }
+ GraphNode *getCurrNode() { return CurrNode; }
+ unsigned getNumNodes() { return Nodes.size(); }
+ std::string getPCString(GraphNode *Node) {
+ std::stringstream ss;
+ ss << std::hex << Node->getGuestPC();
+ return ss.str();
+ }
+
+ GraphNode *getNextNode() {
+ if (NodeQueue.empty())
+ return nullptr;
+ CurrNode = NodeQueue.back();
+ NodeQueue.pop_back();
+
+ if (NodeVisisted.find(CurrNode) != NodeVisisted.end())
+ return getNextNode();
+
+ NodeVisisted.insert(CurrNode);
+ NodeUsed.push_back(CurrNode);
+ return CurrNode;
+ }
+
+ target_ulong getGuestPC(GraphNode *Node) {
+#if defined(TARGET_I386)
+ return Node->getTB()->pc - Node->getTB()->cs_base;
+#else
+ return Node->getTB()->pc;
+#endif
+ }
+ void setUniqueNode(GraphNode *Node) {
+ target_ulong gpc = getGuestPC(Node);
+ if (Nodes.find(gpc) == Nodes.end())
+ Nodes[gpc] = std::make_pair(Node, nullptr);
+ }
+ void setBasicBlock(GraphNode *Node, BasicBlock *BB) {
+ target_ulong gpc = getGuestPC(Node);
+ if (Nodes.find(gpc) == Nodes.end())
+ hqemu_error("internal error.\n");
+ Nodes[gpc].second = BB;
+ }
+ void setBranch(BranchInst *BI, GraphNode *Node) {
+ Branches.push_back(std::make_pair(BI, Node));
+ target_ulong gpc = getGuestPC(Node);
+ if (!Nodes[gpc].second)
+ NodeQueue.push_back(Node);
+ }
+ GraphNode *getNode(target_ulong gpc) {
+ return Nodes.find(gpc) == Nodes.end() ? nullptr : Nodes[gpc].first;
+ }
+ BasicBlock *getBasicBlock(GraphNode *Node) {
+ target_ulong gpc = getGuestPC(Node);
+ if (Nodes.find(gpc) == Nodes.end())
+ hqemu_error("internal error.\n");
+ return Nodes[gpc].second;
+ }
+ void addAttribute(uint32_t Attr) {
+ Attribute |= Attr;
+ }
+};
+
+
+#define META_CONST "const"
+#define META_GVA "gva"
+#define META_LOOP "loop"
+#define META_EXIT "exit"
+#define META_CC "cc"
+
+class MDFactory {
+ uint32_t UID;
+ LLVMContext &Context;
+ MDNode *Dummy;
+
+ ConstantInt *getUID() {
+ return ConstantInt::get(IntegerType::get(Context, 32), UID++);
+ }
+
+public:
+ MDFactory(Module *M);
+ ~MDFactory();
+
+ MDNode *getMDNode(ArrayRef<ConstantInt*> V);
+ DebugLoc getDebugLoc(unsigned Line, unsigned Col, Function *F,
+ ArrayRef<ConstantInt*> Meta);
+
+ void setConst(Instruction *I) { I->setMetadata(META_CONST, Dummy); }
+ void setGuestMemory(Instruction *I) { I->setMetadata(META_GVA, Dummy); }
+ void setLoop(Instruction *I) { I->setMetadata(META_LOOP, Dummy); }
+ void setExit(Instruction *I) { I->setMetadata(META_EXIT, Dummy); }
+ void setCondition(Instruction *I) { I->setMetadata(META_CC, Dummy); }
+
+ static bool isConst(Instruction *I) {
+ return I->getMetadata(META_CONST);
+ }
+ static bool isGuestMemory(Instruction *I) {
+ return I->getMetadata(META_GVA);
+ }
+ static bool isLoop(Instruction *I) {
+ return I->getMetadata(META_LOOP);
+ }
+ static bool isExit(Instruction *I) {
+ return I->getMetadata(META_EXIT);
+ }
+ static bool isCondition(Instruction *I) {
+ return I->getMetadata(META_CC);
+ }
+
+ static void setConstStatic(LLVMContext &Context, Instruction *I,
+ ArrayRef<ConstantInt*> V);
+};
+
+/*
+ * IRFactory conducts QEMU TCG opcodes to LLVM IR conversion.
+ */
+class IRFactory {
+ typedef std::map<std::pair<intptr_t, Type *>, Value *> StatePtrMap;
+ typedef std::map<TCGArg, BasicBlock *> LabelMap;
+
+ enum {
+ COHERENCE_NONE = 0,
+ COHERENCE_GLOBAL,
+ COHERENCE_ALL,
+ };
+
+ bool InitOnce;
+
+ /* Basic types */
+ Type *VoidTy;
+ IntegerType *Int8Ty;
+ IntegerType *Int16Ty;
+ IntegerType *Int32Ty;
+ IntegerType *Int64Ty;
+ IntegerType *Int128Ty;
+ IntegerType *IntPtrTy;
+ PointerType *Int8PtrTy;
+ PointerType *Int16PtrTy;
+ PointerType *Int32PtrTy;
+ PointerType *Int64PtrTy;
+ Type *FloatTy;
+ Type *DoubleTy;
+ Type *FP80Ty;
+ Type *FP128Ty;
+
+ ConstantInt *ExitAddr;
+
+ LLVMTranslator &Translator; /* Uplink to the LLVMTranslator instance */
+ LLVMContext *Context; /* Translator local context */
+ Module *Mod; /* The LLVM module */
+ ExecutionEngine *EE; /* The JIT compiler */
+ EventListener *Listener; /* The JIT listener */
+ JITEventListener *IntelJIT; /* The Intel JIT listener */
+ const DataLayout *DL; /* Data layout */
+ TraceBuilder *Builder;
+ MDFactory *MF;
+ MCDisasm *HostDisAsm;
+
+ HelperMap &Helpers;
+ std::vector<BaseRegister> &BaseReg; /* TCG base register */
+ std::vector<Register> Reg; /* TCG virtual registers */
+ LabelMap Labels; /* TCG labels */
+ int Segment;
+ GuestBaseRegister &GuestBaseReg; /* Reserved guest base register */
+
+ Function *Func; /* The container of LLVM IR to be translated */
+ BasicBlock *InitBB; /* BasicBlock for variable decalaration */
+ BasicBlock *CurrBB; /* Current BasicBlock to insert LLVM IR */
+ BasicBlock *ExitBB; /* Temp BasicBlock as the exit-function stub */
+ BranchInst *LastInst; /* Position to insert LLVM IR */
+
+ Instruction *CPU; /* Base register with (char*) type */
+ Instruction *CPUStruct; /* Base register with (struct CPUArchState*) type */
+ Instruction *GEPInsertPos; /* Position to insert GEP instruction */
+
+ StatePtrMap StatePtr;
+ IVec InlineCalls; /* Helpers to be inlined */
+ std::map<std::string, BasicBlock*> CommonBB;
+ IVec IndirectBrs;
+ IVec toErase;
+ BBVec toSink;
+ std::set<Function *> ClonedFuncs;
+ bool runPasses;
+
+ void CreateJIT();
+ void DeleteJIT();
+
+ /* Initialize basic types used during IR conversion. */
+ void InitializeTypes();
+
+ /* Store dirty states back to CPU state in the memory. */
+ void SaveGlobals(int level, Instruction *InsertPos);
+
+ /* Sync PC to CPU state in the memory. */
+ void CreateStorePC(Instruction *InsertPos);
+
+ /* Get or insert the pointer to the CPU state. */
+ Value *StatePointer(Register &reg);
+ Value *StatePointer(Register &reg, intptr_t Off, Type *PTy);
+
+ /* Load value from the CPU state in the memory. */
+ Value *LoadState(Register &reg);
+ void StoreState(Register &reg, Instruction *InsertPos);
+
+ /* Load/Store data from/to the guest memory. */
+ Value *QEMULoad(Value *AddrL, Value *AddrH, TCGMemOpIdx oi);
+ void QEMUStore(Value *Data, Value *AddrL, Value *AddrH, TCGMemOpIdx oi);
+
+ Value *ConvertCPUType(Function *F, int Idx, Instruction *InsertPos);
+ Value *ConvertCPUType(Function *F, int Idx, BasicBlock *InsertPos);
+
+ Value *ConvertEndian(Value *V, int opc);
+ Value *getExtendValue(Value *V, Type *Ty, int opc);
+ Value *getTruncValue(Value *V, int opc);
+ int getSizeInBits(int opc) {
+ return 8 * (1 << (opc & MO_SIZE));
+ }
+
+ Value *ConcatTLBVersion(Value *GVA);
+
+ /* Return the LLVM instruction that stores PC. For the guest's register
+ * size larger than the host, replace the multiple store-PC instructions
+ * to one single store-PC instruction. */
+ StoreInst *getStorePC();
+
+ /* Create both chaining and exiting stubs. */
+ void InsertLinkAndExit(Instruction *InsertPos);
+
+ /* Create exit stub */
+ void InsertExit(uintptr_t RetVal, bool setExit = false);
+
+ /* Find the next node of a trace according to the brach pc.
+ * Return null if we cannot find one. */
+ GraphNode *findNextNode(target_ulong pc);
+
+ /* Perform internal linking of basic blocks to form a region. */
+ void TraceLink(StoreInst *SI);
+
+ /* Link basic blocks of direct branch. */
+ void TraceLinkDirectJump(GraphNode *NextNode, StoreInst *SI);
+ void TraceLinkDirectJump(StoreInst *SI);
+
+ /* Link basic blocks of indirect branch. */
+ void TraceLinkIndirectJump(GraphNode *NextNode, StoreInst *SI);
+
+ /* Insert code for IBTC hash table lookup. */
+ void InsertLookupIBTC(GraphNode *CurrNode);
+
+ /* Insert code for CPBL hash table lookup. */
+ void InsertLookupCPBL(GraphNode *CurrNode);
+
+ void TraceValidateCPBL(GraphNode *NextNode, StoreInst *StorePC);
+
+ /* Insert bswap intrinsic instruction. */
+ Value *CreateBSwap(Type *Ty, Value *V, Instruction *InsertPos);
+
+ /* Given the size, return its PointerType. */
+ PointerType *getPointerTy(int Size, unsigned AS = 0);
+
+ /* Analyze a helper function to determine if it will be inlined or not. */
+ int AnalyzeInlineCost(CallSite CS);
+
+ /* Perform helper function inlining. */
+ void ProcessInline();
+
+ void VerifyFunction(Function &F);
+
+ /* Legalize LLVM IR before running the pre-defined passes. */
+ void PreProcess();
+
+ void Optimize();
+
+ /* Legalize LLVM IR after running the pre-defined passes. */
+ void PostProcess();
+
+ void FinalizeObject();
+
+ void InitializeLLVMPasses(legacy::FunctionPassManager *FPM);
+
+ uint32_t setRestorePoint(TCGMemOpIdx oi) {
+ if (oi != (uint16_t)oi)
+ hqemu_error("key value too large.\n");
+ return (NI.setRestorePoint() << 16) | oi;
+ }
+
+public:
+ typedef void (IRFactory::*FuncPtr)(const TCGArg *);
+
+ NotifyInfo &NI; /* Info to pass among translator and JIT */
+
+ /* QEMU TCG IR to LLVM IR converion routines. */
+#define DEF(name, oargs, iargs, cargs, flags) void op_ ## name(const TCGArg *);
+#include "tcg-opc.h"
+#undef DEF
+
+ IRFactory(LLVMTranslator *Trans);
+ ~IRFactory();
+
+ void CreateSession(TraceBuilder *builder);
+ void DeleteSession();
+
+ /* Prepare the initial LLVM Function, BasicBlocks and variables. */
+ void CreateFunction();
+ void CreateBlock();
+
+ /* Start LLVM JIT compilation. */
+ void Compile();
+
+ /* Set instruction BI to jump to the basic block BB. */
+ void setSuccessor(BranchInst *BI, BasicBlock *BB);
+
+ /* Get function pointer of the IR converion routines. */
+ void *getOpcFunc();
+
+ Function *ResolveFunction(std::string Name);
+
+ LLVMTranslator &getTranslator() { return Translator; }
+ LLVMContext &getContext() { return *Context; }
+ const DataLayout *getDL() { return DL; }
+ MDFactory *getMDFactory() { return MF; }
+ HelperMap &getHelpers() { return Helpers; }
+ TraceInfo *getTrace() { return Builder->getTrace(); }
+ Value *getGuestBase() { return GuestBaseReg.Base; }
+ Instruction *getDefaultCPU(Function &F);
+
+public:
+ static bool isStateOfPC(intptr_t Off);
+};
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
OpenPOWER on IntegriCloud