summaryrefslogtreecommitdiffstats
path: root/llvm/include/llvm-opc.h
blob: 9454dac6e540fb39da2f2df838eb486ea35c40ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
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