summaryrefslogtreecommitdiffstats
path: root/src/llvm
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineering.com>2019-05-11 15:12:49 -0500
committerTimothy Pearson <tpearson@raptorengineering.com>2019-05-11 15:12:49 -0500
commit9e80202352dd49bdd9e67b8b906d86f058431505 (patch)
tree5673c17aad6e3833da8c4ff21b5a11f666ec9fbe /src/llvm
downloadhqemu-9e80202352dd49bdd9e67b8b906d86f058431505.zip
hqemu-9e80202352dd49bdd9e67b8b906d86f058431505.tar.gz
Initial import of abandoned HQEMU version 2.5.2HEADmaster
Diffstat (limited to 'src/llvm')
-rw-r--r--src/llvm/analysis/InnerLoopAnalysis.cpp631
-rw-r--r--src/llvm/atomic/atomic-arm.c158
-rw-r--r--src/llvm/atomic/atomic-helper.h74
-rw-r--r--src/llvm/atomic/atomic-x86.c504
-rw-r--r--src/llvm/atomic/coremu-atomic.h412
-rw-r--r--src/llvm/atomic/coremu-template.h101
-rw-r--r--src/llvm/fpu/softfloat-native-def.h127
-rw-r--r--src/llvm/fpu/softfloat-native.h248
-rw-r--r--src/llvm/hqemu-helper.c77
-rw-r--r--src/llvm/hqemu.mk191
-rw-r--r--src/llvm/include/InnerLoopAnalysis.h291
-rw-r--r--src/llvm/include/JIT.h228
-rw-r--r--src/llvm/include/JITMemoryManager.h318
-rw-r--r--src/llvm/include/MCJITMemoryManager.h213
-rw-r--r--src/llvm/include/hqemu-config.h142
-rw-r--r--src/llvm/include/hqemu-helper.h8
-rw-r--r--src/llvm/include/hqemu.h84
-rw-r--r--src/llvm/include/llvm-annotate.h51
-rw-r--r--src/llvm/include/llvm-debug.h247
-rw-r--r--src/llvm/include/llvm-hard-perfmon.h87
-rw-r--r--src/llvm/include/llvm-helper.h755
-rw-r--r--src/llvm/include/llvm-macro.h88
-rw-r--r--src/llvm/include/llvm-opc.h494
-rw-r--r--src/llvm/include/llvm-pass.h205
-rw-r--r--src/llvm/include/llvm-soft-perfmon.h74
-rw-r--r--src/llvm/include/llvm-state.h194
-rw-r--r--src/llvm/include/llvm-target.h116
-rw-r--r--src/llvm/include/llvm-translator.h270
-rw-r--r--src/llvm/include/llvm-types.h127
-rw-r--r--src/llvm/include/llvm.h278
-rw-r--r--src/llvm/include/optimization.h261
-rw-r--r--src/llvm/include/pmu/arm/arm-events.h35
-rw-r--r--src/llvm/include/pmu/perf_event.h992
-rw-r--r--src/llvm/include/pmu/pmu-events.h131
-rw-r--r--src/llvm/include/pmu/pmu-global.h52
-rw-r--r--src/llvm/include/pmu/pmu-utils.h106
-rw-r--r--src/llvm/include/pmu/pmu.h170
-rw-r--r--src/llvm/include/pmu/ppc/ppc-events.h30
-rw-r--r--src/llvm/include/pmu/x86/x86-events.h38
-rw-r--r--src/llvm/include/qemu-types.h33
-rw-r--r--src/llvm/include/tcg-opc-vector.h80
-rw-r--r--src/llvm/include/tracer.h109
-rw-r--r--src/llvm/include/utils.h260
-rw-r--r--src/llvm/llvm-annotate.cpp136
-rw-r--r--src/llvm/llvm-debug.cpp229
-rw-r--r--src/llvm/llvm-hard-perfmon.cpp289
-rw-r--r--src/llvm/llvm-opc-mmu.cpp344
-rw-r--r--src/llvm/llvm-opc-vector.cpp943
-rw-r--r--src/llvm/llvm-opc.cpp4431
-rw-r--r--src/llvm/llvm-soft-perfmon.cpp357
-rw-r--r--src/llvm/llvm-target.cpp812
-rw-r--r--src/llvm/llvm-translator.cpp924
-rw-r--r--src/llvm/llvm.cpp1251
-rw-r--r--src/llvm/optimization.cpp317
-rw-r--r--src/llvm/pass/CombineCasts.cpp321
-rw-r--r--src/llvm/pass/CombineGuestMemory.cpp389
-rw-r--r--src/llvm/pass/CombineZExtTrunc.cpp70
-rw-r--r--src/llvm/pass/FastMathPass.cpp87
-rw-r--r--src/llvm/pass/ProfileExec.cpp172
-rw-r--r--src/llvm/pass/RedundantStateElimination.cpp179
-rw-r--r--src/llvm/pass/ReplaceIntrinsic.cpp137
-rw-r--r--src/llvm/pass/SimplifyPointer.cpp334
-rw-r--r--src/llvm/pass/StateMappingPass.cpp885
-rw-r--r--src/llvm/pmu/arm/arm-events.cpp42
-rw-r--r--src/llvm/pmu/pmu-events.cpp414
-rw-r--r--src/llvm/pmu/pmu.cpp491
-rw-r--r--src/llvm/pmu/ppc/ppc-events.cpp37
-rw-r--r--src/llvm/pmu/x86/x86-events.cpp41
-rw-r--r--src/llvm/tracer.cpp365
-rw-r--r--src/llvm/utils.cpp223
-rw-r--r--src/llvm/xml/tinyxml2.cpp2013
-rw-r--r--src/llvm/xml/tinyxml2.h1480
72 files changed, 26803 insertions, 0 deletions
diff --git a/src/llvm/analysis/InnerLoopAnalysis.cpp b/src/llvm/analysis/InnerLoopAnalysis.cpp
new file mode 100644
index 0000000..f67d380
--- /dev/null
+++ b/src/llvm/analysis/InnerLoopAnalysis.cpp
@@ -0,0 +1,631 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/Analysis/ScalarEvolutionExpander.h"
+#include "llvm-debug.h"
+#include "llvm-opc.h"
+#include "llvm-pass.h"
+#include "InnerLoopAnalysis.h"
+
+
+/*
+ * The InnertLoop class represents a single innermost loop. The shape of
+ * InnerLoop is specific to the DBT decoded guest loop, and its loop definition
+ * is different to a nature loop, e.g., latch and exiting block.
+ * For example, the binary of a nature loop (a) will be translated to the loop
+ * CFG (b), which includes an additional block L(loopback) to check flag
+ * `tcg_exit_req' and exits the loop to block E if the flag is raised, otherwise,
+ * goes back to the loop header A.
+ *
+ * In loop (b), a latch is split into two blocks, B and L. The loop bottom test
+ * is in block B and the backward branch is included in block L (which also
+ * has an exit block E attached to it). We include block L in the loop body and
+ * have the following definitions: (1) block B and L are latch head and tail,
+ * respectively; (2) a latch tail is the source of a backedge; (3) block B is a
+ * loop exiting block, but block L is not, and block E is not included in the
+ * exit blocks.
+ *
+ * (a) A (b) A
+ * || |
+ * B B
+ * / / \
+ * C C L -> A
+ * \
+ * E
+ */
+InnerLoop::InnerLoop(Loop *loop)
+ : TheLoop(*loop), Blocks(TheLoop.getBlocks()), UnknownPhi(false)
+{
+ for (auto BB : Blocks)
+ DenseBlockSet.insert(BB);
+
+ /* Find all latches and split latches. */
+ SmallVector<BasicBlock *, 8> LoopLatches;
+ TheLoop.getLoopLatches(LoopLatches);
+ for (BasicBlock *BB : LoopLatches) {
+ Latches.push_back(BB);
+
+ if (MDFactory::isLoop(BB->getTerminator()) &&
+ BB->getSinglePredecessor()) {
+ /* Map latch tail to latch head. */
+ SplitLatches[BB] = BB->getSinglePredecessor();
+ }
+ }
+}
+
+
+/* True if terminator in the block can branch to another block that is
+ * outside of the current loop. */
+bool InnerLoop::isLoopExiting(BasicBlock *BB) const
+{
+ if (SplitLatches.find(BB) != SplitLatches.end())
+ return false;
+
+ typedef GraphTraits<const BasicBlock*> BlockTraits;
+ for (typename BlockTraits::ChildIteratorType SI =
+ BlockTraits::child_begin(BB),
+ SE = BlockTraits::child_end(BB); SI != SE; ++SI) {
+ if (!contains(*SI))
+ return true;
+ }
+ return false;
+}
+
+/* Calculate the number of back edges to the loop header. */
+unsigned InnerLoop::getNumBackEdges() const
+{
+ unsigned NumBackEdges = 0;
+ BasicBlock *H = getHeader();
+
+ typedef GraphTraits<Inverse<BasicBlock*> > InvBlockTraits;
+ for (typename InvBlockTraits::ChildIteratorType I =
+ InvBlockTraits::child_begin(H),
+ E = InvBlockTraits::child_end(H); I != E; ++I)
+ if (contains(*I))
+ ++NumBackEdges;
+
+ return NumBackEdges;
+}
+
+/* Return all blocks inside the loop that have successors outside of the loop. */
+void InnerLoop::getExitingBlocks(SmallVectorImpl<BasicBlock *> &ExitingBlocks) const
+{
+ typedef GraphTraits<BasicBlock *> BlockTraits;
+ for (block_iterator BI = block_begin(), BE = block_end(); BI != BE; ++BI) {
+ /* Skip the latch tail block. */
+ if (SplitLatches.find(*BI) != SplitLatches.end())
+ continue;
+
+ for (typename BlockTraits::ChildIteratorType I =
+ BlockTraits::child_begin(*BI), E = BlockTraits::child_end(*BI);
+ I != E; ++I)
+ if (!contains(*I)) {
+ /* Not in current loop? It must be an exit block. */
+ ExitingBlocks.push_back(*BI);
+ break;
+ }
+ }
+}
+
+/* If getExitingBlocks would return exactly one block, return that block.
+ * Otherwise return null. */
+BasicBlock *InnerLoop::getExitingBlock() const
+{
+ SmallVector<BasicBlock *, 8> ExitingBlocks;
+ getExitingBlocks(ExitingBlocks);
+ if (ExitingBlocks.size() == 1)
+ return ExitingBlocks[0];
+ return nullptr;
+}
+
+/* Return all of the successor blocks of this loop. */
+void InnerLoop::getExitBlocks(SmallVectorImpl<BasicBlock *> &ExitBlocks) const
+{
+ typedef GraphTraits<BasicBlock *> BlockTraits;
+ for (block_iterator BI = block_begin(), BE = block_end(); BI != BE; ++BI) {
+ /* Skip the latch tail block. */
+ if (SplitLatches.find(*BI) != SplitLatches.end())
+ continue;
+
+ for (typename BlockTraits::ChildIteratorType I =
+ BlockTraits::child_begin(*BI), E = BlockTraits::child_end(*BI);
+ I != E; ++I)
+ if (!contains(*I))
+ /* Not in current loop? It must be an exit block. */
+ ExitBlocks.push_back(*I);
+ }
+}
+
+/* If getExitBlocks would return exactly one block, return that block.
+ * Otherwise return null. */
+BasicBlock *InnerLoop::getExitBlock() const
+{
+ SmallVector<BasicBlock *, 8> ExitBlocks;
+ getExitBlocks(ExitBlocks);
+ if (ExitBlocks.size() == 1)
+ return ExitBlocks[0];
+ return nullptr;
+}
+
+/* If there is a preheader for this loop, return it. A loop has a preheader
+ * if there is only one edge to the header of the loop from outside of the
+ * loop. If this is the case, the block branching to the header of the loop
+ * is the preheader node.
+ *
+ * This method returns null if there is no preheader for the loop. */
+BasicBlock *InnerLoop::getLoopPreheader() const
+{
+ /* Keep track of nodes outside the loop branching to the header. */
+ BasicBlock *Out = getLoopPredecessor();
+ if (!Out) return nullptr;
+
+ /* Make sure there is only one exit out of the preheader. */
+ typedef GraphTraits<BasicBlock *> BlockTraits;
+ typename BlockTraits::ChildIteratorType SI = BlockTraits::child_begin(Out);
+ ++SI;
+ if (SI != BlockTraits::child_end(Out))
+ return nullptr; /* Multiple exits from the block, must not be a preheader. */
+
+ /* The predecessor has exactly one successor, so it is a preheader. */
+ return Out;
+}
+
+/* If the given loop's header has exactly one unique predecessor outside the
+ * loop, return it. Otherwise return null.
+ * This is less strict that the loop "preheader" concept, which requires
+ * the predecessor to have exactly one successor. */
+BasicBlock *InnerLoop::getLoopPredecessor() const
+{
+ /* Keep track of nodes outside the loop branching to the header. */
+ BasicBlock *Out = nullptr;
+
+ /* Loop over the predecessors of the header node. */
+ BasicBlock *Header = getHeader();
+#if defined(LLVM_V35) || defined(LLVM_V38) || defined(LLVM_V39)
+ typedef GraphTraits<Inverse<BasicBlock *> > InvBlockTraits;
+ for (typename InvBlockTraits::ChildIteratorType PI =
+ InvBlockTraits::child_begin(Header),
+ PE = InvBlockTraits::child_end(Header); PI != PE; ++PI) {
+ typename InvBlockTraits::NodeType *N = *PI;
+ if (!contains(N)) { /* If the block is not in the loop. */
+ if (Out && Out != N)
+ return nullptr; /* Multiple predecessors outside the loop */
+ Out = N;
+ }
+ }
+#else
+ for (const auto Pred : children<Inverse<BasicBlock *> >(Header)) {
+ if (!contains(Pred)) { /* If the block is not in the loop. */
+ if (Out && Out != Pred)
+ return nullptr; /* Multiple predecessors outside the loop */
+ Out = Pred;
+ }
+ }
+#endif
+
+ return Out;
+}
+
+bool InnerLoop::isReachable(Instruction *From, Instruction *To)
+{
+ if (!contains(From->getParent()) || !contains(To->getParent()))
+ return false;
+ if (From == To)
+ return true;
+
+ SmallPtrSet<Instruction*, 8> Visited;
+ SmallVector<Instruction*, 8> VisitStack;
+
+ VisitStack.push_back(From);
+ while (!VisitStack.empty()) {
+ Instruction *I = VisitStack.back();
+ VisitStack.pop_back();
+
+ if (Visited.count(I))
+ continue;
+
+ Visited.insert(I);
+ for (User *U : I->users()) {
+ Instruction *UI = cast<Instruction>(U);
+ if (UI == To)
+ return true;
+
+ if (contains(UI->getParent()))
+ VisitStack.push_back(UI);
+ }
+ }
+
+ return false;
+}
+
+
+/*
+ * InnerLoopAnalysis
+ */
+static void addInnerLoop(Loop &L, std::vector<Loop *> &Loops)
+{
+ if (L.empty()) {
+ /* Innermost loop.
+ * If any basic block of current loop has been included in another
+ * loop, skip this loop. */
+ for (Loop *InnerL : Loops) {
+ for (auto I = L.begin(), E = L.end(); I != E; ++I) {
+ if (InnerL->contains(*I))
+ return;
+ }
+ }
+ Loops.push_back(&L);
+ return;
+ }
+ for (Loop *InnerL : L)
+ addInnerLoop(*InnerL, Loops);
+}
+
+
+void InnerLoopAnalysis::analyze(LoopInfo *LI, ScalarEvolution *SE)
+{
+ std::vector<Loop *> Loops;
+ for (Loop *L : *LI)
+ addInnerLoop(*L, Loops);
+
+ for (auto L : Loops)
+ InnerLoops.push_back(new InnerLoop(L));
+
+ for (auto L : InnerLoops)
+ analyzePhi(*L, SE);
+}
+
+bool InnerLoopAnalysis::analyzeInduction(InnerLoop &TheLoop,
+ ScalarEvolution *SE,
+ PHINode *Phi)
+{
+ Type *PhiTy = Phi->getType();
+ /* We only handle integer and pointer inductions variables. */
+ if (!PhiTy->isIntegerTy() && !PhiTy->isPointerTy())
+ return false;
+
+ /* We only handle induction that has no outside users (except that the
+ * outside users are all stores.) */
+ for (User *U : Phi->users()) {
+ Instruction *UI = cast<Instruction>(U);
+ if (!TheLoop.contains(UI) && !isa<StoreInst>(UI))
+ return false;
+ }
+
+ const SCEV *PhiScev = SE->getSCEV(Phi);
+ const auto *AR = dyn_cast<SCEVAddRecExpr>(PhiScev);
+ if (!AR)
+ return false;
+
+ const SCEV *Step = AR->getStepRecurrence(*SE);
+ const SCEVConstant *ConstStep = dyn_cast<SCEVConstant>(Step);
+ if (!ConstStep && !SE->isLoopInvariant(Step, AR->getLoop()))
+ return false;
+
+ /* We found an induction variable. */
+ Value *StartValue =
+ Phi->getIncomingValueForBlock(AR->getLoop()->getLoopPreheader());
+ TheLoop.addInduction(Phi, StartValue, Step);
+
+ return true;
+}
+
+/*
+ * isReductionInstr()
+ * Check if the reduction operation is supported.
+ * We don't allow a reduction to bind more than one operation, so drop a
+ * reduction if it already has one operation.
+ */
+static bool isReductionInstr(Instruction *I, ReductionDesc::ReductionKind &Kind,
+ Type *&Ty)
+{
+ ReductionDesc::ReductionKind K = ReductionDesc::NoReduction;
+ switch (I->getOpcode()) {
+ default:
+ return false;
+ case Instruction::PHI:
+ case Instruction::BitCast:
+ return true;
+ case Instruction::Add:
+ case Instruction::Sub:
+ K = ReductionDesc::IntegerAdd;
+ break;
+ case Instruction::Mul:
+ K = ReductionDesc::IntegerMult;
+ break;
+ case Instruction::And:
+ K = ReductionDesc::IntegerAnd;
+ break;
+ case Instruction::Or:
+ K = ReductionDesc::IntegerOr;
+ break;
+ case Instruction::Xor:
+ K = ReductionDesc::IntegerXor;
+ break;
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ K = ReductionDesc::FloatAdd;
+ break;
+ case Instruction::FMul:
+ K = ReductionDesc::FloatMult;
+ break;
+ }
+
+ if (VectorType *VecTy = dyn_cast<VectorType>(I->getType()))
+ Ty = VecTy->getScalarType();
+ else
+ Ty = I->getType();
+
+ if (Kind == ReductionDesc::NoReduction) {
+ Kind = K;
+ return true;
+ }
+
+ if (Kind != K) {
+ /* Different reduction operation to the previous one. */
+ return false;
+ }
+ return true;
+}
+
+static bool hasMultipleUsesOf(Instruction *I,
+ SmallPtrSet<Instruction *, 8> &Insts)
+{
+ unsigned NumUses = 0;
+ for(User::op_iterator Use = I->op_begin(), E = I->op_end(); Use != E; ++Use) {
+ if (Insts.count(dyn_cast<Instruction>(*Use)))
+ ++NumUses;
+ if (NumUses > 1)
+ return true;
+ }
+ return false;
+}
+
+static bool isLegalUser(Instruction *I)
+{
+ if (isa<StoreInst>(I) && !MDFactory::isGuestMemory(I))
+ return true;
+ return false;
+}
+
+bool InnerLoopAnalysis::analyzeReduction(InnerLoop &TheLoop, PHINode *Phi)
+{
+ if (Phi->getNumIncomingValues() != 2)
+ return false;
+
+ /* Reduction variables are only found in the loop header block. */
+ if (Phi->getParent() != TheLoop.getHeader())
+ return false;
+
+ /* Obtain the reduction start value from from the loop preheader. */
+ Value *StartValue = Phi->getIncomingValueForBlock(TheLoop.getLoopPreheader());
+
+ /* ExitInstruction is the single value which is used outside the loop.
+ * We only allow for a single reduction value to be used outside the loop.
+ * This includes users of the reduction, variables (which form a cycle
+ * which ends in the phi node). */
+ Instruction *ExitInstruction = nullptr;
+ /* Indicates that we found a reduction operation in our scan. */
+ bool FoundReduxOp = false;
+
+ /* We start with the PHI node and scan for all of the users of this
+ * instruction. All users must be instructions that can be used as reduction
+ * variables (such as ADD). We must have a single out-of-block user. The cycle
+ * must include the original PHI. */
+ bool FoundStartPHI = false;
+
+ ReductionDesc::ReductionKind Kind = ReductionDesc::NoReduction;
+ Type *Ty = nullptr;
+
+ SmallPtrSet<Instruction *, 8> VisitedInsts;
+ SmallVector<Instruction *, 8> Worklist;
+ Worklist.push_back(Phi);
+ VisitedInsts.insert(Phi);
+
+ /* A value in the reduction can be used:
+ * - By the reduction:
+ * - Reduction operation:
+ * - One use of reduction value (safe).
+ * - Multiple use of reduction value (not safe).
+ * - PHI:
+ * - All uses of the PHI must be the reduction (safe).
+ * - Otherwise, not safe.
+ * - By one or no instruction outside of the loop (safe).
+ * - By further instructions outside of the loop (not safe).
+ * - By an instruction that is not part of the reduction (not safe).
+ * This is either:
+ * An instruction type other than PHI or the reduction operation.
+ * A PHI in the header other than the initial PHI. */
+ while (!Worklist.empty()) {
+ Instruction *Cur = Worklist.back();
+ Worklist.pop_back();
+
+ /* No Users.
+ * If the instruction has no users then this is a broken chain and
+ * cannot be a reduction variable. */
+ if (Cur->use_empty())
+ return false;
+
+ bool IsAPhi = isa<PHINode>(Cur);
+ bool IsBitCast = isa<BitCastInst>(Cur);
+
+ /* Currenly, we don't handle a reduction used by another PHI other than
+ * the original PHI. */
+ if (IsAPhi && Cur != Phi)
+ return false;
+
+ /* Any reduction instruction must be of one of the allowed kinds. */
+ if (!isReductionInstr(Cur, Kind, Ty))
+ return false;
+
+ /* Reductions of instructions such as Div, and Sub is only possible if the
+ * LHS is the reduction variable. */
+ if (!IsAPhi && !Cur->isCommutative() &&
+ !VisitedInsts.count(dyn_cast<Instruction>(Cur->getOperand(0))))
+ return false;
+
+ /* A reduction operation must only have one use of the reduction value. */
+ if (!IsAPhi && hasMultipleUsesOf(Cur, VisitedInsts))
+ return false;
+
+ /* Check whether we found a reduction operator. */
+ FoundReduxOp |= (!IsAPhi && !IsBitCast);
+
+ /* Process users of current instruction. Push non-PHI nodes after PHI
+ * nodes onto the stack. This way we are going to have seen all inputs
+ * to PHI nodes once we get to them. */
+ SmallVector<Instruction *, 8> NonPHIs;
+ SmallVector<Instruction *, 8> PHIs;
+ for (User *U : Cur->users()) {
+ Instruction *UI = cast<Instruction>(U);
+
+ if (isLegalUser(UI))
+ continue;
+
+ /* Check if we found the exit user. */
+ BasicBlock *Parent = UI->getParent();
+ if (!TheLoop.contains(Parent)) {
+ /* Exit if you find multiple outside users or if the header phi node is
+ * being used. In this case the user uses the value of the previous
+ * iteration, in which case we would loose "VF-1" iterations of the
+ * reduction operation if we vectorize. */
+ if (ExitInstruction != nullptr || Cur == Phi)
+ return false;
+
+ /* The instruction used by an outside user must be the last instruction
+ * before we feed back to the reduction phi. Otherwise, we loose VF-1
+ * operations on the value. */
+ if (std::find(Phi->op_begin(), Phi->op_end(), Cur) == Phi->op_end())
+ return false;
+
+ ExitInstruction = Cur;
+ continue;
+ }
+
+ /* Process instructions only once (termination). Each reduction cycle
+ * value must only be used once, except by phi nodes and min/max
+ * reductions which are represented as a cmp followed by a select. */
+ if (!VisitedInsts.count(UI)) {
+ VisitedInsts.insert(UI);
+ if (isa<PHINode>(UI))
+ PHIs.push_back(UI);
+ else
+ NonPHIs.push_back(UI);
+ } else if (!isa<PHINode>(UI))
+ return false;
+
+ /* Remember that we completed the cycle. */
+ if (UI == Phi)
+ FoundStartPHI = true;
+ }
+ Worklist.append(PHIs.begin(), PHIs.end());
+ Worklist.append(NonPHIs.begin(), NonPHIs.end());
+ }
+
+ /* Set the exit instruction to the last instruction feed back to the
+ * reduction phi if we cannot find an exit instruction. */
+ if (!ExitInstruction) {
+ Value *NextValue = Phi->getIncomingValueForBlock(TheLoop.getSingleLatchTail());
+ if (!isa<Instruction>(NextValue))
+ return false;
+ ExitInstruction = cast<Instruction>(NextValue);
+ }
+
+ if (!FoundStartPHI || !FoundReduxOp)
+ return false;
+
+ /* We found an induction variable. */
+ TheLoop.addReduction(Phi, StartValue, ExitInstruction, Kind, Ty);
+
+ return true;
+}
+
+void InnerLoopAnalysis::analyzePhi(InnerLoop &TheLoop, ScalarEvolution *SE)
+{
+ BasicBlock *Header = TheLoop.getHeader();
+ for (BasicBlock *BB : TheLoop.blocks()) {
+ auto I = BB->begin();
+ auto E = BasicBlock::iterator(BB->getFirstNonPHI());
+
+ for (; I != E; ++I) {
+ /* Currently, we cannot handle PHIs in a non-header block, so set
+ * the loop with unknown PHI if we find any of it. */
+ if (BB != Header) {
+ TheLoop.UnknownPhi = true;
+ return;
+ }
+
+ /* The loop must have a preheader and one split latch for us to
+ * analyze inductions and reductions. */
+ if (!TheLoop.getLoopPreheader() || !TheLoop.getSingleLatchTail()) {
+ TheLoop.UnknownPhi = true;
+ return;
+ }
+
+ PHINode *Phi = cast<PHINode>(I);
+ if (!analyzeInduction(TheLoop, SE, Phi) &&
+ !analyzeReduction(TheLoop, Phi))
+ TheLoop.UnknownPhi = true;
+ }
+ }
+}
+
+
+/*
+ * InnerLoopAnalysisWrapperPass Pass
+ */
+char InnerLoopAnalysisWrapperPass::ID = 0;
+INITIALIZE_PASS_BEGIN(InnerLoopAnalysisWrapperPass, "InnerLoopAnalysis",
+ "Inner Loop Analysis", true, true)
+#if defined(LLVM_V35)
+INITIALIZE_PASS_DEPENDENCY(LoopInfo)
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolution)
+#else
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
+#endif
+INITIALIZE_PASS_END(InnerLoopAnalysisWrapperPass, "InnerLoopAnalysis",
+ "Inner Loop Analysis", true, true)
+
+void InnerLoopAnalysisWrapperPass::releaseMemory() {
+ LA.releaseMemory();
+}
+
+void InnerLoopAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.setPreservesAll();
+#if defined(LLVM_V35)
+ AU.addRequired<LoopInfo>();
+ AU.addRequired<ScalarEvolution>();
+#else
+ AU.addRequired<LoopInfoWrapperPass>();
+ AU.addRequired<ScalarEvolutionWrapperPass>();
+#endif
+}
+void InnerLoopAnalysisWrapperPass::print(raw_ostream &OS, const Module *) const {
+ LA.print(OS);
+}
+
+void InnerLoopAnalysisWrapperPass::verifyAnalysis() const {
+ LA.verify();
+}
+
+bool InnerLoopAnalysisWrapperPass::runOnFunction(Function &F) {
+#if defined(LLVM_V35)
+ ScalarEvolution *SE = &getAnalysis<ScalarEvolution>();
+ LoopInfo *LI = &getAnalysis<LoopInfo>();
+#else
+ ScalarEvolution *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+ LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+#endif
+
+ LA.analyze(LI, SE);
+ return false;
+}
+
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/atomic/atomic-arm.c b/src/llvm/atomic/atomic-arm.c
new file mode 100644
index 0000000..4176caa
--- /dev/null
+++ b/src/llvm/atomic/atomic-arm.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2010 Parallel Processing Institute (PPI), Fudan Univ.
+ * <http://ppi.fudan.edu.cn/system_research_group>
+ *
+ * Authors:
+ * Zhaoguo Wang <zgwang@fudan.edu.cn>
+ * Yufei Chen <chenyufei@fudan.edu.cn>
+ * Ran Liu <naruilone@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* We include this file in op_helper.c */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include "coremu-atomic.h"
+
+__thread uint64_t cm_exclusive_val;
+__thread uint32_t cm_exclusive_addr = -1;
+
+#define GEN_LOAD_EXCLUSIVE(type, TYPE) \
+void HELPER(load_exclusive##type)(CPUArchState *env, uint32_t reg, \
+ uint32_t addr) \
+{ \
+ unsigned long q_addr = 0; \
+ DATA_##type val = 0; \
+ \
+ cm_exclusive_addr = addr; \
+ CM_GET_QEMU_ADDR(env, q_addr,addr); \
+ val = *(DATA_##type *)q_addr; \
+ cm_exclusive_val = val; \
+ env->regs[reg] = val; \
+}
+
+GEN_LOAD_EXCLUSIVE(b, B);
+GEN_LOAD_EXCLUSIVE(w, W);
+GEN_LOAD_EXCLUSIVE(l, L);
+//GEN_LOAD_EXCLUSIVE(q, Q);
+
+#define GEN_STORE_EXCLUSIVE(type, TYPE) \
+void HELPER(store_exclusive##type)(CPUArchState *env, uint32_t res, \
+ uint32_t reg, uint32_t addr) \
+{ \
+ unsigned long q_addr = 0; \
+ DATA_##type val = 0; \
+ DATA_##type r = 0; \
+ \
+ if(addr != cm_exclusive_addr) \
+ goto fail; \
+ \
+ CM_GET_QEMU_ADDR(env, q_addr,addr); \
+ val = (DATA_##type)env->regs[reg]; \
+ \
+ r = atomic_compare_exchange##type((DATA_##type *)q_addr, \
+ (DATA_##type)cm_exclusive_val, val); \
+ \
+ if(r == (DATA_##type)cm_exclusive_val) { \
+ env->regs[res] = 0; \
+ goto done; \
+ } else { \
+ goto fail; \
+ } \
+ \
+fail: \
+ env->regs[res] = 1; \
+ \
+done: \
+ cm_exclusive_addr = -1; \
+ return; \
+}
+
+GEN_STORE_EXCLUSIVE(b, B);
+GEN_STORE_EXCLUSIVE(w, W);
+GEN_STORE_EXCLUSIVE(l, L);
+//GEN_STORE_EXCLUSIVE(q, Q);
+
+void HELPER(load_exclusiveq)(CPUArchState *env, uint32_t reg, uint32_t addr)
+{
+ unsigned long q_addr = 0;
+ uint64_t val = 0;
+
+ cm_exclusive_addr = addr;
+ CM_GET_QEMU_ADDR(env, q_addr,addr);
+ val = *(uint64_t *)q_addr;
+ cm_exclusive_val = val;
+ env->regs[reg] = (uint32_t)val;
+ env->regs[reg + 1] = (uint32_t)(val>>32);
+}
+
+void HELPER(store_exclusiveq)(CPUArchState *env, uint32_t res, uint32_t reg, uint32_t addr)
+{
+ unsigned long q_addr = 0;
+ uint64_t val = 0;
+ uint64_t r = 0;
+
+ if(addr != cm_exclusive_addr)
+ goto fail;
+
+ CM_GET_QEMU_ADDR(env, q_addr,addr);
+ val = (uint32_t)env->regs[reg];
+ val |= ((uint64_t)env->regs[reg + 1]) << 32;
+
+ r = atomic_compare_exchangeq((uint64_t *)q_addr,
+ (uint64_t)cm_exclusive_val, val);
+
+ if(r == (uint64_t)cm_exclusive_val) {
+ env->regs[res] = 0;
+ goto done;
+ } else {
+ goto fail;
+ }
+
+fail:
+ env->regs[res] = 1;
+
+done:
+ cm_exclusive_addr = -1;
+ return;
+}
+
+void HELPER(clear_exclusive)(CPUArchState *env)
+{
+ cm_exclusive_addr = -1;
+}
+
+void HELPER(swpb)(CPUArchState *env, uint32_t dst, uint32_t src, uint32_t addr)
+{
+ uint8_t old, val;
+ unsigned long q_addr;
+ CM_GET_QEMU_ADDR(env, q_addr,env->regs[addr]);
+ val = (uint8_t)env->regs[src];
+ old = atomic_exchangeb((uint8_t *)q_addr, (uint8_t)val);
+ env->regs[dst] = old;
+ //printf("SWPB\n");
+}
+
+void HELPER(swp)(CPUArchState *env, uint32_t dst, uint32_t src, uint32_t addr)
+{
+ uint32_t old, val;
+ unsigned long q_addr;
+ CM_GET_QEMU_ADDR(env, q_addr,env->regs[addr]);
+ val = env->regs[src];
+ old = atomic_exchangel((uint32_t *)q_addr, val);
+ env->regs[dst] = old;
+ //printf("SWP\n");
+}
diff --git a/src/llvm/atomic/atomic-helper.h b/src/llvm/atomic/atomic-helper.h
new file mode 100644
index 0000000..9e3cedf
--- /dev/null
+++ b/src/llvm/atomic/atomic-helper.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Parallel Processing Institute (PPI), Fudan Univ.
+ * <http://ppi.fudan.edu.cn/system_research_group>
+ *
+ * Authors:
+ * Zhaoguo Wang <zgwang@fudan.edu.cn>
+ * Yufei Chen <chenyufei@fudan.edu.cn>
+ * Ran Liu <naruilone@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config-target.h"
+
+#ifdef CONFIG_COREMU
+
+#if defined(TARGET_I386)
+#define __GEN_HEADER(type) \
+DEF_HELPER_3(atomic_inc##type, void, env, tl, int) \
+DEF_HELPER_4(xchg##type, void, env, tl, int, int) \
+DEF_HELPER_4(atomic_op##type, void, env, tl, tl, int) \
+DEF_HELPER_4(atomic_xadd##type, void, env, tl, int, int) \
+DEF_HELPER_4(atomic_cmpxchg##type, void, env, tl, int, int) \
+DEF_HELPER_2(atomic_not##type, void, env, tl) \
+DEF_HELPER_2(atomic_neg##type, void, env, tl)
+
+__GEN_HEADER(b)
+__GEN_HEADER(w)
+__GEN_HEADER(l)
+#ifdef TARGET_X86_64
+__GEN_HEADER(q)
+#endif
+
+DEF_HELPER_2(atomic_cmpxchg8b, void, env, tl)
+DEF_HELPER_2(atomic_cmpxchg16b, void, env, tl)
+
+DEF_HELPER_4(atomic_bts, void, env, tl, tl, int)
+DEF_HELPER_4(atomic_btr, void, env, tl, tl, int)
+DEF_HELPER_4(atomic_btc, void, env, tl, tl, int)
+
+/* fence */
+DEF_HELPER_1(fence, void, env)
+
+#elif defined(TARGET_ARM)
+#define __GEN_HEADER(type) \
+DEF_HELPER_3(load_exclusive##type, void, env, i32, i32) \
+DEF_HELPER_4(store_exclusive##type, void, env, i32, i32, i32)
+
+__GEN_HEADER(b)
+__GEN_HEADER(w)
+__GEN_HEADER(l)
+__GEN_HEADER(q)
+
+DEF_HELPER_1(clear_exclusive, void, env)
+
+DEF_HELPER_4(swpb, void, env, i32, i32, i32)
+DEF_HELPER_4(swp, void, env, i32, i32, i32)
+#else
+#error "unsupported processor type"
+#endif
+
+#endif
+
diff --git a/src/llvm/atomic/atomic-x86.c b/src/llvm/atomic/atomic-x86.c
new file mode 100644
index 0000000..dc0baf0
--- /dev/null
+++ b/src/llvm/atomic/atomic-x86.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2010 Parallel Processing Institute (PPI), Fudan Univ.
+ * <http://ppi.fudan.edu.cn/system_research_group>
+ *
+ * Authors:
+ * Zhaoguo Wang <zgwang@fudan.edu.cn>
+ * Yufei Chen <chenyufei@fudan.edu.cn>
+ * Ran Liu <naruilone@gmail.com>
+ * Xi Wu <wuxi@fudan.edu.cn>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* We include this file in op_helper.c */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <assert.h>
+#include "coremu-atomic.h"
+
+#define EAX (env->regs[R_EAX])
+#define ECX (env->regs[R_ECX])
+#define EDX (env->regs[R_EDX])
+#define EBX (env->regs[R_EBX])
+
+/* These definitions are copied from translate.c */
+#if defined(WORDS_BIGENDIAN)
+#define REG_B_OFFSET (sizeof(target_ulong) - 1)
+#define REG_H_OFFSET (sizeof(target_ulong) - 2)
+#define REG_W_OFFSET (sizeof(target_ulong) - 2)
+#define REG_L_OFFSET (sizeof(target_ulong) - 4)
+#define REG_LH_OFFSET (sizeof(target_ulong) - 8)
+#else
+#define REG_B_OFFSET 0
+#define REG_H_OFFSET 1
+#define REG_W_OFFSET 0
+#define REG_L_OFFSET 0
+#define REG_LH_OFFSET 4
+#endif
+
+#ifdef TARGET_X86_64
+#define X86_64_DEF(...) __VA_ARGS__
+#else
+#define X86_64_DEF(...)
+#endif
+
+#define REG_LOW_MASK (~(uint64_t)0x0>>32)
+
+/* gen_op instructions */
+/* i386 arith/logic operations */
+enum {
+ OP_ADDL,
+ OP_ORL,
+ OP_ADCL,
+ OP_SBBL,
+ OP_ANDL,
+ OP_SUBL,
+ OP_XORL,
+ OP_CMPL,
+};
+
+/* */
+static target_ulong cm_get_reg_val(CPUX86State *env, int ot, int hregs, int reg)
+{
+ target_ulong val, offset;
+ CPUX86State *env1 = env;
+
+ switch(ot) {
+ case 0: /* OT_BYTE */
+ if (reg < 4 X86_64_DEF( || reg >= 8 || hregs)) {
+ goto std_case;
+ } else {
+ offset = offsetof(CPUX86State, regs[reg - 4]) + REG_H_OFFSET;
+ val = *(((uint8_t *)env1) + offset);
+ }
+ break;
+ default:
+ std_case:
+ val = env1->regs[reg];
+ break;
+ }
+
+ return val;
+}
+
+static void cm_set_reg_val(CPUX86State *env, int ot, int hregs, int reg, target_ulong val)
+{
+ target_ulong offset;
+
+ CPUX86State *env1 = env;
+
+ switch(ot) {
+ case 0: /* OT_BYTE */
+ if (reg < 4 X86_64_DEF (|| reg >= 8 || hregs)) {
+ offset = offsetof(CPUX86State, regs[reg]) + REG_B_OFFSET;
+ *(((uint8_t *) env1) + offset) = (uint8_t)val;
+ } else {
+ offset = offsetof(CPUX86State, regs[reg - 4]) + REG_H_OFFSET;
+ *(((uint8_t *) env1) + offset) = (uint8_t)val;
+ }
+ break;
+ case 1: /* OT_WORD */
+ offset = offsetof(CPUX86State, regs[reg]) + REG_W_OFFSET;
+ *((uint16_t *)((uint8_t *)env1 + offset)) = (uint16_t)val;
+ break;
+ case 2: /* OT_LONG */
+ env1->regs[reg] = REG_LOW_MASK & val;
+ break;
+ default:
+ case 3: /* OT_QUAD */
+ env1->regs[reg] = val;
+ break;
+ }
+}
+
+#define LD_b ldub_p
+#define LD_w lduw_p
+#define LD_l ldl_p
+#define LD_q ldq_p
+
+/* Lightweight transactional memory. */
+#define TX(vaddr, type, value, command) \
+ unsigned long __q_addr; \
+ DATA_##type __oldv; \
+ DATA_##type value; \
+ \
+ CM_GET_QEMU_ADDR(env, __q_addr, vaddr); \
+ do { \
+ __oldv = value = LD_##type((DATA_##type *)__q_addr); \
+ {command;}; \
+ mb(); \
+ } while (__oldv != (atomic_compare_exchange##type( \
+ (DATA_##type *)__q_addr, __oldv, value)))
+
+/* Atomically emulate INC instruction using CAS1 and memory transaction. */
+
+#define GEN_ATOMIC_INC(type, TYPE) \
+void helper_atomic_inc##type(CPUX86State *env, target_ulong a0, int c) \
+{ \
+ int eflags_c, eflags; \
+ int cc_op; \
+ \
+ /* compute the previous instruction c flags */ \
+ eflags_c = helper_cc_compute_c(CC_DST, CC_SRC, CC_SRC2, CC_OP); \
+ \
+ TX(a0, type, value, { \
+ if (c > 0) { \
+ value++; \
+ cc_op = CC_OP_INC##TYPE; \
+ } else { \
+ value--; \
+ cc_op = CC_OP_DEC##TYPE; \
+ } \
+ }); \
+ \
+ CC_SRC = eflags_c; \
+ CC_DST = value; \
+ \
+ eflags = helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, cc_op); \
+ CC_SRC = eflags; \
+} \
+
+GEN_ATOMIC_INC(b, B);
+GEN_ATOMIC_INC(w, W);
+GEN_ATOMIC_INC(l, L);
+#ifdef TARGET_X86_64
+GEN_ATOMIC_INC(q, Q);
+#endif
+
+#define OT_b 0
+#define OT_w 1
+#define OT_l 2
+#define OT_q 3
+
+#define GEN_ATOMIC_XCHG(type) \
+void helper_xchg##type(CPUX86State *env, target_ulong a0, int reg, \
+ int hreg) \
+{ \
+ DATA_##type val, out; \
+ unsigned long q_addr; \
+ \
+ CM_GET_QEMU_ADDR(env, q_addr, a0); \
+ val = (DATA_##type)cm_get_reg_val(env, OT_##type, hreg, reg); \
+ out = atomic_exchange##type((DATA_##type *)q_addr, val); \
+ mb(); \
+ \
+ cm_set_reg_val(env, OT_##type, hreg, reg, out); \
+}
+
+GEN_ATOMIC_XCHG(b);
+GEN_ATOMIC_XCHG(w);
+GEN_ATOMIC_XCHG(l);
+#ifdef TARGET_X86_64
+GEN_ATOMIC_XCHG(q);
+#endif
+
+#define GEN_ATOMIC_OP(type, TYPE) \
+void helper_atomic_op##type(CPUX86State *env, target_ulong a0, \
+ target_ulong t1, int op) \
+{ \
+ DATA_##type operand; \
+ int eflags_c, eflags; \
+ int cc_op; \
+ \
+ /* compute the previous instruction c flags */ \
+ eflags_c = helper_cc_compute_c(CC_DST, CC_SRC, CC_SRC2, CC_OP); \
+ operand = (DATA_##type)t1; \
+ \
+ TX(a0, type, value, { \
+ switch(op) { \
+ case OP_ADCL: \
+ value += operand + eflags_c; \
+ cc_op = CC_OP_ADD##TYPE + (eflags_c << 2); \
+ CC_SRC = operand; \
+ break; \
+ case OP_SBBL: \
+ value = value - operand - eflags_c; \
+ cc_op = CC_OP_SUB##TYPE + (eflags_c << 2); \
+ CC_SRC = operand; \
+ break; \
+ case OP_ADDL: \
+ value += operand; \
+ cc_op = CC_OP_ADD##TYPE; \
+ CC_SRC = operand; \
+ break; \
+ case OP_SUBL: \
+ value -= operand; \
+ cc_op = CC_OP_SUB##TYPE; \
+ CC_SRC = operand; \
+ break; \
+ default: \
+ case OP_ANDL: \
+ value &= operand; \
+ cc_op = CC_OP_LOGIC##TYPE; \
+ break; \
+ case OP_ORL: \
+ value |= operand; \
+ cc_op = CC_OP_LOGIC##TYPE; \
+ break; \
+ case OP_XORL: \
+ value ^= operand; \
+ cc_op = CC_OP_LOGIC##TYPE; \
+ break; \
+ case OP_CMPL: \
+ abort(); \
+ break; \
+ } \
+ }); \
+ CC_DST = value; \
+ /* successful transaction, compute the eflags */ \
+ eflags = helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, cc_op); \
+ CC_SRC = eflags; \
+}
+
+GEN_ATOMIC_OP(b, B);
+GEN_ATOMIC_OP(w, W);
+GEN_ATOMIC_OP(l, L);
+#ifdef TARGET_X86_64
+GEN_ATOMIC_OP(q, Q);
+#endif
+
+/* xadd */
+#define GEN_ATOMIC_XADD(type, TYPE) \
+void helper_atomic_xadd##type(CPUX86State *env, target_ulong a0, \
+ int reg, int hreg) \
+{ \
+ DATA_##type operand, oldv; \
+ int eflags; \
+ \
+ operand = (DATA_##type)cm_get_reg_val( \
+ env, OT_##type, hreg, reg); \
+ \
+ TX(a0, type, newv, { \
+ oldv = newv; \
+ newv += operand; \
+ }); \
+ \
+ /* transaction successes */ \
+ /* xchg the register and compute the eflags */ \
+ cm_set_reg_val(env, OT_##type, hreg, reg, oldv); \
+ CC_SRC = oldv; \
+ CC_DST = newv; \
+ \
+ eflags = helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, \
+ CC_OP_ADD##TYPE); \
+ CC_SRC = eflags; \
+}
+
+GEN_ATOMIC_XADD(b, B);
+GEN_ATOMIC_XADD(w, W);
+GEN_ATOMIC_XADD(l, L);
+#ifdef TARGET_X86_64
+GEN_ATOMIC_XADD(q, Q);
+#endif
+
+/* cmpxchg */
+#define GEN_ATOMIC_CMPXCHG(type, TYPE) \
+void helper_atomic_cmpxchg##type(CPUX86State *env, target_ulong a0, \
+ int reg, int hreg) \
+{ \
+ DATA_##type reg_v, eax_v, res; \
+ int eflags; \
+ unsigned long q_addr; \
+ \
+ CM_GET_QEMU_ADDR(env, q_addr, a0); \
+ reg_v = (DATA_##type)cm_get_reg_val(env, OT_##type, hreg, reg); \
+ eax_v = (DATA_##type)cm_get_reg_val(env, OT_##type, 0, R_EAX); \
+ \
+ res = atomic_compare_exchange##type( \
+ (DATA_##type *)q_addr, eax_v, reg_v); \
+ mb(); \
+ \
+ if (res != eax_v) \
+ cm_set_reg_val(env, OT_##type, 0, R_EAX, res); \
+ \
+ CC_SRC = res; \
+ CC_DST = eax_v - res; \
+ \
+ eflags = helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, \
+ CC_OP_SUB##TYPE); \
+ CC_SRC = eflags; \
+}
+
+GEN_ATOMIC_CMPXCHG(b, B);
+GEN_ATOMIC_CMPXCHG(w, W);
+GEN_ATOMIC_CMPXCHG(l, L);
+#ifdef TARGET_X86_64
+GEN_ATOMIC_CMPXCHG(q, Q);
+#endif
+
+#if defined(_LP64)
+/* cmpxchgb (8, 16) */
+void helper_atomic_cmpxchg8b(CPUX86State *env, target_ulong a0)
+{
+ uint64_t edx_eax, ecx_ebx, res;
+ int eflags;
+ unsigned long q_addr;
+
+ eflags = helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, CC_OP);
+ CM_GET_QEMU_ADDR(env, q_addr, a0);
+
+ edx_eax = (((uint64_t)EDX << 32) | (uint32_t)EAX);
+ ecx_ebx = (((uint64_t)ECX << 32) | (uint32_t)EBX);
+
+ res = atomic_compare_exchangeq((uint64_t *)q_addr, edx_eax, ecx_ebx);
+ mb();
+
+ if (res == edx_eax) {
+ eflags |= CC_Z;
+ } else {
+ EDX = (uint32_t)(res >> 32);
+ EAX = (uint32_t)res;
+ eflags &= ~CC_Z;
+ }
+
+ CC_SRC = eflags;
+}
+#else
+void helper_atomic_cmpxchg8b(CPUX86State *env, target_ulong a0)
+{
+ assert("helper_atomic_cmpxchg8b: not supported.\n");
+ exit(0);
+}
+#endif
+
+void helper_atomic_cmpxchg16b(CPUX86State *env, target_ulong a0)
+{
+ uint8_t res;
+ int eflags;
+ unsigned long q_addr;
+
+ eflags = helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, CC_OP);
+ CM_GET_QEMU_ADDR(env, q_addr, a0);
+
+ uint64_t old_rax = *(uint64_t *)q_addr;
+ uint64_t old_rdx = *(uint64_t *)(q_addr + 8);
+ res = atomic_compare_exchange16b((uint64_t *)q_addr, EAX, EDX, EBX, ECX);
+ mb();
+
+ if (res) {
+ eflags |= CC_Z; /* swap success */
+ } else {
+ EDX = old_rdx;
+ EAX = old_rax;
+ eflags &= ~CC_Z; /* read the old value ! */
+ }
+
+ CC_SRC = eflags;
+}
+
+/* not */
+#define GEN_ATOMIC_NOT(type) \
+void helper_atomic_not##type(CPUX86State *env, \
+ target_ulong a0) \
+{ \
+ TX(a0, type, value, { \
+ value = ~value; \
+ }); \
+}
+
+GEN_ATOMIC_NOT(b);
+GEN_ATOMIC_NOT(w);
+GEN_ATOMIC_NOT(l);
+#ifdef TARGET_X86_64
+GEN_ATOMIC_NOT(q);
+#endif
+
+/* neg */
+#define GEN_ATOMIC_NEG(type, TYPE) \
+void helper_atomic_neg##type(CPUX86State *env, \
+ target_ulong a0) \
+{ \
+ int eflags; \
+ \
+ TX(a0, type, value, { \
+ value = -value; \
+ }); \
+ \
+ /* We should use the old value to compute CC */ \
+ CC_SRC = CC_DST = -value; \
+ \
+ eflags = helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, \
+ CC_OP_SUB##TYPE); \
+ CC_SRC = eflags; \
+} \
+
+GEN_ATOMIC_NEG(b, B);
+GEN_ATOMIC_NEG(w, W);
+GEN_ATOMIC_NEG(l, L);
+#ifdef TARGET_X86_64
+GEN_ATOMIC_NEG(q, Q);
+#endif
+
+/* This is only used in BTX instruction, with an additional offset.
+ * Note that, when using register bitoffset, the value can be larger than
+ * operand size - 1 (operand size can be 16/32/64), refer to intel manual 2A
+ * page 3-11. */
+#define TX2(vaddr, type, value, offset, command) \
+ unsigned long __q_addr; \
+ DATA_##type __oldv; \
+ DATA_##type value; \
+ \
+ CM_GET_QEMU_ADDR(env, __q_addr, vaddr); \
+ __q_addr += offset >> 3; \
+ do { \
+ __oldv = value = LD_##type((DATA_##type *)__q_addr); \
+ {command;}; \
+ mb(); \
+ } while (__oldv != (atomic_compare_exchange##type( \
+ (DATA_##type *)__q_addr, __oldv, value)))
+
+#define GEN_ATOMIC_BTX(ins, command) \
+void helper_atomic_##ins(CPUX86State *env, target_ulong a0, \
+ target_ulong offset, int ot) \
+{ \
+ uint8_t old_byte; \
+ int eflags; \
+ \
+ TX2(a0, b, value, offset, { \
+ old_byte = value; \
+ {command;}; \
+ }); \
+ \
+ CC_SRC = (old_byte >> (offset & 0x7)); \
+ CC_DST = 0; \
+ eflags = helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, \
+ CC_OP_SARB + ot); \
+ CC_SRC = eflags; \
+}
+
+/* bts */
+GEN_ATOMIC_BTX(bts, {
+ value |= (1 << (offset & 0x7));
+});
+/* btr */
+GEN_ATOMIC_BTX(btr, {
+ value &= ~(1 << (offset & 0x7));
+});
+/* btc */
+GEN_ATOMIC_BTX(btc, {
+ value ^= (1 << (offset & 0x7));
+});
+
+/* fence **/
+void helper_fence(CPUX86State *env)
+{
+ mb();
+}
+
+#undef EAX
+#undef ECX
+#undef EDX
+#undef EBX
diff --git a/src/llvm/atomic/coremu-atomic.h b/src/llvm/atomic/coremu-atomic.h
new file mode 100644
index 0000000..998232b
--- /dev/null
+++ b/src/llvm/atomic/coremu-atomic.h
@@ -0,0 +1,412 @@
+/*
+ * COREMU Parallel Emulator Framework
+ *
+ * Atomic support for COREMU system.
+ * XXX: Now only support x86-64 architecture.
+ *
+ * Copyright (C) 2010 Parallel Processing Institute (PPI), Fudan Univ.
+ * <http://ppi.fudan.edu.cn/system_research_group>
+ *
+ * Authors:
+ * Zhaoguo Wang <zgwang@fudan.edu.cn>
+ * Yufei Chen <chenyufei@fudan.edu.cn>
+ * Ran Liu <naruilone@gmail.com>
+ * Xi Wu <wuxi@fudan.edu.cn>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _COREMU_ATOMIC_H
+#define _COREMU_ATOMIC_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "config-target.h"
+#include "hqemu.h"
+
+/* Given the guest virtual address, get the corresponding host address.
+ * This macro resembles ldxxx in softmmu_template.h
+ * NOTE: This must be inlined since the use of GETPC needs to get the
+ * return address. Using always inline also works, we use macro here to be more
+ * explicit. */
+#if defined(CONFIG_USER_ONLY)
+#define CM_GET_QEMU_ADDR(__env1, q_addr, v_addr) \
+do { \
+ q_addr = v_addr + GUEST_BASE; \
+} while (0)
+
+#else
+#define CM_GET_QEMU_ADDR(__env1, q_addr, v_addr) \
+do { \
+ CPUState *cpu = ENV_GET_CPU(__env1); \
+ int __mmu_idx, __index; \
+ uintptr_t __retaddr; \
+ __index = (v_addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); \
+ /* get the CPL, hence determine the MMU mode */ \
+ __mmu_idx = cpu_mmu_index(__env1, false); \
+ /* We use this function in the implementation of atomic instructions */ \
+ /* and we are going to modify these memory. So we use addr_write. */ \
+ if (unlikely(__env1->tlb_table[__mmu_idx][__index].addr_write \
+ != ((v_addr & TARGET_PAGE_MASK) | tlb_version(__env1)))) { \
+ __retaddr = GETPC(); \
+ tlb_fill(cpu, v_addr, 1, __mmu_idx, __retaddr); \
+ } \
+ q_addr = v_addr + __env1->tlb_table[__mmu_idx][__index].addend; \
+} while(0)
+#endif
+
+/* XXX These are also used by atomic instruction handling.
+ * Put these defines in some other files? */
+#define DATA_b uint8_t
+#define DATA_w uint16_t
+#define DATA_l uint32_t
+#define DATA_q uint64_t
+
+#define __inline__ inline __attribute__((always_inline))
+
+#if defined(__i386__) || defined(__x86_64__)
+// Is this the correct way to detect 64 system?
+#if defined(_LP64)
+static __inline__ uint8_t
+atomic_compare_exchange16b(uint64_t *memp,
+ uint64_t rax, uint64_t rdx,
+ uint64_t rbx, uint64_t rcx)
+{
+ uint8_t z;
+ __asm __volatile__ ( "lock; cmpxchg16b %3\n\t"
+ "setz %2\n\t"
+ : "=a" (rax), "=d" (rdx), "=r" (z), "+m" (*memp)
+ : "a" (rax), "d" (rdx), "b" (rbx), "c" (rcx)
+ : "memory", "cc" );
+ return z;
+}
+#else
+static __inline__ uint8_t
+atomic_compare_exchange16b(uint64_t *memp,
+ uint64_t rax, uint64_t rdx,
+ uint64_t rbx, uint64_t rcx)
+{
+ assert("atomic_compare_exchange16b: not supported.\n");
+ exit(0);
+}
+
+static __inline__ uint8_t
+atomic_compare_exchangeq(uint64_t *addr,
+ uint64_t oldval, uint64_t newval)
+{
+ assert("atomic_compare_exchangeq: not supported.\n");
+ exit(0);
+}
+
+#endif
+
+/* Memory Barriers: x86-64 ONLY now */
+#define mb() asm volatile("mfence":::"memory")
+#define rmb() asm volatile("lfence":::"memory")
+#define wmb() asm volatile("sfence" ::: "memory")
+
+#define LOCK_PREFIX "lock; "
+
+#define coremu_xglue(a, b) a ## b
+// If a/b is macro, it will expand first, then pass to coremu_xglue
+#define coremu_glue(a, b) coremu_xglue(a, b)
+
+#define coremu_xstr(s) # s
+#define coremu_str(s) coremu_xstr(s)
+
+#define DATA_BITS 8
+#include "coremu-template.h"
+
+#define DATA_BITS 16
+#include "coremu-template.h"
+
+#define DATA_BITS 32
+#include "coremu-template.h"
+
+#if defined(_LP64)
+#define DATA_BITS 64
+#include "coremu-template.h"
+#else
+static inline uint64_t atomic_exchangeq(uint64_t *p, uint64_t val)
+{
+ assert("atomic_exchangeq: not supported.\n");
+ exit(0);
+}
+
+#endif
+
+#elif defined(__arm__)
+
+#if defined(__ARM_ARCH_7__) || \
+ defined(__ARM_ARCH_7A__) || \
+ defined(__ARM_ARCH_7EM__) || \
+ defined(__ARM_ARCH_7M__) || \
+ defined(__ARM_ARCH_7R__) || \
+ defined(__ARM_ARCH_6J__) || \
+ defined(__ARM_ARCH_6K__) || \
+ defined(__ARM_ARCH_6T2__) || \
+ defined(__ARM_ARCH_6Z__) || \
+ defined(__ARM_ARCH_6ZK__)
+#define USE_ARMV6_INSTRUCTIONS
+#endif
+
+#ifdef USE_ARMV6_INSTRUCTIONS
+#define mb() __asm__ __volatile__("dmb" : : : "memory")
+#define raw_local_irq_save(x) \
+ ({ \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_save\n" \
+ "cpsid i" \
+ : "=r" (x) : : "memory", "cc"); \
+ })
+#else
+#define mb() __asm__ __volatile__("":::"memory")
+#define raw_local_irq_save(x) \
+ ({ \
+ unsigned long temp; \
+ (void) (&temp == &x); \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_save\n" \
+" orr %1, %0, #128\n" \
+" msr cpsr_c, %1" \
+ : "=r" (x), "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+#endif
+
+#define raw_local_irq_restore(x) \
+ __asm__ __volatile( \
+ "msr cpsr_c, %0 @ local_irq_restore\n" \
+ : \
+ : "r" (x) \
+ : "memory", "cc")
+
+static __inline__ uint8_t atomic_compare_exchangeb(uint8_t *addr,
+ uint8_t oldval, uint8_t newval)
+{
+ uint8_t ret;
+#ifdef USE_ARMV6_INSTRUCTIONS
+ unsigned long tmp;
+ __asm__ __volatile__("@ atomic_cmpxchgl\n"
+ "1: ldrexb %1, [%3]\n"
+ " mov %0, #0\n"
+ " teq %1, %4\n"
+ " strexbeq %0, %5, [%3]\n"
+ " teq %0, #0\n"
+ " bne 1b\n"
+ : "=&r" (tmp), "=&r" (ret), "+Qo" (*addr)
+ : "r" (addr), "Ir" (oldval), "r" (newval)
+ : "cc");
+#else
+ unsigned long flags;
+ raw_local_irq_save(flags);
+ ret = *addr;
+ if (likely(ret == oldval))
+ *addr = newval;
+ raw_local_irq_restore(flags);
+#endif
+ return ret;
+}
+
+static __inline__ uint16_t atomic_compare_exchangew(uint16_t *addr,
+ uint16_t oldval, uint16_t newval)
+{
+ uint16_t ret;
+#ifdef USE_ARMV6_INSTRUCTIONS
+ unsigned long tmp;
+ __asm__ __volatile__("@ atomic_cmpxchgl\n"
+ "1: ldrexh %1, [%3]\n"
+ " mov %0, #0\n"
+ " teq %1, %4\n"
+ " strexheq %0, %5, [%3]\n"
+ " teq %0, #0\n"
+ " bne 1b\n"
+ : "=&r" (tmp), "=&r" (ret), "+Qo" (*addr)
+ : "r" (addr), "Ir" (oldval), "r" (newval)
+ : "cc");
+#else
+ unsigned long flags;
+ raw_local_irq_save(flags);
+ ret = *addr;
+ if (likely(ret == oldval))
+ *addr = newval;
+ raw_local_irq_restore(flags);
+#endif
+ return ret;
+}
+
+static __inline__ uint32_t atomic_compare_exchangel(uint32_t *addr,
+ uint32_t oldval, uint32_t newval)
+{
+ uint32_t ret;
+#ifdef USE_ARMV6_INSTRUCTIONS
+ unsigned long tmp;
+ __asm__ __volatile__("@ atomic_cmpxchgl\n"
+ "1: ldrex %1, [%3]\n"
+ " mov %0, #0\n"
+ " teq %1, %4\n"
+ " strexeq %0, %5, [%3]\n"
+ " teq %0, #0\n"
+ " bne 1b\n"
+ : "=&r" (tmp), "=&r" (ret), "+Qo" (*addr)
+ : "r" (addr), "Ir" (oldval), "r" (newval)
+ : "cc");
+#else
+ unsigned long flags;
+ raw_local_irq_save(flags);
+ ret = *addr;
+ if (likely(ret == oldval))
+ *addr = newval;
+ raw_local_irq_restore(flags);
+#endif
+ return ret;
+}
+
+static __inline__ uint64_t atomic_compare_exchangeq(uint64_t *addr,
+ uint64_t oldval, uint64_t newval)
+{
+ uint64_t ret;
+#ifdef USE_ARMV6_INSTRUCTIONS
+ unsigned long tmp;
+ __asm__ __volatile__("@ atomic_cmpxchgl\n"
+ "1: ldrexd %1, %H1, [%3]\n"
+ " mov %0, #0\n"
+ " teq %1, %4\n"
+ " teqeq %H1, %H4\n"
+ " strexdeq %0, %5, %H5, [%3]\n"
+ " teq %0, #0\n"
+ " bne 1b\n"
+ : "=&r" (tmp), "=&r" (ret), "+Qo" (*addr)
+ : "r" (addr), "Ir" (oldval), "r" (newval)
+ : "cc");
+#else
+ unsigned long flags;
+ raw_local_irq_save(flags);
+ ret = *addr;
+ if (likely(ret == oldval))
+ *addr = newval;
+ raw_local_irq_restore(flags);
+#endif
+ return ret;
+}
+
+static __inline__ uint8_t
+atomic_compare_exchange16b(uint64_t *memp,
+ uint64_t old_less, uint64_t old_most,
+ uint64_t new_less, uint64_t new_most)
+{
+ uint8_t ret = 0;
+ unsigned long flags;
+ raw_local_irq_save(flags);
+ ret = *memp;
+ if (likely(*memp == old_less && *(memp+1) == old_most))
+ {
+ *memp = new_less;
+ *(memp+1) = new_most;
+ ret = 1;
+ }
+ raw_local_irq_restore(flags);
+ return ret;
+}
+
+static __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
+{
+ unsigned long ret;
+#ifdef USE_ARMV6_INSTRUCTIONS
+ unsigned int tmp;
+#endif
+
+ mb();
+
+ switch (size) {
+#ifdef USE_ARMV6_INSTRUCTIONS
+ case 1:
+ __asm __volatile("@ __xchg1\n"
+ "1: ldrexb %0, [%3]\n"
+ " strexb %1, %2, [%3]\n"
+ " teq %1, #0\n"
+ " bne 1b"
+ : "=&r" (ret), "=&r" (tmp)
+ : "r" (x), "r" (ptr)
+ : "memory", "cc");
+ break;
+ case 2:
+ __asm __volatile("@ __xchg1\n"
+ "1: ldrexh %0, [%3]\n"
+ " strexh %1, %2, [%3]\n"
+ " teq %1, #0\n"
+ " bne 1b"
+ : "=&r" (ret), "=&r" (tmp)
+ : "r" (x), "r" (ptr)
+ : "memory", "cc");
+ break;
+ case 4:
+ __asm __volatile("@ __xchg4\n"
+ "1: ldrex %0, [%3]\n"
+ " strex %1, %2, [%3]\n"
+ " teq %1, #0\n"
+ " bne 1b"
+ : "=&r" (ret), "=&r" (tmp)
+ : "r" (x), "r" (ptr)
+ : "memory", "cc");
+ break;
+#else
+ case 1:
+ __asm __volatile("@ __xchg1\n"
+ " swpb %0, %1, [%2]"
+ : "=&r" (ret)
+ : "r" (x), "r" (ptr)
+ : "memory", "cc");
+ break;
+
+ case 4:
+ __asm __volatile("@ __xchg4\n"
+ " swp %0, %1, [%2]"
+ : "=&r" (ret)
+ : "r" (x), "r" (ptr)
+ : "memory", "cc");
+ break;
+ case 2:
+ {
+ unsigned long flags = 0;
+ raw_local_irq_save(flags);
+ ret = *(volatile uint16_t *)ptr;
+ *(volatile uint16_t *)ptr = x;
+ raw_local_irq_restore(flags);
+ break;
+ }
+
+#endif
+ default:
+ exit(0);
+ }
+ mb();
+
+ return ret;
+}
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define GEN_ATOMIC_XCHG_HELPER(TYPE) \
+static __inline__ DATA_##TYPE atomic_exchange##TYPE(DATA_##TYPE *p, DATA_##TYPE val) { return xchg(p, val); }
+
+GEN_ATOMIC_XCHG_HELPER(b);
+GEN_ATOMIC_XCHG_HELPER(w);
+GEN_ATOMIC_XCHG_HELPER(l);
+
+#endif
+
+#endif /* _COREMU_ATOMIC_H */
+
diff --git a/src/llvm/atomic/coremu-template.h b/src/llvm/atomic/coremu-template.h
new file mode 100644
index 0000000..66b185c
--- /dev/null
+++ b/src/llvm/atomic/coremu-template.h
@@ -0,0 +1,101 @@
+/* The following code may be included multiple times in a single file. */
+
+#if DATA_BITS == 64
+# define DATA_TYPE uint64_t
+# define SUFFIX q
+#elif DATA_BITS == 32
+# define DATA_TYPE uint32_t
+# define SUFFIX l
+#elif DATA_BITS == 16
+# define DATA_TYPE uint16_t
+# define SUFFIX w
+#elif DATA_BITS == 8
+# define DATA_TYPE uint8_t
+# define SUFFIX b
+#else
+#error unsupported data size
+#endif
+
+static __inline__ void coremu_glue(atomic_inc, SUFFIX)(DATA_TYPE *p) {
+ asm volatile(
+ LOCK_PREFIX "inc"coremu_str(SUFFIX)" %0"
+ : "+m"(*p)
+ :
+ : "cc");
+}
+
+static __inline__ void coremu_glue(atomic_dec, SUFFIX)(DATA_TYPE *p) {
+ asm volatile(
+ LOCK_PREFIX "dec"coremu_str(SUFFIX)" %0"
+ : "+m"(*p)
+ :
+ : "cc");
+}
+
+static __inline__ void coremu_glue(atomic_add, SUFFIX)(DATA_TYPE* addr,
+ DATA_TYPE val) {
+ asm volatile(
+ LOCK_PREFIX "add"coremu_str(SUFFIX)" %1, %0"
+ : "+m"(*addr)
+ : "a"(val)
+ : "cc");
+}
+
+/* swap the value VAL and *p.
+ * Return the value swapped out from memory. */
+static inline DATA_TYPE coremu_glue(atomic_exchange, SUFFIX)(
+ DATA_TYPE *p, DATA_TYPE val)
+{
+ DATA_TYPE out;
+ __asm __volatile(
+ "lock; xchg"coremu_str(SUFFIX)" %1,%2 \n\t"
+ : "=a" (out), "+m" (*p)
+ : "a" (val)
+ );
+ return out;
+}
+/* Return previous value in addr. So if the return value is the same as oldval,
+ * swap occured. */
+static __inline__ DATA_TYPE coremu_glue(atomic_compare_exchange, SUFFIX)(DATA_TYPE *addr,
+ DATA_TYPE oldval, DATA_TYPE newval) {
+ asm volatile(
+ LOCK_PREFIX "cmpxchg"coremu_str(SUFFIX)" %2, %1"
+ : "+a"(oldval), "+m"(*addr)
+ : "q"(newval)
+ : "cc");
+
+ return oldval;
+}
+
+static __inline__ void coremu_glue(atomic_and, SUFFIX)(DATA_TYPE *addr,
+ DATA_TYPE mask) {
+ asm volatile(
+ LOCK_PREFIX "and"coremu_str(SUFFIX)" %1, %0"
+ : "+m"(*addr)
+ : "r"(mask)
+ : "cc");
+}
+
+static __inline__ void coremu_glue(atomic_or, SUFFIX)(DATA_TYPE *addr,
+ DATA_TYPE mask) {
+ asm volatile(
+ LOCK_PREFIX "or"coremu_str(SUFFIX)" %1, %0"
+ : "+m"(*addr)
+ : "r"(mask)
+ : "cc");
+}
+
+static __inline__ DATA_TYPE coremu_glue(atomic_xadd, SUFFIX)(
+ DATA_TYPE* addr, DATA_TYPE val) {
+ asm volatile(
+ LOCK_PREFIX "xadd"coremu_str(SUFFIX)" %0, %1"
+ : "+a"(val), "+m"(*addr)
+ :
+ : "cc");
+
+ return val;
+}
+
+#undef DATA_BITS
+#undef DATA_TYPE
+#undef SUFFIX
diff --git a/src/llvm/fpu/softfloat-native-def.h b/src/llvm/fpu/softfloat-native-def.h
new file mode 100644
index 0000000..4b0fd22
--- /dev/null
+++ b/src/llvm/fpu/softfloat-native-def.h
@@ -0,0 +1,127 @@
+/*
+ * QEMU float support
+ *
+ * Derived from SoftFloat.
+ */
+
+/*============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
+Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#ifndef SOFTFLOAT_NATIVE_DEF_H
+#define SOFTFLOAT_NATIVE_DEF_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "fpu/softfloat.h"
+
+int num_native_fpu_helpers(void);
+void *get_native_fpu_helpers(void);
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE integer-to-floating-point conversion routines.
+*----------------------------------------------------------------------------*/
+float32 llvm_int32_to_float32(int32_t v);
+float64 llvm_int32_to_float64(int32_t v);
+float32 llvm_uint32_to_float32(uint32_t v);
+float64 llvm_uint32_to_float64(uint32_t v);
+float32 llvm_int64_to_float32(int64_t v);
+float32 llvm_uint64_to_float32(uint64_t v);
+float64 llvm_int64_to_float64(int64_t v);
+float64 llvm_uint64_to_float64(uint64_t v);
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE single-precision conversion routines.
+*----------------------------------------------------------------------------*/
+int32 llvm_float32_to_int32( float32 a );
+int32 llvm_float32_to_int32_round_to_zero( float32 a );
+int64 llvm_float32_to_int64( float32 a );
+int64 llvm_float32_to_int64_round_to_zero( float32 a );
+float64 llvm_float32_to_float64( float32 a );
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE single-precision operations.
+*----------------------------------------------------------------------------*/
+float32 llvm_float32_round_to_int( float32 a );
+float32 llvm_float32_add( float32 a, float32 b );
+float32 llvm_float32_sub( float32 a, float32 b );
+float32 llvm_float32_mul( float32 a, float32 b );
+float32 llvm_float32_div( float32 a, float32 b );
+float32 llvm_float32_rem( float32 a, float32 b );
+float32 llvm_float32_sqrt( float32 a );
+int llvm_float32_eq( float32 a, float32 b );
+int llvm_float32_le( float32 a, float32 b );
+int llvm_float32_lt( float32 a, float32 b );
+int llvm_float32_unordered( float32 a, float32 b );
+float32 llvm_float32_abs(float32 a);
+float32 llvm_float32_chs(float32 a);
+
+float32 llvm_float32_muladd( float32 a, float32 b, float32 c );
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE double-precision conversion routines.
+*----------------------------------------------------------------------------*/
+int32 llvm_float64_to_int32( float64 a );
+int32 llvm_float64_to_int32_round_to_zero( float64 a );
+int64 llvm_float64_to_int64( float64 a );
+int64 llvm_float64_to_int64_round_to_zero( float64 a );
+float32 llvm_float64_to_float32( float64 a );
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE double-precision operations.
+*----------------------------------------------------------------------------*/
+float64 llvm_float64_round_to_int( float64 a );
+float64 llvm_float64_trunc_to_int( float64 a );
+float64 llvm_float64_add( float64 a, float64 b );
+float64 llvm_float64_sub( float64 a, float64 b );
+float64 llvm_float64_mul( float64 a, float64 b );
+float64 llvm_float64_div( float64 a, float64 b );
+float64 llvm_float64_rem( float64 a, float64 b );
+float64 llvm_float64_sqrt( float64 a );
+int llvm_float64_eq( float64 a, float64 b );
+int llvm_float64_le( float64 a, float64 b );
+int llvm_float64_lt( float64 a, float64 b );
+int llvm_float64_unordered( float64 a, float64 b );
+float64 llvm_float64_abs(float64 a);
+float64 llvm_float64_chs(float64 a);
+
+float64 llvm_float64_muladd( float64 a, float64 b, float64 c );
+
+float32 llvm_float32_maybe_silence_nan( float32 a );
+float64 llvm_float64_maybe_silence_nan( float64 a );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !SOFTFLOAT_NATIVE_DEF_H */
diff --git a/src/llvm/fpu/softfloat-native.h b/src/llvm/fpu/softfloat-native.h
new file mode 100644
index 0000000..c12f62b
--- /dev/null
+++ b/src/llvm/fpu/softfloat-native.h
@@ -0,0 +1,248 @@
+/*
+ * QEMU float support
+ *
+ * Derived from SoftFloat.
+ */
+
+/*============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
+Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#ifndef SOFTFLOAT_NATIVE_H
+#define SOFTFLOAT_NATIVE_H
+
+#include <math.h>
+#include "fpu/softfloat-native-def.h"
+
+typedef union {
+ float32 f;
+ int32_t i;
+ uint32_t u;
+ float s;
+} llvm_float32;
+
+typedef union {
+ float64 f;
+ int64_t i;
+ uint64_t u;
+ double d;
+} llvm_float64;
+
+#ifdef float32_val
+#undef float32_val
+#endif
+#ifdef float64_val
+#undef float64_val
+#endif
+
+#define float32_val(x) ((llvm_float32)(x)).f
+#define float64_val(x) ((llvm_float64)(x)).f
+#define lfloat(x) ((llvm_float32)(x)).s
+#define ldouble(x) ((llvm_float64)(x)).d
+
+#define DEF_HELPER(name) { (void *)llvm_##name, "llvm_"#name }
+static TCGHelperInfo native_fpu_helpers[] = {
+ DEF_HELPER(int32_to_float32),
+ DEF_HELPER(int32_to_float64),
+ DEF_HELPER(uint32_to_float32),
+ DEF_HELPER(uint32_to_float64),
+ DEF_HELPER(int64_to_float32),
+ DEF_HELPER(uint64_to_float32),
+ DEF_HELPER(int64_to_float64),
+ DEF_HELPER(uint64_to_float64),
+ DEF_HELPER(float32_to_int32),
+ DEF_HELPER(float32_to_int64),
+ DEF_HELPER(float32_to_float64),
+ DEF_HELPER(float32_add),
+ DEF_HELPER(float32_sub),
+ DEF_HELPER(float32_mul),
+ DEF_HELPER(float32_div),
+ DEF_HELPER(float32_rem),
+ DEF_HELPER(float32_sqrt),
+ DEF_HELPER(float32_abs),
+ DEF_HELPER(float32_chs),
+ DEF_HELPER(float64_to_int32),
+ DEF_HELPER(float64_to_int64),
+ DEF_HELPER(float64_to_float32),
+ DEF_HELPER(float64_add),
+ DEF_HELPER(float64_sub),
+ DEF_HELPER(float64_mul),
+ DEF_HELPER(float64_div),
+ DEF_HELPER(float64_rem),
+ DEF_HELPER(float64_sqrt),
+ DEF_HELPER(float64_abs),
+ DEF_HELPER(float64_chs),
+
+ DEF_HELPER(float32_muladd),
+ DEF_HELPER(float64_muladd),
+
+ DEF_HELPER(float32_maybe_silence_nan),
+ DEF_HELPER(float64_maybe_silence_nan),
+#if 0
+ DEF_HELPER(float32_to_int32_round_to_zero),
+ DEF_HELPER(float32_to_int64_round_to_zero),
+ DEF_HELPER(float32_round_to_int),
+ DEF_HELPER(float32_eq),
+ DEF_HELPER(float32_le),
+ DEF_HELPER(float32_lt),
+ DEF_HELPER(float32_unordered),
+ DEF_HELPER(float64_to_int32_round_to_zero),
+ DEF_HELPER(float64_to_int64_round_to_zero),
+ DEF_HELPER(float64_round_to_int),
+ DEF_HELPER(float64_trunc_to_int),
+ DEF_HELPER(float64_eq),
+ DEF_HELPER(float64_le),
+ DEF_HELPER(float64_lt),
+ DEF_HELPER(float64_unordered),
+#endif
+};
+#undef DEF_HELPER
+
+int num_native_fpu_helpers(void)
+{
+ return ARRAY_SIZE(native_fpu_helpers);
+}
+
+void *get_native_fpu_helpers(void)
+{
+ return native_fpu_helpers;
+}
+
+/* XXX: this code implements the x86 behaviour, not the IEEE one. */
+#if TCG_TARGET_REG_BITS == 32
+static inline int32 long_to_int32(long a)
+{
+ return a;
+}
+#else
+static inline int32 long_to_int32(long a)
+{
+ if (a != (int32_t)a)
+ a = 0x80000000;
+ return a;
+}
+#endif
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE integer-to-floating-point conversion routines.
+*----------------------------------------------------------------------------*/
+float32 llvm_int32_to_float32(int32_t v) { return float32_val((float)v); }
+float64 llvm_int32_to_float64(int32_t v) { return float64_val((double)v); }
+float32 llvm_uint32_to_float32(uint32_t v) { return float32_val((float)v); }
+float64 llvm_uint32_to_float64(uint32_t v) { return float64_val((double)v); }
+float32 llvm_int64_to_float32(int64_t v) { return float32_val((float)v); }
+float32 llvm_uint64_to_float32(uint64_t v) { return float32_val((float)v); }
+float64 llvm_int64_to_float64(int64_t v) { return float64_val((double)v); }
+float64 llvm_uint64_to_float64(uint64_t v) { return float64_val((double)v); }
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE single-precision conversion routines.
+*----------------------------------------------------------------------------*/
+int32 llvm_float32_to_int32( float32 a ) { return long_to_int32(lrintf(lfloat(a))); }
+int32 llvm_float32_to_int32_round_to_zero( float32 a ) { return (int32)lfloat(a); }
+int64 llvm_float32_to_int64( float32 a ) { return llrintf(lfloat(a)); }
+int64 llvm_float32_to_int64_round_to_zero( float32 a ) { return (int64)lfloat(a); }
+float64 llvm_float32_to_float64( float32 a ) { return float64_val((double)lfloat(a)); }
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE single-precision operations.
+*----------------------------------------------------------------------------*/
+float32 llvm_float32_round_to_int( float32 a ) { return float32_val(rintf(lfloat(a))); }
+float32 llvm_float32_add( float32 a, float32 b ) { return float32_val(lfloat(a) + lfloat(b)); }
+float32 llvm_float32_sub( float32 a, float32 b ) { return float32_val(lfloat(a) - lfloat(b)); }
+float32 llvm_float32_mul( float32 a, float32 b ) { return float32_val(lfloat(a) * lfloat(b)); }
+float32 llvm_float32_div( float32 a, float32 b ) { return float32_val(lfloat(a) / lfloat(b)); }
+float32 llvm_float32_rem( float32 a, float32 b ) { return float32_val(remainderf(lfloat(a), lfloat(b))); }
+float32 llvm_float32_sqrt( float32 a ) { return float32_val(sqrtf(lfloat(a))); }
+int llvm_float32_eq( float32 a, float32 b ) { return lfloat(a) == lfloat(b); }
+int llvm_float32_le( float32 a, float32 b ) { return lfloat(a) <= lfloat(b); }
+int llvm_float32_lt( float32 a, float32 b ) { return lfloat(a) < lfloat(b); }
+int llvm_float32_unordered( float32 a, float32 b ) { return isunordered(lfloat(a), lfloat(b)); }
+float32 llvm_float32_abs(float32 a) { return float32_val(fabsf(lfloat(a))); }
+float32 llvm_float32_chs(float32 a) { return float32_val(-lfloat(a)); }
+
+float32 llvm_float32_muladd( float32 a, float32 b, float32 c ) { return float32_val(lfloat(a) * lfloat(b) + lfloat(c)); }
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE double-precision conversion routines.
+*----------------------------------------------------------------------------*/
+int32 llvm_float64_to_int32( float64 a ) { return long_to_int32(lrint(ldouble(a))); }
+int32 llvm_float64_to_int32_round_to_zero( float64 a ) { return (int32)ldouble(a); }
+int64 llvm_float64_to_int64( float64 a ) { return llrint(ldouble(a)); }
+int64 llvm_float64_to_int64_round_to_zero( float64 a ) { return (int64)ldouble(a); }
+float32 llvm_float64_to_float32( float64 a ) { return float32_val((float)ldouble(a)); }
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE double-precision operations.
+*----------------------------------------------------------------------------*/
+float64 llvm_float64_round_to_int( float64 a ) { return float64_val(rint(ldouble(a))); }
+float64 llvm_float64_trunc_to_int( float64 a ) { return float64_val(trunc(ldouble(a))); }
+float64 llvm_float64_add( float64 a, float64 b ) { return float64_val(ldouble(a) + ldouble(b)); }
+float64 llvm_float64_sub( float64 a, float64 b ) { return float64_val(ldouble(a) - ldouble(b)); }
+float64 llvm_float64_mul( float64 a, float64 b ) { return float64_val(ldouble(a) * ldouble(b)); }
+float64 llvm_float64_div( float64 a, float64 b ) { return float64_val(ldouble(a) / ldouble(b)); }
+float64 llvm_float64_rem( float64 a, float64 b ) { return float64_val(remainder(ldouble(a), ldouble(b))); }
+float64 llvm_float64_sqrt( float64 a ) { return float64_val(sqrt(ldouble(a))); }
+int llvm_float64_eq( float64 a, float64 b ) { return ldouble(a) == ldouble(b); }
+int llvm_float64_le( float64 a, float64 b ) { return ldouble(a) <= ldouble(b); }
+int llvm_float64_lt( float64 a, float64 b ) { return ldouble(a) < ldouble(b); }
+int llvm_float64_unordered( float64 a, float64 b ) { return isunordered(ldouble(a), ldouble(b)); }
+float64 llvm_float64_abs(float64 a) { return float64_val(fabs(ldouble(a))); }
+float64 llvm_float64_chs(float64 a) { return float64_val(-ldouble(a)); }
+
+float64 llvm_float64_muladd( float64 a, float64 b, float64 c ) { return float64_val(ldouble(a) * ldouble(b) + ldouble(c)); }
+
+float32 llvm_float32_maybe_silence_nan( float32 a ) {
+ uint32_t _a = ((llvm_float32)(a)).u;
+ if ( ((_a >> 22) & 0x1FF) == 0x1FE && (_a & 0x003FFFFF)) {
+ _a |= (1 << 22);
+ return float32_val(_a);
+ }
+ return a;
+}
+float64 llvm_float64_maybe_silence_nan( float64 a ) {
+ uint64_t _a = ((llvm_float64)(a)).u;
+ if (((_a >> 51) & 0xFFF) == 0xFFE && (_a & 0x0007FFFFFFFFFFFFLL)) {
+ _a |= 0x0008000000000000LL;
+ return float64_val(_a);
+ }
+ return a;
+}
+
+#undef float32_val
+#undef float64_val
+#undef lfloat
+#undef ldouble
+
+#endif /* !SOFTFLOAT_NATIVE_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/hqemu-helper.c b/src/llvm/hqemu-helper.c
new file mode 100644
index 0000000..6325716
--- /dev/null
+++ b/src/llvm/hqemu-helper.c
@@ -0,0 +1,77 @@
+#include "cpu.h"
+#include "tcg.h"
+#include "exec/helper-proto.h"
+#include "hqemu.h"
+#include "fpu/softfloat-native.h"
+
+CPUArchState basereg;
+target_ulong pcid;
+
+#if defined(TARGET_I386)
+XMMReg xmm_reg;
+#endif
+
+extern TranslationBlock *tbs;
+
+void *ibtc_lookup(CPUArchState *env);
+void *cpbl_lookup(CPUArchState *env);
+int cpbl_validate(CPUArchState *env, target_ulong pc, int id);
+
+/* This helper is a hack to export symbols of helper functions in the LLVM
+ * bitcode file. If a target is alerted with lacks of symbols of function/variable,
+ * add such symbols in this helper by accessing it. */
+void helper_export_hqemu(CPUArchState *env)
+{
+ helper_lookup_ibtc(env);
+ helper_lookup_cpbl(env);
+ helper_validate_cpbl(env, 0, 0);
+
+#if defined(CONFIG_SOFTMMU) && defined(CONFIG_LLVM)
+ target_ulong ptr = 0;
+ llvm_ret_ldub_mmu(env, ptr, 0);
+ llvm_le_lduw_mmu(env, ptr, 0);
+ llvm_le_ldul_mmu(env, ptr, 0);
+ llvm_le_ldq_mmu(env, ptr, 0);
+ llvm_be_lduw_mmu(env, ptr, 0);
+ llvm_be_ldul_mmu(env, ptr, 0);
+ llvm_be_ldq_mmu(env, ptr, 0);
+ llvm_ret_ldsb_mmu(env, ptr, 0);
+ llvm_le_ldsw_mmu(env, ptr, 0);
+ llvm_le_ldsl_mmu(env, ptr, 0);
+ llvm_be_ldsw_mmu(env, ptr, 0);
+ llvm_be_ldsl_mmu(env, ptr, 0);
+ llvm_ret_stb_mmu(env, ptr, 0, 0);
+ llvm_le_stw_mmu(env, ptr, 0, 0);
+ llvm_le_stl_mmu(env, ptr, 0, 0);
+ llvm_le_stq_mmu(env, ptr, 0, 0);
+ llvm_be_stw_mmu(env, ptr, 0, 0);
+ llvm_be_stl_mmu(env, ptr, 0, 0);
+ llvm_be_stq_mmu(env, ptr, 0, 0);
+#endif
+}
+
+void helper_verify_tb(CPUArchState *env, int id)
+{
+ static TranslationBlock *last_tb;
+ TranslationBlock *tb = &tbs[id];
+ if (tb->mode == BLOCK_INVALID) {
+ fprintf(stderr, "%s: tb=%p pc=" TARGET_FMT_lx " last_pc="
+ TARGET_FMT_lx "\n", __func__, tb, tb->pc,
+ (last_tb) ? last_tb->pc : -1U);
+ }
+ last_tb = tb;
+}
+
+/*
+ * helper_profile_exec is used to profile LLVM translated code.
+ */
+void helper_profile_exec(CPUArchState *env, void *counter_p, int idx)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ uint64_t **counter = (uint64_t **)counter_p;
+ counter[cpu->cpu_index][idx]++;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/hqemu.mk b/src/llvm/hqemu.mk
new file mode 100644
index 0000000..01de6d6
--- /dev/null
+++ b/src/llvm/hqemu.mk
@@ -0,0 +1,191 @@
+# Makefile for HQEMU.
+
+QEMU_CFLAGS += -I$(SRC_PATH)/llvm -I$(SRC_PATH)/llvm/include -I$(SRC_PATH)/llvm/atomic
+QEMU_CXXFLAGS += -std=c++11 -Wno-narrowing
+obj-y += llvm/optimization.o llvm/tracer.o llvm/utils.o llvm/hqemu-helper.o
+
+# LLVM
+ifdef CONFIG_LLVM
+
+LLVM_EXTRA_FLAGS += -Wall -DNEED_CPU_H -D$(LLVM_VERSION) -I..
+
+LLVM_CXXFLAGS := $(patsubst -Wcast-qual, ,$(LLVM_CXXFLAGS))
+LLVM_CXXFLAGS := $(patsubst -fno-exceptions, ,$(LLVM_CXXFLAGS))
+LLVM_CXXFLAGS := $(patsubst -pedantic, ,$(LLVM_CXXFLAGS))
+LLVM_CXXFLAGS += -Wno-unused-local-typedefs -Wno-cast-qual -fno-rtti
+LLVM_CFLAGS += $(patsubst -O2, ,$(patsubst -g, ,$(CFLAGS)))
+LLVM_CFLAGS += $(LLVM_EXTRA_FLAGS) $(QEMU_INCLUDES) \
+ -I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
+ -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -I$(SRC_PATH)/llvm \
+ -I$(SRC_PATH)/llvm/atomic -I$(SRC_PATH)/llvm/include/pmu
+LLVM_CFLAGS := $(patsubst -pedantic, ,$(LLVM_CFLAGS))
+LLVM_CFLAGS := $(patsubst -g, ,$(LLVM_CFLAGS))
+
+PASS := llvm/pass
+ANALYSIS := llvm/analysis
+HPM := llvm/pmu
+QEMU_CXXFLAGS += $(LLVM_CXXFLAGS) $(LLVM_EXTRA_FLAGS) -Wno-undef
+LDFLAGS += $(LLVM_LDFLAGS)
+LIBS += $(LLVM_LIBS) -ldl -lz -lncurses
+
+
+ifeq ($(CONFIG_WIN32), y)
+LIBS += -lpthread -limagehlp -lpsapi
+endif
+
+obj-y += llvm/xml/tinyxml2.o
+obj-y += llvm/llvm.o \
+ llvm/llvm-translator.o \
+ llvm/llvm-opc.o \
+ llvm/llvm-opc-vector.o \
+ llvm/llvm-opc-mmu.o \
+ llvm/llvm-debug.o \
+ llvm/llvm-target.o \
+ llvm/llvm-soft-perfmon.o \
+ llvm/llvm-hard-perfmon.o \
+ llvm/llvm-annotate.o
+obj-y += $(PASS)/ProfileExec.o \
+ $(PASS)/ReplaceIntrinsic.o \
+ $(PASS)/CombineGuestMemory.o \
+ $(PASS)/CombineCasts.o \
+ $(PASS)/CombineZExtTrunc.o \
+ $(PASS)/FastMathPass.o \
+ $(PASS)/StateMappingPass.o \
+ $(PASS)/RedundantStateElimination.o \
+ $(PASS)/SimplifyPointer.o
+obj-y += $(ANALYSIS)/InnerLoopAnalysis.o
+
+# HPM
+obj-y += $(HPM)/pmu.o \
+ $(HPM)/pmu-events.o
+
+ifeq ($(ARCH),$(filter $(ARCH),i386 x86_64))
+obj-y += $(HPM)/x86/x86-events.o
+endif
+ifeq ($(ARCH),$(filter $(ARCH),arm aarch64))
+obj-y += $(HPM)/arm/arm-events.o
+endif
+ifeq ($(ARCH),$(filter $(ARCH),ppc64))
+obj-y += $(HPM)/ppc/ppc-events.o
+endif
+
+#
+# LLVM Bitcode file
+#
+
+ifdef CONFIG_SOFTMMU
+BCSUF = _softmmu
+MMU_HELPER = $(TARGET_PATH)/mmu_helper.bc
+endif
+
+LLVM_BITCODE = llvm_helper_${TARGET_NAME}${BCSUF}.bc
+TARGET_PATH = target-$(TARGET_BASE_ARCH)
+LLVM_HELPER += tcg-runtime.bc llvm/hqemu-helper.bc $(TARGET_PATH)/helper.bc
+
+ifeq ($(TARGET_I386), y)
+LLVM_HELPER += $(TARGET_PATH)/cc_helper.bc \
+ $(TARGET_PATH)/int_helper.bc \
+ $(TARGET_PATH)/smm_helper.bc \
+ $(TARGET_PATH)/excp_helper.bc \
+ $(TARGET_PATH)/mem_helper.bc \
+ $(TARGET_PATH)/svm_helper.bc \
+ $(TARGET_PATH)/fpu_helper.bc \
+ $(TARGET_PATH)/misc_helper.bc \
+ $(TARGET_PATH)/seg_helper.bc \
+ $(TARGET_PATH)/bpt_helper.bc
+endif
+ifeq ($(TARGET_X86_64), y)
+LLVM_HELPER += $(TARGET_PATH)/cc_helper.bc \
+ $(TARGET_PATH)/int_helper.bc \
+ $(TARGET_PATH)/smm_helper.bc \
+ $(TARGET_PATH)/excp_helper.bc \
+ $(TARGET_PATH)/mem_helper.bc \
+ $(TARGET_PATH)/svm_helper.bc \
+ $(TARGET_PATH)/fpu_helper.bc \
+ $(TARGET_PATH)/misc_helper.bc \
+ $(TARGET_PATH)/seg_helper.bc
+endif
+ifeq ($(TARGET_ALPHA), y)
+LLVM_HELPER += $(TARGET_PATH)/fpu_helper.bc \
+ $(TARGET_PATH)/int_helper.bc \
+ $(TARGET_PATH)/mem_helper.bc \
+ $(TARGET_PATH)/sys_helper.bc
+endif
+ifeq ($(TARGET_ARM), y)
+LLVM_HELPER += $(TARGET_PATH)/op_helper.bc \
+ $(TARGET_PATH)/neon_helper.bc
+endif
+ifeq ($(TARGET_AARCH64), y)
+LLVM_HELPER += $(TARGET_PATH)/op_helper.bc \
+ $(TARGET_PATH)/helper-a64.bc \
+ $(TARGET_PATH)/neon_helper.bc
+endif
+ifeq ($(TARGET_MICROBLAZE), y)
+LLVM_HELPER += $(TARGET_PATH)/op_helper.bc
+endif
+ifeq ($(TARGET_MIPS), y)
+LLVM_HELPER += $(TARGET_PATH)/op_helper.bc \
+ $(TARGET_PATH)/dsp_helper.bc \
+ $(TARGET_PATH)/lmi_helper.bc
+endif
+ifeq ($(TARGET_OPENRISC), y)
+LLVM_HELPER += $(TARGET_PATH)/exception_helper.bc \
+ $(TARGET_PATH)/fpu_helper.bc \
+ $(TARGET_PATH)/interrupt_helper.bc \
+ $(TARGET_PATH)/int_helper.bc \
+ $(TARGET_PATH)/sys_helper.bc \
+ $(MMU_HELPER)
+endif
+ifeq ($(TARGET_PPC), y)
+LLVM_HELPER += $(TARGET_PATH)/excp_helper.bc \
+ $(TARGET_PATH)/int_helper.bc \
+ $(TARGET_PATH)/misc_helper.bc \
+ $(TARGET_PATH)/fpu_helper.bc \
+ $(TARGET_PATH)/mem_helper.bc \
+ $(TARGET_PATH)/timebase_helper.bc \
+ $(MMU_HELPER)
+endif
+ifeq ($(TARGET_PPC64), y)
+LLVM_HELPER += $(TARGET_PATH)/excp_helper.bc \
+ $(TARGET_PATH)/int_helper.bc \
+ $(TARGET_PATH)/misc_helper.bc \
+ $(TARGET_PATH)/fpu_helper.bc \
+ $(TARGET_PATH)/mem_helper.bc \
+ $(TARGET_PATH)/timebase_helper.bc \
+ $(MMU_HELPER)
+endif
+ifeq ($(TARGET_SH4), y)
+LLVM_HELPER += $(TARGET_PATH)/op_helper.bc
+endif
+ifeq ($(TARGET_SPARC), y)
+LLVM_HELPER += $(TARGET_PATH)/cc_helper.bc \
+ $(TARGET_PATH)/fop_helper.bc \
+ $(TARGET_PATH)/int32_helper.bc \
+ $(TARGET_PATH)/ldst_helper.bc \
+ $(TARGET_PATH)/vis_helper.bc \
+ $(TARGET_PATH)/win_helper.bc \
+ $(MMU_HELPER)
+endif
+ifeq ($(TARGET_SPARC64), y)
+LLVM_HELPER += $(TARGET_PATH)/cc_helper.bc \
+ $(TARGET_PATH)/fop_helper.bc \
+ $(TARGET_PATH)/int64_helper.bc \
+ $(TARGET_PATH)/ldst_helper.bc \
+ $(TARGET_PATH)/vis_helper.bc \
+ $(TARGET_PATH)/win_helper.bc \
+ $(MMU_HELPER)
+endif
+
+LOCAL_BC := clang
+LOCAL_BC_CFLAGS := -S -emit-llvm $(BCFLAGS) -I$(SRC_PATH)/llvm/include $(LLVM_CFLAGS) \
+ -Wno-missing-prototypes -Wno-sign-compare -Wno-unused-function \
+ -Wno-constant-conversion
+
+%.bc: %.c
+ $(call quiet-command,$(LOCAL_BC) $(LOCAL_BC_CFLAGS) -c -o $@ $<, " LCC $(TARGET_DIR)$@")
+
+
+$(LLVM_BITCODE): $(LLVM_HELPER)
+ $(call quiet-command,llvm-link -o $@ $^, " LCC $(TARGET_DIR)$@")
+
+endif
diff --git a/src/llvm/include/InnerLoopAnalysis.h b/src/llvm/include/InnerLoopAnalysis.h
new file mode 100644
index 0000000..f11225d
--- /dev/null
+++ b/src/llvm/include/InnerLoopAnalysis.h
@@ -0,0 +1,291 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __INNERLOOPANALYSIS_H
+#define __INNERLOOPANALYSIS_H
+
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm-types.h"
+
+
+class InductionDesc {
+ /* Start value. */
+ Value *StartValue;
+ /* Step value. */
+ const SCEV *Step;
+
+public:
+ InductionDesc() : StartValue(nullptr), Step(nullptr) {}
+ InductionDesc(Value *Start, const SCEV *Step)
+ : StartValue(Start), Step(Step) {}
+
+ Value *getStartValue() const { return StartValue; }
+ const SCEV *getStep() const { return Step; }
+};
+
+class ReductionDesc {
+public:
+
+ enum ReductionKind {
+ NoReduction, /* Not a reduction. */
+ IntegerAdd, /* Sum of numbers. */
+ IntegerMult, /* Product of numbers. */
+ IntegerOr, /* Bitwise or logical OR of numbers. */
+ IntegerAnd, /* Bitwise or logical AND of numbers. */
+ IntegerXor, /* Bitwise or logical XOR of numbers. */
+ FloatAdd, /* Sum of float numbers. */
+ FloatMult, /* Product of float numbers. */
+ };
+
+ ReductionDesc()
+ : StartValue(nullptr), LoopExitInstr(nullptr),
+ Kind(ReductionKind::NoReduction), Ty(nullptr) {}
+ ReductionDesc(Value *Start, Instruction *Exit, ReductionKind K, Type *Ty)
+ : StartValue(Start), LoopExitInstr(Exit), Kind(K), Ty(Ty) {}
+
+ Value *getStartValue() const { return StartValue; }
+ Value *getNextValue() const { return LoopExitInstr; }
+ Instruction *getLoopExitInstr() { return LoopExitInstr; }
+ ReductionKind getReductionKind() { return Kind; }
+ Type *getScalarType() { return Ty; }
+
+private:
+ /* The starting value of the recurrence. */
+ Value *StartValue;
+ /* The instruction who's value is used outside the loop. */
+ Instruction *LoopExitInstr;
+ /* The kind of the recurrence.*/
+ ReductionKind Kind;
+ /* The scalar type. */
+ Type *Ty;
+};
+
+/*
+ * The InnertLoop class represents a single innertmost loop. The InnerLoop has
+ * a special shape that is specific to the DBT decoded guest loop, and its loop
+ * definition is different to a nature loop, e.g., latch and exiting block.
+ */
+class InnerLoop {
+public:
+ typedef std::map<PHINode *, InductionDesc> InductionList;
+ typedef std::map<PHINode *, ReductionDesc> ReductionList;
+
+private:
+ Loop &TheLoop;
+
+ /* The list of blocks in this loop. First entry is the header node. */
+ std::vector<BasicBlock *> Blocks;
+ SmallPtrSet<const BasicBlock *, 8> DenseBlockSet;
+
+ std::vector<BasicBlock *> Latches;
+ std::map<BasicBlock *, BasicBlock *> SplitLatches;
+
+ bool UnknownPhi;
+ InductionList Inductions;
+ ReductionList Reductions;
+
+ void addInduction(PHINode *Phi, Value *Start, const SCEV *Step) {
+ Inductions[Phi] = InductionDesc(Start, Step);
+ }
+
+ void addReduction(PHINode *Phi, Value *Start, Instruction *Exit,
+ ReductionDesc::ReductionKind K, Type *Ty) {
+ Reductions[Phi] = ReductionDesc(Start, Exit, K, Ty);
+ }
+
+ InnerLoop(const InnerLoop &) = delete;
+ const InnerLoop& operator=(const InnerLoop &) = delete;
+
+ friend class InnerLoopAnalysis;
+
+public:
+ InnerLoop(Loop *loop);
+ ~InnerLoop() {}
+
+ Loop &getLoop() const { return TheLoop; }
+
+ BasicBlock *getHeader() const { return Blocks.front(); }
+
+ /* Return true if the specified basic block is in this loop. */
+ bool contains(const BasicBlock *BB) const {
+ return DenseBlockSet.count(BB);
+ }
+
+ /* Return true if the specified instruction is in this loop. */
+ bool contains(const Instruction *Inst) const {
+ return contains(Inst->getParent());
+ }
+
+ /* Get a list of the basic blocks which make up this loop. */
+ typedef typename std::vector<BasicBlock*>::const_iterator block_iterator;
+ const std::vector<BasicBlock*> &getBlocks() const { return Blocks; }
+ block_iterator block_begin() const { return Blocks.begin(); }
+ block_iterator block_end() const { return Blocks.end(); }
+ inline iterator_range<block_iterator> blocks() const {
+ return make_range(block_begin(), block_end());
+ }
+
+ /* Get the number of blocks in this loop in constant time. */
+ unsigned getNumBlocks() const { return Blocks.size(); }
+
+ /* True if terminator in the block can branch to another block that is
+ * outside of the current loop. */
+ bool isLoopExiting(BasicBlock *BB) const;
+
+ /* Calculate the number of back edges to the loop header. */
+ unsigned getNumBackEdges() const;
+
+ /* Return all blocks inside the loop that have successors outside of the
+ * loop. */
+ void getExitingBlocks(SmallVectorImpl<BasicBlock *> &ExitingBlocks) const;
+
+ /* If getExitingBlocks would return exactly one block, return that block.
+ * Otherwise return null. */
+ BasicBlock *getExitingBlock() const;
+
+ /* Return all of the successor blocks of this loop. */
+ void getExitBlocks(SmallVectorImpl<BasicBlock *> &ExitBlocks) const;
+
+ /* If getExitBlocks would return exactly one block, return that block.
+ * Otherwise return null. */
+ BasicBlock *getExitBlock() const;
+
+ /* If there is a preheader for this loop, return it. A loop has a preheader
+ * if there is only one edge to the header of the loop from outside of the
+ * loop. If this is the case, the block branching to the header of the loop
+ * is the preheader node.
+ *
+ * This method returns null if there is no preheader for the loop. */
+ BasicBlock *getLoopPreheader() const;
+
+ /* If the given loop's header has exactly one unique predecessor outside the
+ * loop, return it. Otherwise return null.
+ * This is less strict that the loop "preheader" concept, which requires
+ * the predecessor to have exactly one successor. */
+ BasicBlock *getLoopPredecessor() const;
+
+ unsigned getNumLoopLatches() const { return Latches.size(); }
+ unsigned getNumSplitLatches() const { return SplitLatches.size(); }
+
+ /* Return all loop latch blocks of this loop. A latch block is a block that
+ * contains a branch back to the header. */
+ void getLoopLatches(SmallVectorImpl<BasicBlock *> &LoopLatches) const {
+ for (auto I : Latches)
+ LoopLatches.push_back(I);
+ }
+
+ /* If there is a latch tail, return it. */
+ BasicBlock *getSingleLatchTail() const {
+ return (SplitLatches.size() == 1) ? SplitLatches.begin()->first :
+ nullptr;
+ }
+
+ /* If there is a latch head, return it. */
+ BasicBlock *getSingleLatchHead() const {
+ return (SplitLatches.size() == 1) ? SplitLatches.begin()->second :
+ nullptr;
+ }
+
+ /* Return all of the latch tails of this loop. */
+ void getLatchTails(SmallVectorImpl<BasicBlock *> &LatchTails) const {
+ for (auto &I : SplitLatches)
+ LatchTails.push_back(I.first);
+ }
+
+ /* Given a latch tail, return its latch head. */
+ BasicBlock *getLatchHead(BasicBlock *BB) {
+ if (SplitLatches.find(BB) == SplitLatches.end())
+ return nullptr;
+ return SplitLatches[BB];
+ }
+
+ /* If the given phi is an induction of the loop, return the induciton. */
+ InductionDesc *getInduction(PHINode *Phi) {
+ if (Inductions.find(Phi) == Inductions.end())
+ return nullptr;
+ return &Inductions[Phi];
+ }
+
+ /* If the given phi is a reduction of the loop, return the induciton. */
+ ReductionDesc *getReduction(PHINode *Phi) {
+ if (Reductions.find(Phi) == Reductions.end())
+ return nullptr;
+ return &Reductions[Phi];
+ }
+
+ /* Return true if the loop has unknown phi(s). A loop has unknown phi(s) if
+ * a phi node is not identified, or the loop has no preheader or latch tail.
+ *
+ * If the loop has unknown phi(s), the data structure of Inductions and
+ * Reductions can be undefined. */
+ bool hasUnknownPhi() { return UnknownPhi; }
+
+ /* Return true if the instruction `From' can flow to instruction `To' in
+ * the loop. */
+ bool isReachable(Instruction *From, Instruction *To);
+};
+
+class InnerLoopAnalysis {
+ std::vector<InnerLoop *> InnerLoops;
+
+ void analyzePhi(InnerLoop &TheLoop, ScalarEvolution *SE);
+ bool analyzeInduction(InnerLoop &TheLoop, ScalarEvolution *SE, PHINode *Phi);
+ bool analyzeReduction(InnerLoop &TheLoop, PHINode *Phi);
+
+public:
+ InnerLoopAnalysis() {}
+ ~InnerLoopAnalysis() { releaseMemory(); }
+
+ void releaseMemory() {
+ while (!InnerLoops.empty()) {
+ InnerLoop *L = InnerLoops.back();
+ InnerLoops.pop_back();
+ delete L;
+ }
+ }
+ void print(raw_ostream &OS, const Module * = nullptr) const {}
+ void verify() const {}
+ void analyze(LoopInfo *LI, ScalarEvolution *SE);
+
+ /* iterator/begin/end - The interface to the innermost loops. */
+ typedef typename std::vector<InnerLoop *>::const_iterator iterator;
+ typedef typename std::vector<InnerLoop *>::const_reverse_iterator
+ reverse_iterator;
+ iterator begin() const { return InnerLoops.begin(); }
+ iterator end() const { return InnerLoops.end(); }
+ reverse_iterator rbegin() const { return InnerLoops.rbegin(); }
+ reverse_iterator rend() const { return InnerLoops.rend(); }
+ bool empty() const { return InnerLoops.empty(); }
+ unsigned size() { return InnerLoops.size(); }
+};
+
+/*
+ * InnerLoopAnalysisWrapperPass Pass
+ */
+class InnerLoopAnalysisWrapperPass : public FunctionPass {
+ InnerLoopAnalysis LA;
+
+public:
+ static char ID;
+ InnerLoopAnalysisWrapperPass() : FunctionPass(ID) {
+ initializeInnerLoopAnalysisWrapperPassPass(*PassRegistry::getPassRegistry());
+ }
+
+ InnerLoopAnalysis &getLoopAnalysis() { return LA; }
+ const InnerLoopAnalysis &getLoopAnalysis() const { return LA; }
+
+ void releaseMemory() override;
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+ void print(raw_ostream &OS, const Module * = nullptr) const override;
+ void verifyAnalysis() const override;
+ bool runOnFunction(Function &F) override;
+};
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/JIT.h b/src/llvm/include/JIT.h
new file mode 100644
index 0000000..a1b3c8d
--- /dev/null
+++ b/src/llvm/include/JIT.h
@@ -0,0 +1,228 @@
+//===-- JIT.h - Class definition for the JIT --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the top-level JIT data structure.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __JIT_H
+#define __JIT_H
+
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/PassManager.h"
+
+namespace llvm {
+
+class Function;
+struct JITEvent_EmittedFunctionDetails;
+class MachineCodeEmitter;
+class MachineCodeInfo;
+class TargetJITInfo;
+class TargetMachine;
+
+class JITState {
+private:
+ FunctionPassManager PM; // Passes to compile a function
+ Module *M; // Module used to create the PM
+
+ /// PendingFunctions - Functions which have not been code generated yet, but
+ /// were called from a function being code generated.
+ std::vector<AssertingVH<Function> > PendingFunctions;
+
+public:
+ explicit JITState(Module *M) : PM(M), M(M) {}
+
+ FunctionPassManager &getPM() {
+ return PM;
+ }
+
+ Module *getModule() const { return M; }
+ std::vector<AssertingVH<Function> > &getPendingFunctions() {
+ return PendingFunctions;
+ }
+};
+
+
+class JIT : public ExecutionEngine {
+ /// types
+ typedef ValueMap<const BasicBlock *, void *>
+ BasicBlockAddressMapTy;
+ /// data
+ TargetMachine &TM; // The current target we are compiling to
+ TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
+ JITCodeEmitter *JCE; // JCE object
+ JITMemoryManager *JMM;
+ std::vector<JITEventListener*> EventListeners;
+
+ /// AllocateGVsWithCode - Some applications require that global variables and
+ /// code be allocated into the same region of memory, in which case this flag
+ /// should be set to true. Doing so breaks freeMachineCodeForFunction.
+ bool AllocateGVsWithCode;
+
+ /// True while the JIT is generating code. Used to assert against recursive
+ /// entry.
+ bool isAlreadyCodeGenerating;
+
+ JITState *jitstate;
+
+ /// BasicBlockAddressMap - A mapping between LLVM basic blocks and their
+ /// actualized version, only filled for basic blocks that have their address
+ /// taken.
+ BasicBlockAddressMapTy BasicBlockAddressMap;
+
+
+ JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji,
+ JITMemoryManager *JMM, bool AllocateGVsWithCode);
+public:
+ ~JIT();
+
+ static void Register() {
+ JITCtor = createJIT;
+ }
+
+ /// getJITInfo - Return the target JIT information structure.
+ ///
+ TargetJITInfo &getJITInfo() const { return TJI; }
+
+ /// create - Create an return a new JIT compiler if there is one available
+ /// for the current target. Otherwise, return null.
+ ///
+ static ExecutionEngine *create(Module *M,
+ std::string *Err,
+ JITMemoryManager *JMM,
+ CodeGenOpt::Level OptLevel =
+ CodeGenOpt::Default,
+ bool GVsWithCode = true,
+ Reloc::Model RM = Reloc::Default,
+ CodeModel::Model CMM = CodeModel::JITDefault) {
+ return ExecutionEngine::createJIT(M, Err, JMM, OptLevel, GVsWithCode,
+ RM, CMM);
+ }
+
+ void addModule(Module *M) override;
+
+ /// removeModule - Remove a Module from the list of modules. Returns true if
+ /// M is found.
+ bool removeModule(Module *M) override;
+
+ /// runFunction - Start execution with the specified function and arguments.
+ ///
+ GenericValue runFunction(Function *F,
+ const std::vector<GenericValue> &ArgValues) override;
+
+ /// getPointerToNamedFunction - This method returns the address of the
+ /// specified function by using the MemoryManager. As such it is only
+ /// useful for resolving library symbols, not code generated symbols.
+ ///
+ /// If AbortOnFailure is false and no function with the given name is
+ /// found, this function silently returns a null pointer. Otherwise,
+ /// it prints a message to stderr and aborts.
+ ///
+ void *getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure = true) override;
+
+ // CompilationCallback - Invoked the first time that a call site is found,
+ // which causes lazy compilation of the target function.
+ //
+ static void CompilationCallback();
+
+ /// getPointerToFunction - This returns the address of the specified function,
+ /// compiling it if necessary.
+ ///
+ void *getPointerToFunction(Function *F) override;
+
+ /// addPointerToBasicBlock - Adds address of the specific basic block.
+ void addPointerToBasicBlock(const BasicBlock *BB, void *Addr);
+
+ /// clearPointerToBasicBlock - Removes address of specific basic block.
+ void clearPointerToBasicBlock(const BasicBlock *BB);
+
+ /// getPointerToBasicBlock - This returns the address of the specified basic
+ /// block, assuming function is compiled.
+ void *getPointerToBasicBlock(BasicBlock *BB) override;
+
+ /// getOrEmitGlobalVariable - Return the address of the specified global
+ /// variable, possibly emitting it to memory if needed. This is used by the
+ /// Emitter.
+ void *getOrEmitGlobalVariable(const GlobalVariable *GV) override;
+
+ /// getPointerToFunctionOrStub - If the specified function has been
+ /// code-gen'd, return a pointer to the function. If not, compile it, or use
+ /// a stub to implement lazy compilation if available.
+ ///
+ void *getPointerToFunctionOrStub(Function *F) override;
+
+ /// recompileAndRelinkFunction - This method is used to force a function
+ /// which has already been compiled, to be compiled again, possibly
+ /// after it has been modified. Then the entry to the old copy is overwritten
+ /// with a branch to the new copy. If there was no old copy, this acts
+ /// just like JIT::getPointerToFunction().
+ ///
+ void *recompileAndRelinkFunction(Function *F) override;
+
+ /// freeMachineCodeForFunction - deallocate memory used to code-generate this
+ /// Function.
+ ///
+ void freeMachineCodeForFunction(Function *F) override;
+
+ /// addPendingFunction - while jitting non-lazily, a called but non-codegen'd
+ /// function was encountered. Add it to a pending list to be processed after
+ /// the current function.
+ ///
+ void addPendingFunction(Function *F);
+
+ /// getCodeEmitter - Return the code emitter this JIT is emitting into.
+ ///
+ JITCodeEmitter *getCodeEmitter() const { return JCE; }
+
+ static ExecutionEngine *createJIT(Module *M,
+ std::string *ErrorStr,
+ JITMemoryManager *JMM,
+ bool GVsWithCode,
+ TargetMachine *TM);
+
+ // Run the JIT on F and return information about the generated code
+ void runJITOnFunction(Function *F, MachineCodeInfo *MCI = nullptr) override;
+
+ void RegisterJITEventListener(JITEventListener *L) override;
+ void UnregisterJITEventListener(JITEventListener *L) override;
+
+ TargetMachine *getTargetMachine() override { return &TM; }
+
+ /// These functions correspond to the methods on JITEventListener. They
+ /// iterate over the registered listeners and call the corresponding method on
+ /// each.
+ void NotifyFunctionEmitted(
+ const Function &F, void *Code, size_t Size,
+ const JITEvent_EmittedFunctionDetails &Details);
+ void NotifyFreeingMachineCode(void *OldPtr);
+
+ BasicBlockAddressMapTy &
+ getBasicBlockAddressMap() {
+ return BasicBlockAddressMap;
+ }
+
+
+private:
+ static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM,
+ TargetMachine &tm);
+ void runJITOnFunctionUnlocked(Function *F);
+ void updateFunctionStubUnlocked(Function *F);
+ void jitTheFunctionUnlocked(Function *F);
+
+protected:
+
+ /// getMemoryforGV - Allocate memory for a global variable.
+ char* getMemoryForGV(const GlobalVariable* GV) override;
+
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/src/llvm/include/JITMemoryManager.h b/src/llvm/include/JITMemoryManager.h
new file mode 100644
index 0000000..301d227
--- /dev/null
+++ b/src/llvm/include/JITMemoryManager.h
@@ -0,0 +1,318 @@
+//===-- JITMemoryManager.cpp - Memory Allocator for JIT'd code ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DefaultJITMemoryManager class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __JITMEMORYMANAGER_H
+#define __JITMEMORYMANAGER_H
+
+#include <sys/mman.h>
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm-debug.h"
+#include "utils.h"
+
+using namespace llvm;
+
+#define MIN_CODE_CACHE_SIZE (1 * 1024 * 1024)
+#define DEFAULT_GLOBAL_SIZE (64 * 1024)
+#define DEFAULT_THRESHOLD (32 * 1024)
+
+
+// AtExitHandlers - List of functions to call when the program exits,
+// registered with the atexit() library function.
+static std::vector<void (*)()> AtExitHandlers;
+
+/// runAtExitHandlers - Run any functions registered by the program's
+/// calls to atexit(3), which we intercept and store in
+/// AtExitHandlers.
+///
+static void runAtExitHandlers() {
+ while (!AtExitHandlers.empty()) {
+ void (*Fn)() = AtExitHandlers.back();
+ AtExitHandlers.pop_back();
+ Fn();
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Function stubs that are invoked instead of certain library calls
+//
+// Force the following functions to be linked in to anything that uses the
+// JIT. This is a hack designed to work around the all-too-clever Glibc
+// strategy of making these functions work differently when inlined vs. when
+// not inlined, and hiding their real definitions in a separate archive file
+// that the dynamic linker can't see. For more info, search for
+// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
+#if defined(__linux__) && defined(__GLIBC__)
+/* stat functions are redirecting to __xstat with a version number. On x86-64
+ * linking with libc_nonshared.a and -Wl,--export-dynamic doesn't make 'stat'
+ * available as an exported symbol, so we have to add it explicitly.
+ */
+namespace {
+class StatSymbols {
+public:
+ StatSymbols() {
+ sys::DynamicLibrary::AddSymbol("stat", (void*)(intptr_t)stat);
+ sys::DynamicLibrary::AddSymbol("fstat", (void*)(intptr_t)fstat);
+ sys::DynamicLibrary::AddSymbol("lstat", (void*)(intptr_t)lstat);
+ sys::DynamicLibrary::AddSymbol("stat64", (void*)(intptr_t)stat64);
+ sys::DynamicLibrary::AddSymbol("\x1stat64", (void*)(intptr_t)stat64);
+ sys::DynamicLibrary::AddSymbol("\x1open64", (void*)(intptr_t)open64);
+ sys::DynamicLibrary::AddSymbol("\x1lseek64", (void*)(intptr_t)lseek64);
+ sys::DynamicLibrary::AddSymbol("fstat64", (void*)(intptr_t)fstat64);
+ sys::DynamicLibrary::AddSymbol("lstat64", (void*)(intptr_t)lstat64);
+ sys::DynamicLibrary::AddSymbol("atexit", (void*)(intptr_t)atexit);
+ sys::DynamicLibrary::AddSymbol("mknod", (void*)(intptr_t)mknod);
+ }
+};
+}
+static StatSymbols initStatSymbols;
+#endif // __linux__
+
+// jit_exit - Used to intercept the "exit" library call.
+static void jit_exit(int Status) {
+ runAtExitHandlers(); // Run atexit handlers...
+ exit(Status);
+}
+
+// jit_atexit - Used to intercept the "atexit" library call.
+static int jit_atexit(void (*Fn)()) {
+ AtExitHandlers.push_back(Fn); // Take note of atexit handler...
+ return 0; // Always successful
+}
+
+static int jit_noop() {
+ return 0;
+}
+
+
+/// DefaultJITMemoryManager - Manage trace cache memory for the JIT code generation.
+class DefaultJITMemoryManager : public JITMemoryManager {
+ uint8_t *TraceCache;
+ size_t TraceCacheSize;
+
+ uint8_t *GlobalBase; /* section for global data used by QEMU helpers */
+ uint8_t *CodeBase; /* section for emitting trace code */
+ uint8_t *CodeGenPtr;
+
+ size_t GlobalRemain;
+ size_t CodeRemain;
+ size_t Threshold;
+
+ hqemu::Mutex lock;
+
+public:
+ DefaultJITMemoryManager(uint8_t *Cache, size_t Size)
+ : TraceCache(Cache), TraceCacheSize(Size), Threshold(DEFAULT_THRESHOLD)
+ {
+ GlobalBase = TraceCache;
+ GlobalRemain = DEFAULT_GLOBAL_SIZE;
+
+ CodeBase = GlobalBase + DEFAULT_GLOBAL_SIZE;
+ CodeBase = (uint8_t *)(((uintptr_t)CodeBase + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+ CodeRemain = (uintptr_t)TraceCache + TraceCacheSize - (uintptr_t)CodeBase;
+ CodeGenPtr = CodeBase;
+ }
+
+ ~DefaultJITMemoryManager() {}
+
+ //===----------------------------------------------------------------------===//
+ //
+ /// getPointerToNamedFunction - This method returns the address of the specified
+ /// function by using the dynamic loader interface. As such it is only useful
+ /// for resolving library symbols, not code generated symbols.
+ ///
+ void *getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure = true) override {
+ // Check to see if this is one of the functions we want to intercept. Note,
+ // we cast to intptr_t here to silence a -pedantic warning that complains
+ // about casting a function pointer to a normal pointer.
+ if (Name == "exit") return (void*)(intptr_t)&jit_exit;
+ if (Name == "atexit") return (void*)(intptr_t)&jit_atexit;
+
+ // 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;
+
+ const char *NameStr = Name.c_str();
+ // If this is an asm specifier, skip the sentinal.
+ if (NameStr[0] == 1) ++NameStr;
+
+ // If it's an external function, look it up in the process image...
+ void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
+ if (Ptr) return Ptr;
+
+ // If it wasn't found and if it starts with an underscore ('_') character,
+ // try again without the underscore.
+ if (NameStr[0] == '_') {
+ Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
+ if (Ptr) return Ptr;
+ }
+
+ // Darwin/PPC adds $LDBLStub suffixes to various symbols like printf. These
+ // are references to hidden visibility symbols that dlsym cannot resolve.
+ // If we have one of these, strip off $LDBLStub and try again.
+#if defined(__APPLE__) && defined(__ppc__)
+ if (Name.size() > 9 && Name[Name.size()-9] == '$' &&
+ memcmp(&Name[Name.size()-8], "LDBLStub", 8) == 0) {
+ // First try turning $LDBLStub into $LDBL128. If that fails, strip it off.
+ // This mirrors logic in libSystemStubs.a.
+ std::string Prefix = std::string(Name.begin(), Name.end()-9);
+ if (void *Ptr = getPointerToNamedFunction(Prefix+"$LDBL128", false))
+ return Ptr;
+ if (void *Ptr = getPointerToNamedFunction(Prefix, false))
+ return Ptr;
+ }
+#endif
+
+ if (AbortOnFailure) {
+ report_fatal_error("Program used external function '"+Name+
+ "' which could not be resolved!");
+ }
+ return nullptr;
+ }
+
+ void AllocateGOT() override { hqemu_error("fixme.\n"); }
+
+ // Testing methods.
+ bool CheckInvariants(std::string &ErrorStr) override { hqemu_error("fixme.\n"); return false; }
+ size_t GetDefaultCodeSlabSize() override { hqemu_error("fixme.\n"); return 0; }
+ size_t GetDefaultDataSlabSize() override { hqemu_error("fixme.\n"); return 0; }
+ size_t GetDefaultStubSlabSize() override { hqemu_error("fixme.\n"); return 0; }
+ unsigned GetNumCodeSlabs() override { hqemu_error("fixme.\n"); return 0; }
+ unsigned GetNumDataSlabs() override { hqemu_error("fixme.\n"); return 0; }
+ unsigned GetNumStubSlabs() override { hqemu_error("fixme.\n"); return 0; }
+
+ /// startFunctionBody - When a function starts, allocate a block of free
+ /// executable memory, returning a pointer to it and its actual size.
+ uint8_t *startFunctionBody(const Function *F,
+ uintptr_t &ActualSize) override {
+ lock.acquire();
+ if (unlikely(CodeRemain < Threshold))
+ hqemu_error("internal error (fixme).\n");
+
+ ActualSize = CodeRemain;
+ return CodeGenPtr;
+ }
+
+ /// endFunctionBody - The function F is now allocated, and takes the memory
+ /// in the range [FunctionStart,FunctionEnd).
+ void endFunctionBody(const Function *F, uint8_t *FunctionStart,
+ uint8_t *FunctionEnd) override {
+ assert(FunctionEnd > FunctionStart);
+
+ size_t GenSize = FunctionEnd - FunctionStart;
+ if (unlikely(GenSize > CodeRemain))
+ hqemu_error("exceeds available cache size.\n");
+
+ CodeGenPtr = (uint8_t *)(((uintptr_t)CodeGenPtr + GenSize + CODE_GEN_ALIGN - 1)
+ & ~(CODE_GEN_ALIGN - 1));
+ CodeRemain = (uintptr_t)TraceCache + TraceCacheSize - (uintptr_t)CodeGenPtr;
+ lock.release();
+ }
+
+ /// allocateSpace - Allocate a memory block of the given size. This method
+ /// cannot be called between calls to startFunctionBody and endFunctionBody.
+ uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) override {
+ hqemu_error("fixme.\n");
+ return nullptr;
+ }
+
+ /// allocateStub - Allocate memory for a function stub.
+ uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
+ unsigned Alignment) override {
+ return allocateGlobal(StubSize, Alignment);
+ }
+
+ /// allocateGlobal - Allocate memory for a global.
+ uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) override {
+ hqemu::MutexGuard locked(lock);
+
+ if (!Alignment)
+ Alignment = 16;
+ if (Alignment & (Alignment - 1))
+ hqemu_error("alignment must be a power of two.\n");
+
+ unsigned MisAligned = ((intptr_t)GlobalBase & (Alignment - 1));
+ if (MisAligned)
+ MisAligned = Alignment - MisAligned;
+
+ if (GlobalRemain < Size + MisAligned)
+ hqemu_error("exceeds available global size.\n");
+
+ uint8_t *GlobalPtr = GlobalBase + MisAligned;
+ GlobalBase = GlobalPtr + Size;
+ GlobalRemain -= (Size + MisAligned);
+ return GlobalPtr;
+ }
+
+ /// allocateCodeSection - Allocate memory for a code section.
+ uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID,
+ StringRef SectionName) override {
+ hqemu_error("fixme.\n"); return nullptr;
+ }
+
+ /// allocateDataSection - Allocate memory for a data section.
+ uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID, StringRef SectionName,
+ bool IsReadOnly) override {
+ hqemu_error("fixme.\n"); return nullptr;
+ }
+
+ bool finalizeMemory(std::string *ErrMsg) override { return false; }
+
+ uint8_t *getGOTBase() const override { return nullptr; }
+
+ void deallocateBlock(void *Block) {}
+
+ /// deallocateFunctionBody - Deallocate all memory for the specified
+ /// function body.
+ void deallocateFunctionBody(void *Body) override {}
+
+ /// setMemoryWritable - When code generation is in progress,
+ /// the code pages may need permissions changed.
+ void setMemoryWritable() override {}
+ /// setMemoryExecutable - When code generation is done and we're ready to
+ /// start execution, the code pages may need permissions changed.
+ void setMemoryExecutable() override {}
+
+ /// setPoisonMemory - Controls whether we write garbage over freed memory.
+ ///
+ void setPoisonMemory(bool poison) override {}
+
+ size_t getCodeSize() { return CodeGenPtr - CodeBase; }
+ bool isSizeAvailable() {
+ hqemu::MutexGuard locked(lock);
+ return CodeRemain >= Threshold ? 1 : 0;
+ }
+ void Flush() {
+ CodeGenPtr = CodeBase;
+ CodeRemain = (uintptr_t)TraceCache + TraceCacheSize - (uintptr_t)CodeBase;
+ }
+
+ static DefaultJITMemoryManager *Create(uint8_t *Cache, size_t Size) {
+ if (Size < MIN_CODE_CACHE_SIZE)
+ hqemu_error("Trace cache size is too small.\n");
+ return new DefaultJITMemoryManager(Cache, Size);
+ }
+};
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/MCJITMemoryManager.h b/src/llvm/include/MCJITMemoryManager.h
new file mode 100644
index 0000000..33059a5
--- /dev/null
+++ b/src/llvm/include/MCJITMemoryManager.h
@@ -0,0 +1,213 @@
+//===-- MCJITMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Interface of the MCJIT memory manager base class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MCJITMEMORYMANAGER_H
+#define __MCJITMEMORYMANAGER_H
+
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+#include "llvm-debug.h"
+#include "utils.h"
+
+using namespace llvm;
+
+#define MIN_CODE_CACHE_SIZE (1 * 1024 * 1024)
+#define DEFAULT_GLOBAL_SIZE (64 * 1024)
+#define DEFAULT_THRESHOLD (32 * 1024)
+
+// RuntimeDyld clients often want to handle the memory management of
+// what gets placed where. For JIT clients, this is the subset of
+// JITMemoryManager required for dynamic loading of binaries.
+//
+// FIXME: As the RuntimeDyld fills out, additional routines will be needed
+// for the varying types of objects to be allocated.
+class DefaultMCJITMemoryManager : public RTDyldMemoryManager {
+ uint8_t *TraceCache;
+ size_t TraceCacheSize;
+
+ uint8_t *GlobalBase; /* section for global data used by QEMU helpers */
+ uint8_t *CodeBase; /* section for emitting trace code */
+ uint8_t *CodeGenPtr;
+
+ size_t GlobalRemain;
+ size_t CodeRemain;
+ size_t Threshold;
+
+ hqemu::Mutex lock;
+
+ SymbolMap Symbols;
+
+public:
+ DefaultMCJITMemoryManager(uint8_t *Cache, size_t Size)
+ : TraceCache(Cache), TraceCacheSize(Size), Threshold(DEFAULT_THRESHOLD)
+ {
+ GlobalBase = TraceCache;
+ GlobalRemain = DEFAULT_GLOBAL_SIZE;
+
+ CodeBase = GlobalBase + DEFAULT_GLOBAL_SIZE;
+ CodeBase = (uint8_t *)(((uintptr_t)CodeBase + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+ CodeRemain = (uintptr_t)TraceCache + TraceCacheSize - (uintptr_t)CodeBase;
+ CodeGenPtr = CodeBase;
+ }
+ ~DefaultMCJITMemoryManager() {}
+
+ /// Allocate a memory block of (at least) the given size suitable for
+ /// executable code. The SectionID is a unique identifier assigned by the JIT
+ /// engine, and optionally recorded by the memory manager to access a loaded
+ /// section.
+ uint8_t *allocateCodeSection(
+ uintptr_t Size, unsigned Alignment, unsigned SectionID,
+ StringRef SectionName) override {
+ hqemu::MutexGuard locked(lock);
+
+ if (!Alignment)
+ Alignment = 16;
+
+ if (Alignment & (Alignment - 1))
+ hqemu_error("Alignment must be a power of two.\n");
+
+ uintptr_t CurGenPtr = (uintptr_t)CodeGenPtr;
+ CurGenPtr = (CurGenPtr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
+ CodeGenPtr = (uint8_t *)((CurGenPtr + Size + CODE_GEN_ALIGN - 1) &
+ ~(uintptr_t)(CODE_GEN_ALIGN - 1));
+ CodeRemain = (uintptr_t)TraceCache + TraceCacheSize - (uintptr_t)CodeGenPtr;
+ return (uint8_t *)CurGenPtr;
+ }
+
+ /// Allocate a memory block of (at least) the given size suitable for data.
+ /// The SectionID is a unique identifier assigned by the JIT engine, and
+ /// optionally recorded by the memory manager to access a loaded section.
+ uint8_t *allocateDataSection(
+ uintptr_t Size, unsigned Alignment, unsigned SectionID,
+ StringRef SectionName, bool IsReadOnly) override {
+ return allocateCodeSection(Size, Alignment, SectionID, SectionName);
+ }
+
+ /// Inform the memory manager about the total amount of memory required to
+ /// allocate all sections to be loaded:
+ /// \p CodeSize - the total size of all code sections
+ /// \p DataSizeRO - the total size of all read-only data sections
+ /// \p DataSizeRW - the total size of all read-write data sections
+ ///
+ /// Note that by default the callback is disabled. To enable it
+ /// redefine the method needsToReserveAllocationSpace to return true.
+ void reserveAllocationSpace(
+ uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) {
+ hqemu_error("fixme.\n");
+ }
+
+ /// Override to return true to enable the reserveAllocationSpace callback.
+ bool needsToReserveAllocationSpace() { return false; }
+
+ /// Register the EH frames with the runtime so that c++ exceptions work.
+ ///
+ /// \p Addr parameter provides the local address of the EH frame section
+ /// data, while \p LoadAddr provides the address of the data in the target
+ /// address space. If the section has not been remapped (which will usually
+ /// be the case for local execution) these two values will be the same.
+ void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {
+ hqemu_error("fixme.\n");
+ }
+
+ void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {
+ hqemu_error("fixme.\n");
+ }
+
+ /// This method returns the address of the specified function or variable.
+ /// It is used to resolve symbols during module linking.
+ uint64_t getSymbolAddress(const std::string &Name) {
+ hqemu::MutexGuard locked(lock);
+ if (Symbols.find(Name) == Symbols.end()) {
+ std::string ErrMsg = "Program used external symbol '" + Name +
+ "'which could not be resolved!\n";
+ hqemu_error(ErrMsg.c_str());
+ }
+ return Symbols[Name];
+ }
+
+ /// This method returns the address of the specified function. As such it is
+ /// only useful for resolving library symbols, not code generated symbols.
+ ///
+ /// If \p AbortOnFailure is false and no function with the given name is
+ /// found, this function returns a null pointer. Otherwise, it prints a
+ /// message to stderr and aborts.
+ ///
+ /// This function is deprecated for memory managers to be used with
+ /// MCJIT or RuntimeDyld. Use getSymbolAddress instead.
+ void *getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure = true) {
+ if (AbortOnFailure) {
+ std::string ErrMsg = "Program used external symbol '" + Name +
+ "'which could not be resolved!\n";
+ hqemu_error(ErrMsg.c_str());
+ }
+ return nullptr;
+ }
+
+ /// This method is called after an object has been loaded into memory but
+ /// before relocations are applied to the loaded sections. The object load
+ /// may have been initiated by MCJIT to resolve an external symbol for another
+ /// object that is being finalized. In that case, the object about which
+ /// the memory manager is being notified will be finalized immediately after
+ /// the memory manager returns from this call.
+ ///
+ /// Memory managers which are preparing code for execution in an external
+ /// address space can use this call to remap the section addresses for the
+ /// newly loaded object.
+#if defined(LLVM_V35)
+ void notifyObjectLoaded(ExecutionEngine *EE,
+ const ObjectImage *Obj) {
+ }
+#else
+ void notifyObjectLoaded(RuntimeDyld &RTDyld,
+ const object::ObjectFile &Obj) {
+ }
+#endif
+
+ /// This method is called when object loading is complete and section page
+ /// permissions can be applied. It is up to the memory manager implementation
+ /// to decide whether or not to act on this method. The memory manager will
+ /// typically allocate all sections as read-write and then apply specific
+ /// permissions when this method is called. Code sections cannot be executed
+ /// until this function has been called. In addition, any cache coherency
+ /// operations needed to reliably use the memory are also performed.
+ ///
+ /// Returns true if an error occurred, false otherwise.
+ bool finalizeMemory(std::string *ErrMsg = nullptr) override {
+ return false;
+ }
+
+ void AddSymbols(SymbolMap &symbols) {
+ Symbols = symbols;
+ }
+
+ size_t getCodeSize() { return CodeGenPtr - CodeBase; }
+ bool isSizeAvailable() {
+ hqemu::MutexGuard locked(lock);
+ return CodeRemain >= Threshold ? 1 : 0;
+ }
+ void Flush() {
+ CodeGenPtr = CodeBase;
+ CodeRemain = (uintptr_t)TraceCache + TraceCacheSize - (uintptr_t)CodeBase;
+ }
+
+ static DefaultMCJITMemoryManager *Create(uint8_t *Cache, size_t Size) {
+ if (Size < MIN_CODE_CACHE_SIZE) {
+ std::string ErrMsg = "Trace cache size is too small (" +
+ std::to_string(Size) + ")\n.";
+ hqemu_error(ErrMsg.c_str());
+ }
+ return new DefaultMCJITMemoryManager(Cache, Size);
+ }
+};
+
+#endif
diff --git a/src/llvm/include/hqemu-config.h b/src/llvm/include/hqemu-config.h
new file mode 100644
index 0000000..2e2f42f
--- /dev/null
+++ b/src/llvm/include/hqemu-config.h
@@ -0,0 +1,142 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __HQEMU_CONFIG_H
+#define __HQEMU_CONFIG_H
+
+
+#define PACKAGE_NAME "HQEMU"
+#define PACKAGE_VERSION_MAJOR "2.5"
+#define PACKAGE_VERSION_MINOR "2"
+
+#define ENABLE_IBTC
+#define ENABLE_CPBL
+#define ENABLE_LPAGE
+#define ENABLE_PASSES
+#define ENABLE_MCJIT
+//#define ENABLE_HPM_THREAD
+//#define ENABLE_TLBVERSION
+//#define ENALBE_CPU_PROFILE
+//#define USE_TRACETREE_ONLY
+
+
+#if defined(CONFIG_USER_ONLY)
+# define ENABLE_TCG_VECTOR
+# define GUEST_BASE guest_base
+#else
+# define GUEST_BASE (0UL)
+#endif
+
+#if defined(ENABLE_TLBVERSION)
+# if defined(ALIGNED_ONLY)
+# undef ENABLE_TLBVERSION
+# elif HOST_LONG_BITS == 64 && TARGET_LONG_BITS == 32 && defined(HOST_X86_64)
+# define ENABLE_TLBVERSION_EXT
+# endif
+#endif
+
+#ifndef ENABLE_TLBVERSION
+# define TLB_INVALID_SHIFT 3
+# define TLB_NOTDIRTY_SHIFT 4
+# define TLB_MMIO_SHIFT 5
+# define TLB_VERSION_BITS 0
+# define TLB_VERSION_MASK 0
+# define TLB_VERSION_SHIFT (0)
+# define tlb_version(__env) 0
+typedef target_ulong tlbaddr_t;
+#elif defined(ENABLE_TLBVERSION_EXT)
+# define TLB_INVALID_SHIFT 3
+# define TLB_NOTDIRTY_SHIFT 4
+# define TLB_MMIO_SHIFT 5
+# define TLB_VERSION_BITS 32
+# define TLB_VERSION_SIZE (1UL << TLB_VERSION_BITS)
+# define TLB_VERSION_MASK (0xFFFFFFFF00000000UL)
+# define TLB_VERSION_SHIFT (32)
+# define tlb_version(__env) (__env->tlb_version)
+typedef unsigned long tlbaddr_t;
+#else
+# define TLB_INVALID_SHIFT (TARGET_PAGE_BITS - 3)
+# define TLB_NOTDIRTY_SHIFT (TARGET_PAGE_BITS - 2)
+# define TLB_MMIO_SHIFT (TARGET_PAGE_BITS - 1)
+# define TLB_VERSION_BITS (TARGET_PAGE_BITS - 3)
+# define TLB_VERSION_SIZE (1 << TLB_VERSION_BITS)
+# define TLB_VERSION_MASK (TLB_VERSION_SIZE - 1)
+# define TLB_VERSION_SHIFT (0)
+# define tlb_version(__env) (__env->tlb_version)
+typedef target_ulong tlbaddr_t;
+#endif
+
+
+typedef int BlockID;
+typedef int TraceID;
+#define BUILD_NONE ((uint16_t)0)
+#define BUILD_TCG ((uint16_t)1 << 0)
+#define BUILD_LLVM ((uint16_t)1 << 1)
+
+#define CPU_OPTIMIZATION_COMMON \
+ unsigned long sp; \
+ void *opt_link; \
+ uint16_t build_mode; \
+ int start_trace_prediction; \
+ int fallthrough; \
+ uintptr_t image_base; \
+ uint32_t restore_val; \
+ uint64_t num_trace_exits; \
+
+
+#define TB_OPTIMIZATION_COMMON \
+ BlockID id; \
+ TraceID tid; /* trace id */ \
+ int mode; /* current state */ \
+ void *opt_ptr; /* pointer to the optimized code */ \
+ uint32_t exec_count; /* trace profile execution count */ \
+ uint16_t patch_jmp; /* offset of trace trampoline */ \
+ uint16_t patch_next; /* offset of trace prediction stub */ \
+ target_ulong jmp_pc[2]; /* pc of the succeeding blocks */ \
+ void *image; \
+ void *state; \
+ void *chain;
+
+
+enum {
+ BLOCK_NONE = 0,
+ BLOCK_ACTIVE,
+ BLOCK_TRACEHEAD,
+ BLOCK_OPTIMIZED,
+ BLOCK_INVALID,
+};
+
+enum {
+ TRANS_MODE_NONE = 0,
+ TRANS_MODE_BLOCK,
+ TRANS_MODE_HYBRIDS,
+ TRANS_MODE_HYBRIDM,
+ TRANS_MODE_INVALID,
+};
+
+/* Parse translation mode from env-variable LLVM_MODE. */
+static inline int getTransMode(void) {
+ char *p = getenv("LLVM_MODE");
+ if (p == NULL) return TRANS_MODE_HYBRIDM;
+ if (!strcmp(p, "hybridm")) return TRANS_MODE_HYBRIDM;
+ if (!strcmp(p, "hybrids")) return TRANS_MODE_HYBRIDS;
+ if (!strcmp(p, "block")) return TRANS_MODE_BLOCK;
+ if (!strcmp(p, "none")) return TRANS_MODE_NONE;
+ return TRANS_MODE_INVALID;
+}
+
+/* Annotation/attribute for traces. */
+enum {
+ A_None = ((uint32_t)0),
+ A_SetCC = ((uint32_t)1 << 0),
+ A_NoSIMDization = ((uint32_t)1 << 1),
+};
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/include/hqemu-helper.h b/src/llvm/include/hqemu-helper.h
new file mode 100644
index 0000000..dfcb396
--- /dev/null
+++ b/src/llvm/include/hqemu-helper.h
@@ -0,0 +1,8 @@
+DEF_HELPER_1(export_hqemu, void, env)
+DEF_HELPER_1(lookup_ibtc, ptr, env)
+DEF_HELPER_1(lookup_cpbl, ptr, env)
+DEF_HELPER_3(validate_cpbl, int, env, tl, int)
+DEF_HELPER_2(NET_profile, void, env, int)
+DEF_HELPER_2(NET_predict, void, env, int)
+DEF_HELPER_2(verify_tb, void, env, int)
+DEF_HELPER_3(profile_exec, void, env, ptr, int)
diff --git a/src/llvm/include/hqemu.h b/src/llvm/include/hqemu.h
new file mode 100644
index 0000000..f5e7180
--- /dev/null
+++ b/src/llvm/include/hqemu.h
@@ -0,0 +1,84 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __HQEMU_H
+#define __HQEMU_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "config-host.h"
+#include "config-target.h"
+#include "hqemu-config.h"
+
+#define build_tcg(_env) ((_env)->build_mode & BUILD_TCG)
+#define build_llvm(_env) ((_env)->build_mode & BUILD_LLVM)
+#define build_llvm_only(_env) ((_env)->build_mode == BUILD_LLVM)
+
+void hqemu_help(void);
+
+/* Optimizations */
+int optimization_init(CPUArchState *env);
+int optimization_finalize(CPUArchState *env);
+int optimization_reset(CPUArchState *env, int force_flush);
+int optimization_remove_entry(CPUArchState *env, TranslationBlock *tb);
+int optimization_flush_page(CPUArchState *env, target_ulong pc);
+int optimization_init_tb(TranslationBlock *tb, int id);
+
+void itlb_update_entry(CPUArchState *env, TranslationBlock *tb);
+void ibtc_update_entry(CPUArchState *env, TranslationBlock *tb);
+
+int lpt_reset(CPUArchState *env);
+int lpt_add_page(CPUArchState *env, target_ulong addr, target_ulong size);
+int lpt_search_page(CPUArchState *env, target_ulong addr, target_ulong *addrp, target_ulong *sizep);
+int lpt_flush_page(CPUArchState *env, target_ulong addr, target_ulong *addrp, target_ulong *sizep);
+
+
+/* Tracer */
+void tracer_exec_tb(CPUArchState *env, uintptr_t next_tb, TranslationBlock *tb);
+void tracer_reset(CPUArchState *env);
+
+
+/* LLVM */
+int llvm_init(void);
+int llvm_finalize(void);
+int llvm_alloc_cache(void);
+int llvm_check_cache(void);
+int llvm_tb_flush(void);
+int llvm_tb_remove(TranslationBlock *tb);
+void llvm_handle_chaining(uintptr_t next_tb, TranslationBlock *tb);
+int llvm_locate_trace(uintptr_t searched_pc);
+TranslationBlock *llvm_find_pc(CPUState *cpu, uintptr_t searched_pc);
+int llvm_restore_state(CPUState *cpu, TranslationBlock *tb, uintptr_t searched_pc);
+void llvm_fork_start(void);
+void llvm_fork_end(int child);
+
+
+/* Annotation */
+enum {
+ ANNOTATION_NONE = 0,
+ ANNOTATION_LOOP,
+};
+int llvm_has_annotation(target_ulong addr, int annotation);
+
+
+/* External variables */
+extern int tracer_mode;
+extern target_ulong pcid;
+extern unsigned long alignment_count[]; /* 0: misaligned, 1: aligned. */
+extern unsigned long aligned_boundary;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/include/llvm-annotate.h b/src/llvm/include/llvm-annotate.h
new file mode 100644
index 0000000..25454ed
--- /dev/null
+++ b/src/llvm/include/llvm-annotate.h
@@ -0,0 +1,51 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_ANNOTATE_H
+#define __LLVM_ANNOTATE_H
+
+#include <map>
+#include <cstdint>
+#include "qemu-types.h"
+#include "llvm-types.h"
+#include "utils.h"
+
+/* Loop metadata */
+struct LoopMetadata {
+ LoopMetadata()
+ : Address(-1), Length(-1), VS(-1), VF(-1), Distance(INT_MIN), Start(-1),
+ End(-1), Stride(-1) {}
+ target_ulong Address;
+ uint32_t Length;
+ uint32_t VS, VF;
+ int Distance;
+ int Start, End;
+ int Stride;
+};
+
+/*
+ * The AnnotationFactory class manages the metadata information.
+ */
+class AnnotationFactory {
+ typedef std::map<uintptr_t, LoopMetadata*> LoopList;
+
+ std::string MetaFile;
+
+ int ParseXML(const char *name);
+
+public:
+ AnnotationFactory();
+ ~AnnotationFactory();
+
+ LoopList Loops;
+ LoopMetadata *getLoopAnnotation(target_ulong addr);
+ bool hasLoopAnnotation(target_ulong addr);
+};
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/llvm-debug.h b/src/llvm/include/llvm-debug.h
new file mode 100644
index 0000000..405b466
--- /dev/null
+++ b/src/llvm/include/llvm-debug.h
@@ -0,0 +1,247 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_DEBUG_H
+#define __LLVM_DEBUG_H
+
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <cstdarg>
+#include <unistd.h>
+#include <sys/time.h>
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrAnalysis.h"
+#include "llvm/Support/FileSystem.h"
+#include "utils.h"
+
+
+struct DebugMode {
+ uint64_t Mode;
+
+ DebugMode(uint64_t M) : Mode(M) {}
+
+ bool operator==(const DebugMode &RHS) const {
+ return Mode == RHS.Mode;
+ }
+ bool operator&(const DebugMode &RHS) const {
+ return Mode & RHS.Mode;
+ }
+ DebugMode operator|(const DebugMode &RHS) {
+ return DebugMode(Mode | RHS.Mode);
+ }
+ DebugMode &operator|=(const DebugMode &RHS) {
+ Mode |= RHS.Mode;
+ return *this;
+ }
+};
+
+/*
+ * LLVMDebug provides facilities to debug the LLVM translator, based on the
+ * debug levels.
+ */
+class LLVMDebug {
+public:
+ enum LLVMDebugMode {
+ D_NONE = ((uint64_t)0),
+ D_LLVM = ((uint64_t)1 << 0),
+ D_INASM = ((uint64_t)1 << 1),
+ D_OP = ((uint64_t)1 << 2),
+ D_OUTASM = ((uint64_t)1 << 3),
+ D_IR = ((uint64_t)1 << 4),
+ D_IR_OPT = ((uint64_t)1 << 5),
+ D_ENTRY = ((uint64_t)1 << 6),
+ D_VERIFY = ((uint64_t)1 << 7),
+ D_PASS = ((uint64_t)1 << 8),
+ D_ANNOTATE = ((uint64_t)1 << 9),
+ D_HPM = ((uint64_t)1 << 10),
+ D_ASM = (D_INASM | D_OP | D_OUTASM),
+ D_DEBUG = (D_LLVM | D_IR_OPT | D_OUTASM | D_PASS),
+ D_ALL = (D_LLVM | D_INASM | D_OP | D_OUTASM | D_IR | D_IR_OPT |
+ D_ENTRY | D_VERIFY | D_PASS | D_ANNOTATE | D_HPM),
+ };
+
+ LLVMDebug() : Mode(D_NONE)
+ {
+ hqemu_out.reset(new llvm::raw_fd_ostream(STDOUT_FILENO, false, true));
+ hqemu_dbg.reset(new llvm::raw_fd_ostream(STDERR_FILENO, false, true));
+
+ std::string Str("");
+ gettimeofday(&uptime, nullptr);
+ ParseDebugMode(Str, false);
+ hqemu_null.SetUnbuffered();
+ }
+
+ DebugMode &getDebugMode() {
+ return Mode;
+ }
+
+ DebugMode &getDebugMode(LLVMDebugMode M) {
+ if (Modes.find(M) == Modes.end())
+ M = D_NONE;
+ return *Modes[M];
+ }
+
+ void setDebugMode(std::string &DebugLevel, std::string &DebugFile) {
+ ParseDebugMode(DebugLevel);
+ if (DebugFile != "") {
+ std::error_code EC;
+ auto OS = new llvm::raw_fd_ostream(DebugFile, EC,
+ llvm::sys::fs::F_Text);
+ if (EC) {
+ *hqemu_dbg << "Error: failed to open debug file " << DebugFile
+ << ". (" << EC.message().c_str() << ")\n";
+ }
+ OS->SetUnbuffered();
+ hqemu_dbg.reset(OS);
+ }
+ }
+
+ void Flush() {
+ hqemu_dbg->flush();
+ }
+
+ void error(const char *fname, const char *fmt, ...) {
+ static char str[256] = {'\0'};
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(str, fmt, ap);
+ va_end(ap);
+ *hqemu_dbg << timestamp() << " Error: " << fname << " - " << str;
+ exit(0);
+ }
+
+ llvm::raw_ostream &output() {
+ return *hqemu_out;
+ }
+
+ llvm::raw_ostream &debug() {
+ return *hqemu_dbg;
+ }
+
+ llvm::raw_ostream &operator<<(DebugMode &M) {
+ if (M & Mode) {
+ *hqemu_dbg << timestamp() << " ";
+ return *hqemu_dbg;
+ }
+ return hqemu_null;
+ };
+
+private:
+ llvm::raw_null_ostream hqemu_null;
+ std::unique_ptr<llvm::raw_fd_ostream> hqemu_out;
+ std::unique_ptr<llvm::raw_fd_ostream> hqemu_dbg;
+ struct timeval uptime; /* The startup time of the DBT */
+ DebugMode Mode; /* The debug level */
+ std::map<LLVMDebugMode, DebugMode*> Modes;
+
+ std::string timestamp() {
+ struct timeval tv;
+ char timestamp[32];
+ gettimeofday(&tv, 0);
+ timersub(&tv, &uptime, &tv);
+ strftime(timestamp, 32, "[%H:%M:%S", gmtime(&tv.tv_sec));
+ sprintf(timestamp + 9, ".%06ld]", tv.tv_usec);
+ return timestamp;
+ }
+
+ void ParseDebugMode(std::string &DebugLevel, bool Update=true) {
+ static std::string debug_str[] = {
+ "none", "llvm", "in_asm", "op", "out_asm", "ir", "ir_opt",
+ "entry", "verify", "pass", "annotate", "hpm", "asm", "debug",
+ "all"
+ };
+ static LLVMDebugMode debug_enum[] = {
+ D_NONE, D_LLVM, D_INASM, D_OP, D_OUTASM, D_IR, D_IR_OPT,
+ D_ENTRY, D_VERIFY, D_PASS, D_ANNOTATE, D_HPM, D_ASM, D_DEBUG,
+ D_ALL
+ };
+
+ if (!Update) {
+ for (auto M : debug_enum)
+ Modes[M] = new DebugMode(M);
+ return;
+ }
+
+ if (DebugLevel.empty())
+ return;
+
+ std::istringstream ss(DebugLevel);
+ std::string token;
+ while(std::getline(ss, token, ',')) {
+ for (unsigned i = 0, e = ARRAY_SIZE(debug_enum); i != e; ++i) {
+ if (token == debug_str[i]) {
+ Mode |= getDebugMode(debug_enum[i]);
+ break;
+ }
+ }
+ }
+ }
+};
+
+extern LLVMDebug DM;
+
+/* Print messages to stdout. Should not use this function in release mode. */
+static inline llvm::raw_ostream &out() {
+ return DM.output();
+}
+/* Print messages to stderr, controlled by DebugMode. */
+static inline LLVMDebug &dbg() {
+ return DM;
+}
+/* Print error messages to stderr and terminate the process. */
+#define hqemu_error(msg,args...) do { DM.error(__func__,msg,##args); } while(0)
+
+/* Macros to get defined DebugMode. */
+#define DEBUG_NONE DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_NONE)
+#define DEBUG_LLVM DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_LLVM)
+#define DEBUG_INASM DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_INASM)
+#define DEBUG_OP DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_OP)
+#define DEBUG_OUTASM DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_OUTASM)
+#define DEBUG_IR DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_IR)
+#define DEBUG_IR_OPT DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_IR_OPT)
+#define DEBUG_ENTRY DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_ENTRY)
+#define DEBUG_VERIFY DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_VERIFY)
+#define DEBUG_PASS DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_PASS)
+#define DEBUG_ANNOTATE DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_ANNOTATE)
+#define DEBUG_HPM DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_HPM)
+#define DEBUG_ASM DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_ASM)
+#define DEBUG_DEBUG DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_DEBUG)
+#define DEBUG_ALL DM.getDebugMode(LLVMDebug::LLVMDebugMode::D_ALL)
+
+
+
+/*
+ * Binary disassembler using MCDisassembler.
+ */
+class MCDisasm {
+ const llvm::MCDisassembler *DisAsm;
+ const llvm::MCSubtargetInfo *STI;
+ llvm::MCInstPrinter *IP;
+ const llvm::MCInstrAnalysis *MIA;
+ bool HostDisAsm;
+ bool NoShowRawInsn;
+
+ MCDisasm(const llvm::Target *TheTarget, std::string TripleName,
+ bool isHost);
+
+ void DumpBytes(llvm::ArrayRef<uint8_t> bytes, llvm::raw_ostream &OS);
+
+public:
+ ~MCDisasm();
+ void PrintInAsm(uint64_t Addr, uint64_t Size, uint64_t GuestAddr);
+ void PrintOutAsm(uint64_t Addr, uint64_t Size);
+
+ static MCDisasm *CreateMCDisasm(std::string TripleName, bool isHost);
+};
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/llvm-hard-perfmon.h b/src/llvm/include/llvm-hard-perfmon.h
new file mode 100644
index 0000000..ac03b23
--- /dev/null
+++ b/src/llvm/include/llvm-hard-perfmon.h
@@ -0,0 +1,87 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_HARD_PERFMON_H
+#define __LLVM_HARD_PERFMON_H
+
+#include <map>
+#include <thread>
+#include "pmu/pmu.h"
+#include "utils.h"
+
+class PerfmonData;
+class BaseTracer;
+
+enum HPMControl {
+ HPM_INIT = 0,
+ HPM_FINALIZE,
+ HPM_START,
+ HPM_STOP,
+};
+
+/*
+ * Hardware Performance Monitor (HPM)
+ */
+class HardwarePerfmon {
+ std::thread MonThread; /* Monitor thread */
+ int MonThreadID; /* Monitor thread id */
+ bool MonThreadStop; /* Monitor thread is stopped or not */
+ hqemu::Mutex Lock;
+
+ /* Start monitor thread. */
+ void StartMonThread();
+
+ /* Monitor thread routine. */
+ void MonitorFunc();
+
+public:
+ HardwarePerfmon();
+ ~HardwarePerfmon();
+
+ /* Set up HPM with the monitor thread id */
+ void Init(int monitor_thread_tid);
+
+ /* Register a thread to be monitored. */
+ void RegisterThread(BaseTracer *Tracer);
+
+ /* Unreigster a thread from being monitored. */
+ void UnregisterThread(BaseTracer *Tracer);
+
+ /* Notify that the execution enters/leaves the code cache. */
+ void NotifyCacheEnter(BaseTracer *Tracer);
+ void NotifyCacheLeave(BaseTracer *Tracer);
+
+ /* Stop the monitor. */
+ void Pause();
+
+ /* Restart the monitor. */
+ void Resume();
+};
+
+
+class PerfmonData {
+public:
+ PerfmonData(int tid);
+ ~PerfmonData();
+
+ int TID;
+ pmu::Handle ICountHndl;
+ pmu::Handle BranchHndl;
+ pmu::Handle MemLoadHndl;
+ pmu::Handle MemStoreHndl;
+ pmu::Handle CoverSetHndl;
+ uint64_t LastNumBranches, LastNumLoads, LastNumStores;
+
+ void MonitorBasic(HPMControl Ctl);
+ void MonitorCoverSet(HPMControl Ctl);
+};
+
+extern HardwarePerfmon *HP;
+
+#endif /* __LLVM_HARD_PERFMON_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/llvm-helper.h b/src/llvm/include/llvm-helper.h
new file mode 100644
index 0000000..2d24f81
--- /dev/null
+++ b/src/llvm/include/llvm-helper.h
@@ -0,0 +1,755 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * This file defines the QEMU helper functions that could be inlined by
+ * the LLVM translators.
+ */
+
+#ifndef __LLVM_HELPER_H
+#define __LLVM_HELPER_H
+
+/* Speical TCG runtime helper */
+ "tcg_helper_div_i32",
+ "tcg_helper_rem_i32",
+ "tcg_helper_divu_i32",
+ "tcg_helper_remu_i32",
+ "tcg_helper_shl_i64",
+ "tcg_helper_shr_i64",
+ "tcg_helper_sar_i64",
+ "tcg_helper_div_i64",
+ "tcg_helper_rem_i64",
+ "tcg_helper_divu_i64",
+ "tcg_helper_remu_i64",
+
+#if defined(TARGET_I386)
+ /* General */
+ "helper_cc_compute_c",
+ "helper_cc_compute_all",
+ "helper_load_seg",
+ "helper_write_eflags",
+ "helper_read_eflags",
+ "helper_cli",
+ "helper_sti",
+ "helper_set_inhibit_irq",
+ "helper_reset_inhibit_irq",
+ /* FPU */
+ "helper_divb_AL",
+ "helper_idivb_AL",
+ "helper_divw_AX",
+ "helper_idivw_AX",
+ "helper_divl_EAX",
+ "helper_idivl_EAX",
+ "helper_flds_FT0",
+ "helper_fldl_FT0",
+ "helper_fildl_FT0",
+ "helper_flds_ST0",
+ "helper_fldl_ST0",
+ "helper_fildl_ST0",
+ "helper_fildll_ST0",
+ "helper_fsts_ST0",
+ "helper_fstl_ST0",
+ "helper_fist_ST0",
+ "helper_fistl_ST0",
+ "helper_fistll_ST0",
+ "helper_fistt_ST0",
+ "helper_fisttl_ST0",
+ "helper_fisttll_ST0",
+ "helper_fldt_ST0",
+ "helper_fstt_ST0",
+ "helper_fpush",
+ "helper_fpop",
+ "helper_fdecstp",
+ "helper_fincstp",
+ "helper_ffree_STN",
+ "helper_fmov_ST0_FT0",
+ "helper_fmov_FT0_STN",
+ "helper_fmov_ST0_STN",
+ "helper_fmov_STN_ST0",
+ "helper_fxchg_ST0_STN",
+ "helper_fcom_ST0_FT0",
+ "helper_fucom_ST0_FT0",
+ "helper_fcomi_ST0_FT0",
+ "helper_fucomi_ST0_FT0",
+ "helper_fadd_ST0_FT0",
+ "helper_fmul_ST0_FT0",
+ "helper_fsub_ST0_FT0",
+ "helper_fsubr_ST0_FT0",
+ "helper_fdiv_ST0_FT0",
+ "helper_fdivr_ST0_FT0",
+ "helper_fadd_STN_ST0",
+ "helper_fmul_STN_ST0",
+ "helper_fsub_STN_ST0",
+ "helper_fsubr_STN_ST0",
+ "helper_fdiv_STN_ST0",
+ "helper_fdivr_STN_ST0",
+ "helper_fchs_ST0",
+ "helper_fabs_ST0",
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS == 64
+ "helper_fxam_ST0",
+#endif
+ "helper_fld1_ST0",
+ "helper_fldl2t_ST0",
+ "helper_fldl2e_ST0",
+ "helper_fldpi_ST0",
+ "helper_fldlg2_ST0",
+ "helper_fldln2_ST0",
+ "helper_fldz_ST0",
+ "helper_fldz_FT0",
+ "helper_fnstsw",
+ "helper_fnstcw",
+ "helper_fldcw",
+ "helper_fclex",
+ "helper_fwait",
+ "helper_fninit",
+ "helper_fbld_ST0",
+ "helper_fbst_ST0",
+ "helper_f2xm1",
+ "helper_fyl2x",
+ "helper_fptan",
+ "helper_fpatan",
+ "helper_fxtract",
+ "helper_fprem1",
+ "helper_fprem",
+ "helper_fyl2xp1",
+ "helper_fsqrt",
+ "helper_fsincos",
+ "helper_frndint",
+ "helper_fscale",
+ "helper_fsin",
+ "helper_fcos",
+ "helper_fstenv",
+ "helper_fldenv",
+ "helper_fsave",
+ "helper_frstor",
+ "helper_fxsave",
+ "helper_fxrstor",
+ "helper_bsf",
+ "helper_bsr",
+ "helper_lzcnt",
+
+ /* MMX/SSE */
+ "helper_psrlw_xmm",
+ "helper_psraw_xmm",
+ "helper_psllw_xmm",
+ "helper_psrld_xmm",
+ "helper_psrad_xmm",
+ "helper_pslld_xmm",
+ "helper_psrlq_xmm",
+ "helper_psllq_xmm",
+ "helper_psrldq_xmm",
+ "helper_pslldq_xmm",
+ "helper_paddb_xmm",
+ "helper_paddw_xmm",
+ "helper_paddl_xmm",
+ "helper_paddq_xmm",
+ "helper_psubb_xmm",
+ "helper_psubw_xmm",
+ "helper_psubl_xmm",
+ "helper_psubq_xmm",
+ "helper_paddusb_xmm",
+ "helper_paddsb_xmm",
+ "helper_psubusb_xmm",
+ "helper_psubsb_xmm",
+ "helper_paddusw_xmm",
+ "helper_paddsw_xmm",
+ "helper_psubusw_xmm",
+ "helper_psubsw_xmm",
+ "helper_pminub_xmm",
+ "helper_pmaxub_xmm",
+ "helper_pminsw_xmm",
+ "helper_pmaxsw_xmm",
+ "helper_pand_xmm",
+ "helper_pandn_xmm",
+ "helper_por_xmm",
+ "helper_pxor_xmm",
+ "helper_pcmpgtb_xmm",
+ "helper_pcmpgtw_xmm",
+ "helper_pcmpgtl_xmm",
+ "helper_pcmpeqb_xmm",
+ "helper_pcmpeqw_xmm",
+ "helper_pcmpeql_xmm",
+ "helper_pmullw_xmm",
+ "helper_pmulhuw_xmm",
+ "helper_pmulhw_xmm",
+ "helper_pavgb_xmm",
+ "helper_pavgw_xmm",
+ "helper_pmuludq_xmm",
+ "helper_pmaddwd_xmm",
+ "helper_psadbw_xmm",
+ "helper_maskmov_xmm",
+ "helper_movl_mm_T0_xmm",
+ "helper_shufps_xmm",
+ "helper_shufpd_xmm",
+#if !defined(TCG_TARGET_ARM)
+ "helper_pshufd_xmm",
+ "helper_pshuflw_xmm",
+ "helper_pshufhw_xmm",
+ "helper_punpcklbw_xmm",
+ "helper_punpcklwd_xmm",
+ "helper_punpckldq_xmm",
+ "helper_punpckhbw_xmm",
+ "helper_punpckhwd_xmm",
+ "helper_punpckhdq_xmm",
+#endif
+ "helper_punpcklqdq_xmm",
+ "helper_punpckhqdq_xmm",
+
+ "helper_enter_mmx",
+ "helper_psrlw_mmx",
+ "helper_psraw_mmx",
+ "helper_psllw_mmx",
+ "helper_psrld_mmx",
+ "helper_psrad_mmx",
+ "helper_pslld_mmx",
+ "helper_psrlq_mmx",
+ "helper_psllq_mmx",
+ "helper_psrldq_mmx",
+ "helper_pslldq_mmx",
+ "helper_paddb_mmx",
+ "helper_paddw_mmx",
+ "helper_paddl_mmx",
+ "helper_paddq_mmx",
+ "helper_psubb_mmx",
+ "helper_psubw_mmx",
+ "helper_psubl_mmx",
+ "helper_psubq_mmx",
+ "helper_paddusb_mmx",
+ "helper_paddsb_mmx",
+ "helper_psubusb_mmx",
+ "helper_psubsb_mmx",
+ "helper_paddusw_mmx",
+ "helper_paddsw_mmx",
+ "helper_psubusw_mmx",
+ "helper_psubsw_mmx",
+ "helper_pminub_mmx",
+ "helper_pmaxub_mmx",
+ "helper_pminsw_mmx",
+ "helper_pmaxsw_mmx",
+ "helper_pand_mmx",
+ "helper_pandn_mmx",
+ "helper_por_mmx",
+ "helper_pxor_mmx",
+ "helper_pcmpgtb_mmx",
+ "helper_pcmpgtw_mmx",
+ "helper_pcmpgtl_mmx",
+ "helper_pcmpeqb_mmx",
+ "helper_pcmpeqw_mmx",
+ "helper_pcmpeql_mmx",
+ "helper_pmullw_mmx",
+ "helper_pmulhuw_mmx",
+ "helper_pmulhw_mmx",
+ "helper_pavgb_mmx",
+ "helper_pavgw_mmx",
+ "helper_pmuludq_mmx",
+ "helper_pmaddwd_mmx",
+ "helper_psadbw_mmx",
+ "helper_maskmov_mmx",
+ "helper_movl_mm_T0_mmx",
+ "helper_shufps_mmx",
+ "helper_shufpd_mmx",
+#if !defined(TCG_TARGET_ARM)
+ "helper_pshufd_mmx",
+ "helper_pshuflw_mmx",
+ "helper_pshufhw_mmx",
+ "helper_punpcklbw_mmx",
+ "helper_punpcklwd_mmx",
+ "helper_punpckldq_mmx",
+ "helper_punpckhbw_mmx",
+ "helper_punpckhwd_mmx",
+ "helper_punpckhdq_mmx",
+#endif
+ "helper_punpcklqdq_mmx",
+ "helper_punpckhqdq_mmx",
+
+ "helper_addps",
+ "helper_addss",
+ "helper_addpd",
+ "helper_addsd",
+ "helper_subps",
+ "helper_subss",
+ "helper_subpd",
+ "helper_subsd",
+ "helper_mulps",
+ "helper_mulss",
+ "helper_mulpd",
+ "helper_mulsd",
+ "helper_divps",
+ "helper_divss",
+ "helper_divpd",
+ "helper_divsd",
+ "helper_minps",
+ "helper_minss",
+ "helper_minpd",
+ "helper_minsd",
+ "helper_maxps",
+ "helper_maxss",
+ "helper_maxpd",
+ "helper_maxsd",
+ "helper_sqrtps",
+ "helper_sqrtss",
+ "helper_sqrtpd",
+ "helper_sqrtsd",
+ "helper_shufps",
+ "helper_shufpd",
+
+ "helper_cmpeqps",
+ "helper_cmpeqss",
+ "helper_cmpeqpd",
+ "helper_cmpeqsd",
+ "helper_cmpltps",
+ "helper_cmpltss",
+ "helper_cmpltpd",
+ "helper_cmpltsd",
+ "helper_cmpleps",
+ "helper_cmpless",
+ "helper_cmplepd",
+ "helper_cmplesd",
+ "helper_cmpunordps",
+ "helper_cmpunordss",
+ "helper_cmpunordpd",
+ "helper_cmpunordsd",
+ "helper_cmpneqps",
+ "helper_cmpneqss",
+ "helper_cmpneqpd",
+ "helper_cmpneqsd",
+ "helper_cmpnltps",
+ "helper_cmpnltss",
+ "helper_cmpnltpd",
+ "helper_cmpnltsd",
+ "helper_cmpnleps",
+ "helper_cmpnless",
+ "helper_cmpnlepd",
+ "helper_cmpnlesd",
+ "helper_cmpordps",
+ "helper_cmpordss",
+ "helper_cmpordpd",
+ "helper_cmpordsd",
+
+ "helper_cvtps2pd",
+ "helper_cvtpd2ps",
+ "helper_cvtss2sd",
+ "helper_cvtsd2ss",
+ "helper_cvtdq2ps",
+ "helper_cvtdq2pd",
+ "helper_cvtpi2ps",
+ "helper_cvtpi2pd",
+ "helper_cvtsi2ss",
+ "helper_cvtsi2sd",
+ "helper_cvtps2dq",
+ "helper_cvtpd2dq",
+ "helper_cvtps2pi",
+ "helper_cvtpd2pi",
+ "helper_cvtss2si",
+ "helper_cvtsd2si",
+ "helper_cvttps2dq",
+ "helper_cvttpd2dq",
+ "helper_cvttps2pi",
+ "helper_cvttpd2pi",
+ "helper_cvttss2si",
+ "helper_cvttsd2si",
+
+ "helper_cmpeqps",
+ "helper_cmpeqss",
+ "helper_cmpeqpd",
+ "helper_cmpeqsd",
+ "helper_cmpltps",
+ "helper_cmpltss",
+ "helper_cmpltpd",
+ "helper_cmpltsd",
+ "helper_cmpleps",
+ "helper_cmpless",
+ "helper_cmplepd",
+ "helper_cmplesd",
+ "helper_cmpunordps",
+ "helper_cmpunordss",
+ "helper_cmpunordpd",
+ "helper_cmpunordsd",
+ "helper_cmpneqps",
+ "helper_cmpneqss",
+ "helper_cmpneqpd",
+ "helper_cmpneqsd",
+ "helper_cmpnltps",
+ "helper_cmpnltss",
+ "helper_cmpnltpd",
+ "helper_cmpnltsd",
+ "helper_cmpnleps",
+ "helper_cmpnless",
+ "helper_cmpnlepd",
+ "helper_cmpnlesd",
+ "helper_cmpordps",
+ "helper_cmpordss",
+ "helper_cmpordpd",
+ "helper_cmpordsd",
+
+ "helper_ucomisd",
+ "helper_comisd",
+ "helper_ucomiss",
+ "helper_comiss",
+
+ "helper_packuswb_xmm",
+ "helper_packsswb_xmm",
+ "helper_pmovmskb_xmm",
+ "helper_pshufw_mmx",
+
+#elif defined(TARGET_ARM)
+ "helper_add_cc",
+ "helper_sub_cc",
+ "helper_shl_cc",
+ "helper_shr_cc",
+ "helper_sar_cc",
+ "helper_adc_cc",
+ "helper_sbc_cc",
+ "helper_shl",
+ "helper_shr",
+ "helper_sar",
+ "helper_clz",
+
+ "helper_sadd8",
+ "helper_sadd16",
+ "helper_ssub8",
+ "helper_ssub16",
+ "helper_ssubaddx",
+ "helper_saddsubx",
+ "helper_uadd8",
+ "helper_uadd16",
+ "helper_usub8",
+ "helper_usub16",
+ "helper_usubaddx",
+ "helper_uaddsubx",
+
+ "helper_qadd8",
+ "helper_qadd16",
+ "helper_qsub8",
+ "helper_qsub16",
+ "helper_qsubaddx",
+ "helper_qaddsubx",
+ "helper_uqadd8",
+ "helper_uqadd16",
+ "helper_uqsub8",
+ "helper_uqsub16",
+ "helper_uqsubaddx",
+ "helper_uqaddsubx",
+
+ "helper_set_rmode",
+ "helper_cpsr_write_nzcv",
+ "helper_cpsr_write",
+ "helper_cpsr_read",
+ "helper_vfp_get_fpscr",
+ "helper_vfp_set_fpscr",
+ "helper_vfp_adds",
+ "helper_vfp_addd",
+ "helper_vfp_subs",
+ "helper_vfp_subd",
+ "helper_vfp_muls",
+ "helper_vfp_muld",
+ "helper_vfp_divs",
+ "helper_vfp_divd",
+ "helper_vfp_negs",
+ "helper_vfp_negd",
+ "helper_vfp_abss",
+ "helper_vfp_absd",
+ "helper_vfp_sqrts",
+ "helper_vfp_sqrtd",
+ "helper_vfp_cmps",
+ "helper_vfp_cmpd",
+ "helper_vfp_cmpes",
+ "helper_vfp_cmped",
+
+ "helper_vfp_muladds",
+ "helper_vfp_muladdd",
+
+#if defined(TARGET_AARCH64)
+ "helper_vfp_cmps_a64",
+ "helper_vfp_cmpd_a64",
+ "helper_vfp_cmpes_a64",
+ "helper_vfp_cmped_a64",
+ "helper_vfp_minnums",
+ "helper_vfp_maxnums",
+ "helper_vfp_minnumd",
+ "helper_vfp_maxnumd",
+#endif
+#if !defined(TCG_TARGET_PPC64)
+ "helper_vfp_fcvtds",
+ "helper_vfp_fcvtsd",
+ "helper_vfp_uitos",
+ "helper_vfp_uitod",
+ "helper_vfp_sitos",
+ "helper_vfp_sitod",
+ "helper_vfp_touis",
+ "helper_vfp_touid",
+ "helper_vfp_touizs",
+ "helper_vfp_touizd",
+ "helper_vfp_tosis",
+ "helper_vfp_tosid",
+ "helper_vfp_tosizs",
+ "helper_vfp_tosizd",
+ "helper_vfp_toshs",
+ "helper_vfp_tosls",
+ "helper_vfp_touhs",
+ "helper_vfp_touls",
+ "helper_vfp_toshd",
+ "helper_vfp_tosld",
+ "helper_vfp_touhd",
+ "helper_vfp_tould",
+ "helper_vfp_shtos",
+ "helper_vfp_sltos",
+ "helper_vfp_uhtos",
+ "helper_vfp_ultos",
+ "helper_vfp_shtod",
+ "helper_vfp_sltod",
+ "helper_vfp_uhtod",
+ "helper_vfp_ultod",
+#endif
+
+ /* neon helper */
+ "helper_neon_qadd_u8",
+ "helper_neon_qadd_s8",
+ "helper_neon_qadd_u16",
+ "helper_neon_qadd_s16",
+ "helper_neon_qsub_u8",
+ "helper_neon_qsub_s8",
+ "helper_neon_qsub_u16",
+ "helper_neon_qsub_s16",
+
+ "helper_neon_hadd_s8",
+ "helper_neon_hadd_u8",
+ "helper_neon_hadd_s16",
+ "helper_neon_hadd_u16",
+ "helper_neon_hadd_s32",
+ "helper_neon_hadd_u32",
+ "helper_neon_rhadd_s8",
+ "helper_neon_rhadd_u8",
+ "helper_neon_rhadd_s16",
+ "helper_neon_rhadd_u16",
+ "helper_neon_rhadd_s32",
+ "helper_neon_rhadd_u32",
+ "helper_neon_hsub_s8",
+ "helper_neon_hsub_u8",
+ "helper_neon_hsub_s16",
+ "helper_neon_hsub_u16",
+ "helper_neon_hsub_s32",
+ "helper_neon_hsub_u32",
+
+ "helper_neon_cgt_u8",
+ "helper_neon_cgt_s8",
+ "helper_neon_cgt_u16",
+ "helper_neon_cgt_s16",
+ "helper_neon_cgt_u32",
+ "helper_neon_cgt_s32",
+ "helper_neon_cge_u8",
+ "helper_neon_cge_s8",
+ "helper_neon_cge_u16",
+ "helper_neon_cge_s16",
+ "helper_neon_cge_u32",
+ "helper_neon_cge_s32",
+
+ "helper_neon_min_u8",
+ "helper_neon_min_s8",
+ "helper_neon_min_u16",
+ "helper_neon_min_s16",
+ "helper_neon_min_u32",
+ "helper_neon_min_s32",
+ "helper_neon_max_u8",
+ "helper_neon_max_s8",
+ "helper_neon_max_u16",
+ "helper_neon_max_s16",
+ "helper_neon_max_u32",
+ "helper_neon_max_s32",
+ "helper_neon_pmin_u8",
+ "helper_neon_pmin_s8",
+ "helper_neon_pmin_u16",
+ "helper_neon_pmin_s16",
+ "helper_neon_pmax_u8",
+ "helper_neon_pmax_s8",
+ "helper_neon_pmax_u16",
+ "helper_neon_pmax_s16",
+
+ "helper_neon_abd_u8",
+ "helper_neon_abd_s8",
+ "helper_neon_abd_u16",
+ "helper_neon_abd_s16",
+ "helper_neon_abd_u32",
+ "helper_neon_abd_s32",
+
+ "helper_neon_shl_u8",
+ "helper_neon_shl_s8",
+ "helper_neon_shl_u16",
+ "helper_neon_shl_s16",
+ "helper_neon_shl_u32",
+ "helper_neon_shl_s32",
+ "helper_neon_shl_u64",
+ "helper_neon_shl_s64",
+ "helper_neon_rshl_u8",
+ "helper_neon_rshl_s8",
+ "helper_neon_rshl_u16",
+ "helper_neon_rshl_s16",
+ "helper_neon_rshl_u32",
+ "helper_neon_rshl_s32",
+ "helper_neon_rshl_u64",
+ "helper_neon_rshl_s64",
+ "helper_neon_qshl_u8",
+ "helper_neon_qshl_s8",
+ "helper_neon_qshl_u16",
+ "helper_neon_qshl_s16",
+ "helper_neon_qshl_u32",
+ "helper_neon_qshl_s32",
+ "helper_neon_qshl_u64",
+ "helper_neon_qshl_s64",
+ "helper_neon_qrshl_u8",
+ "helper_neon_qrshl_s8",
+ "helper_neon_qrshl_u16",
+ "helper_neon_qrshl_s16",
+ "helper_neon_qrshl_u32",
+ "helper_neon_qrshl_s32",
+ "helper_neon_qrshl_u64",
+ "helper_neon_qrshl_s64",
+
+ "helper_neon_add_u8",
+ "helper_neon_add_u16",
+ "helper_neon_padd_u8",
+ "helper_neon_padd_u16",
+ "helper_neon_sub_u8",
+ "helper_neon_sub_u16",
+ "helper_neon_mul_u8",
+ "helper_neon_mul_u16",
+ "helper_neon_mul_p8",
+
+ "helper_neon_tst_u8",
+ "helper_neon_tst_u16",
+ "helper_neon_tst_u32",
+ "helper_neon_ceq_u8",
+ "helper_neon_ceq_u16",
+ "helper_neon_ceq_u32",
+
+ "helper_neon_abs_s8",
+ "helper_neon_abs_s16",
+ "helper_neon_clz_u8",
+ "helper_neon_clz_u16",
+ "helper_neon_cls_s8",
+ "helper_neon_cls_s16",
+ "helper_neon_cls_s32",
+ "helper_neon_cnt_u8",
+
+ "helper_neon_qdmulh_s16",
+ "helper_neon_qrdmulh_s16",
+ "helper_neon_qdmulh_s32",
+ "helper_neon_qrdmulh_s32",
+
+ "helper_neon_narrow_u8",
+ "helper_neon_narrow_u16",
+ "helper_neon_narrow_sat_u8",
+ "helper_neon_narrow_sat_s8",
+ "helper_neon_narrow_sat_u16",
+ "helper_neon_narrow_sat_s16",
+ "helper_neon_narrow_sat_u32",
+ "helper_neon_narrow_sat_s32",
+ "helper_neon_narrow_high_u8",
+ "helper_neon_narrow_high_u16",
+ "helper_neon_narrow_round_high_u8",
+ "helper_neon_narrow_round_high_u16",
+ "helper_neon_widen_u8",
+ "helper_neon_widen_s8",
+ "helper_neon_widen_u16",
+ "helper_neon_widen_s16",
+
+ "helper_neon_addl_u16",
+ "helper_neon_addl_u32",
+ "helper_neon_paddl_u16",
+ "helper_neon_paddl_u32",
+ "helper_neon_subl_u16",
+ "helper_neon_subl_u32",
+ "helper_neon_addl_saturate_s32",
+ "helper_neon_addl_saturate_s64",
+ "helper_neon_abdl_u16",
+ "helper_neon_abdl_s16",
+ "helper_neon_abdl_u32",
+ "helper_neon_abdl_s32",
+ "helper_neon_abdl_u64",
+ "helper_neon_abdl_s64",
+ "helper_neon_mull_u8",
+ "helper_neon_mull_s8",
+ "helper_neon_mull_u16",
+ "helper_neon_mull_s16",
+
+ "helper_neon_negl_u16",
+ "helper_neon_negl_u32",
+ "helper_neon_negl_u64",
+
+ "helper_neon_qabs_s8",
+ "helper_neon_qabs_s16",
+ "helper_neon_qabs_s32",
+ "helper_neon_qneg_s8",
+ "helper_neon_qneg_s16",
+ "helper_neon_qneg_s32",
+
+ "helper_neon_min_f32",
+ "helper_neon_max_f32",
+ "helper_neon_abd_f32",
+ "helper_neon_add_f32",
+ "helper_neon_sub_f32",
+ "helper_neon_mul_f32",
+ "helper_neon_ceq_f32",
+ "helper_neon_cge_f32",
+ "helper_neon_cgt_f32",
+ "helper_neon_acge_f32",
+ "helper_neon_acgt_f32",
+
+#elif defined(TARGET_PPC)
+ "helper_popcntb",
+ "helper_cntlzw",
+ "helper_cntlsw32",
+ "helper_cntlzw32",
+
+ "helper_compute_fprf",
+ "helper_store_fpscr",
+ "helper_fpscr_clrbit",
+ "helper_fpscr_setbit",
+ "helper_fcmpo",
+ "helper_fcmpu",
+
+ "helper_fctiw",
+ "helper_fctiwz",
+ "helper_frsp",
+ "helper_frin",
+ "helper_friz",
+ "helper_frip",
+ "helper_frim",
+
+ "helper_fadd",
+ "helper_fsub",
+ "helper_fmul",
+ "helper_fdiv",
+ "helper_fmadd",
+ "helper_fmsub",
+ "helper_fnmadd",
+ "helper_fnmsub",
+ "helper_fabs",
+ "helper_fnabs",
+ "helper_fneg",
+ "helper_fsqrt",
+ "helper_fre",
+ "helper_fres",
+ "helper_frsqrte",
+ "helper_fsel",
+
+#elif defined(TARGET_MICROBLAZE)
+ "helper_addkc",
+ "helper_subkc",
+ "helper_cmp",
+ "helper_cmpu",
+ "helper_divs",
+ "helper_divu",
+#elif defined(TARGET_MIPS)
+ "helper_lwl",
+ "helper_lwr",
+ "helper_swl",
+ "helper_swr",
+#endif
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/include/llvm-macro.h b/src/llvm/include/llvm-macro.h
new file mode 100644
index 0000000..7b0e613
--- /dev/null
+++ b/src/llvm/include/llvm-macro.h
@@ -0,0 +1,88 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_MACRO_H
+#define __LLVM_MACRO_H
+
+#if defined(CONFIG_SOFTMMU)
+#define SaveStates() SaveGlobals(COHERENCE_GLOBAL, LastInst)
+#else
+#define SaveStates()
+#endif
+
+#define CONST8(a) ConstantInt::get(Int8Ty, a)
+#define CONST16(a) ConstantInt::get(Int16Ty, a)
+#define CONST32(a) ConstantInt::get(Int32Ty, a)
+#define CONST64(a) ConstantInt::get(Int64Ty, a)
+#define CONST128(a) ConstantInt::get(Int128Ty, a)
+#define CONSTPtr(a) ConstantInt::get(IntPtrTy, a)
+
+#define FPCONST32(a) ConstantFP::get(FloatTy, a)
+#define FPCONST64(a) ConstantFP::get(DoubleTy, a)
+#define FPCONST80(a) ConstantFP::get(FP80Ty, a)
+#define FPCONST128(a) ConstantFP::get(FP128Ty, a)
+
+#define ICMP(a,b,pred) new ICmpInst(LastInst, pred, a, b, "")
+
+#define AND(a,b) BinaryOperator::Create(Instruction::And, a, b, "", LastInst)
+#define OR(a,b) BinaryOperator::Create(Instruction::Or, a, b, "", LastInst)
+#define XOR(a,b) BinaryOperator::Create(Instruction::Xor, a, b, "", LastInst)
+#define SHL(a,b) BinaryOperator::Create(Instruction::Shl, a, b, "", LastInst)
+#define LSHR(a,b) BinaryOperator::Create(Instruction::LShr, a, b, "", LastInst)
+#define ASHR(a,b) BinaryOperator::Create(Instruction::AShr, a, b, "", LastInst)
+#define ADD(a,b) BinaryOperator::Create(Instruction::Add, a, b, "", LastInst)
+#define SUB(a,b) BinaryOperator::Create(Instruction::Sub, a, b, "", LastInst)
+#define MUL(a,b) BinaryOperator::Create(Instruction::Mul, a, b, "", LastInst)
+#define SDIV(a,b) BinaryOperator::Create(Instruction::SDiv, a, b, "", LastInst)
+#define UDIV(a,b) BinaryOperator::Create(Instruction::UDiv, a, b, "", LastInst)
+#define SREM(a,b) BinaryOperator::Create(Instruction::SRem, a, b, "", LastInst)
+#define UREM(a,b) BinaryOperator::Create(Instruction::URem, a, b, "", LastInst)
+
+#define FADD(a,b) BinaryOperator::Create(Instruction::FAdd, a, b, "", LastInst)
+#define FSUB(a,b) BinaryOperator::Create(Instruction::FSub, a, b, "", LastInst)
+#define FMUL(a,b) BinaryOperator::Create(Instruction::FMul, a, b, "", LastInst)
+#define FDIV(a,b) BinaryOperator::Create(Instruction::FDiv, a, b, "", LastInst)
+
+#define CAST(a,t) new BitCastInst(a, t, "", LastInst)
+#define CASTPTR8(a) CAST(a,Int8PtrTy)
+#define CASTPTR16(a) CAST(a,Int16PtrTy)
+#define CASTPTR32(a) CAST(a,Int32PtrTy)
+#define CASTPTR64(a) CAST(a,Int64PtrTy)
+
+#define ITP(a,t) new IntToPtrInst(a, t, "", LastInst)
+#define ITP8(a) ITP(a,Int8PtrTy)
+#define ITP16(a) ITP(a,Int16PtrTy)
+#define ITP32(a) ITP(a,Int32PtrTy)
+#define ITP64(a) ITP(a,Int64PtrTy)
+
+#define TRUNC(a,t) new TruncInst(a, t, "", LastInst)
+#define TRUNC8(a) TRUNC(a, Int8Ty)
+#define TRUNC16(a) TRUNC(a, Int16Ty)
+#define TRUNC32(a) TRUNC(a, Int32Ty)
+#define TRUNC64(a) TRUNC(a, Int64Ty)
+
+#define ZEXT(a,t) new ZExtInst(a, t, "", LastInst)
+#define ZEXT8(a) ZEXT(a, Int8Ty)
+#define ZEXT16(a) ZEXT(a, Int16Ty)
+#define ZEXT32(a) ZEXT(a, Int32Ty)
+#define ZEXT64(a) ZEXT(a, Int64Ty)
+#define ZEXT128(a) ZEXT(a, Int128Ty)
+#define SEXT(a,t) new SExtInst(a, t, "", LastInst)
+#define SEXT8(a) SEXT(a, Int8Ty)
+#define SEXT16(a) SEXT(a, Int16Ty)
+#define SEXT32(a) SEXT(a, Int32Ty)
+#define SEXT64(a) SEXT(a, Int64Ty)
+#define SEXT128(a) SEXT(a, Int128Ty)
+
+#define BSWAP16(a) CreateBSwap(Int16Ty, a, LastInst)
+#define BSWAP32(a) CreateBSwap(Int32Ty, a, LastInst)
+#define BSWAP64(a) CreateBSwap(Int64Ty, a, LastInst)
+
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/llvm-opc.h b/src/llvm/include/llvm-opc.h
new file mode 100644
index 0000000..9454dac
--- /dev/null
+++ b/src/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
+ */
diff --git a/src/llvm/include/llvm-pass.h b/src/llvm/include/llvm-pass.h
new file mode 100644
index 0000000..75bcf4a
--- /dev/null
+++ b/src/llvm/include/llvm-pass.h
@@ -0,0 +1,205 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_PASS_H
+#define __LLVM_PASS_H
+
+#include <map>
+#include <vector>
+#include "llvm-types.h"
+
+class IRFactory;
+
+
+static inline Value *getPointerOperand(Value *I) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(I))
+ return LI->getPointerOperand();
+ if (StoreInst *SI = dyn_cast<StoreInst>(I))
+ return SI->getPointerOperand();
+ return nullptr;
+}
+
+static inline Value *getValueOperand(Value *I) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(I))
+ return LI;
+ if (StoreInst *SI = dyn_cast<StoreInst>(I))
+ return SI->getValueOperand();
+ return nullptr;
+}
+
+static inline unsigned getAddressSpaceOperand(Value *I) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(I))
+ return LI->getPointerAddressSpace();
+ if (StoreInst *SI = dyn_cast<StoreInst>(I))
+ return SI->getPointerAddressSpace();
+ return -1;
+}
+
+/* A CPU state reference. */
+struct StateRef {
+ StateRef(intptr_t Start, intptr_t End, Instruction *I)
+ : Start(Start), End(End), I(I) {}
+ intptr_t Start;
+ intptr_t End;
+ Instruction *I;
+
+ intptr_t getSize() {
+ return End - Start;
+ }
+ Type *getType() {
+ return getValueOperand(I)->getType();
+ }
+};
+
+/* A group of references to a CPU state. */
+struct StateData {
+ intptr_t Start;
+ intptr_t End;
+ std::vector<StateRef*> Refs;
+
+ void reset(StateRef &Ref) {
+ Start = Ref.Start;
+ End = Ref.End;
+ Refs.clear();
+ Refs.push_back(&Ref);
+ }
+ void insert(StateRef &Ref) {
+ End = std::max(End, Ref.End);
+ Refs.push_back(&Ref);
+ }
+};
+
+typedef std::map<intptr_t, intptr_t> StateRange;
+typedef std::vector<StateData> StateList;
+typedef std::vector<CallInst*> CallList;
+
+/*
+ * The purpose of StateAnalyzer is to analyze loads/stores of CPU states and
+ * group loads/stores of the same CPU state into the same bucket (StateData).
+ */
+class StateAnalyzer {
+ const DataLayout *DL;
+ std::vector<StateRef> StateRefs;
+ CallList Calls;
+ StateList States;
+
+ /* Sort state references by the state offset. */
+ void sortStateRefs() {
+ if (StateRefs.empty())
+ return;
+ std::sort(StateRefs.begin(), StateRefs.end(),
+ [](const StateRef &lhs, const StateRef &rhs) -> bool {
+ return lhs.Start < rhs.Start;
+ });
+ }
+
+public:
+ StateAnalyzer(const DataLayout *DL) : DL(DL) {}
+
+ void clear() {
+ StateRefs.clear();
+ Calls.clear();
+ States.clear();
+ }
+
+ /* Add a CPU state reference. */
+ void addStateRef(Instruction *I, intptr_t Off) {
+ Type *Ty = getValueOperand(I)->getType();
+ intptr_t Start = Off;
+ intptr_t End = Off + DL->getTypeSizeInBits(Ty) / 8;
+ StateRefs.push_back(StateRef(Start, End, I));
+ }
+
+ /* Add a helper function call. */
+ void addCall(CallInst *CI) {
+ Calls.push_back(CI);
+ }
+
+ /* Return non-overlapped ranges of states. */
+ void computeStateRange(StateRange &Reads, StateRange &Writes) {
+ computeState();
+ if (StateRefs.empty())
+ return;
+
+ const uint8_t READ = 0x1;
+ const uint8_t WRITE = 0x2;
+ for (auto &State : States) {
+ uint8_t RW = 0;
+ for (auto &Ref : State.Refs)
+ RW |= isa<LoadInst>(Ref->I) ? READ : WRITE;
+ if (RW & READ)
+ Reads[State.Start] = State.End;
+ if (RW & WRITE)
+ Writes[State.Start] = State.End;
+ }
+ }
+
+ /* Compute referenced states and group instructions. */
+ void computeState() {
+ /* Sort state refs by the offset. */
+ sortStateRefs();
+ if (StateRefs.empty())
+ return;
+
+ StateData State;
+ State.reset(StateRefs.front());
+ for (unsigned i = 1, e = StateRefs.size(); i != e; ++i) {
+ StateRef &Next = StateRefs[i];
+ if (State.End <= Next.Start) {
+ /* The next reference is not overlapped with the previous
+ * reference. A new state is found. */
+ States.push_back(State);
+ /* Reset Curr to the next state. */
+ State.reset(Next);
+ } else {
+ /* Overlap and merge. */
+ State.insert(Next);
+ }
+ }
+ /* The last state. */
+ States.push_back(State);
+ }
+
+ StateList &getStateList() {
+ return States;
+ }
+
+ CallList &getCalls() {
+ return Calls;
+ }
+};
+
+
+namespace llvm {
+/* Passes */
+FunctionPass *createReplaceIntrinsic();
+FunctionPass *createFastMathPass();
+FunctionPass *createProfileExec(IRFactory *IF);
+FunctionPass *createStateMappingPass(IRFactory *IF);
+FunctionPass *createRedundantStateElimination(IRFactory *IF);
+FunctionPass *createCombineGuestMemory(IRFactory *IF);
+FunctionPass *createCombineCasts(IRFactory *IF);
+FunctionPass *createCombineZExtTrunc();
+FunctionPass *createSimplifyPointer(IRFactory *IF);
+
+void initializeReplaceIntrinsicPass(llvm::PassRegistry&);
+void initializeFastMathPassPass(llvm::PassRegistry&);
+void initializeProfileExecPass(llvm::PassRegistry&);
+void initializeStateMappingPassPass(llvm::PassRegistry&);
+void initializeRedundantStateEliminationPass(llvm::PassRegistry&);
+void initializeCombineGuestMemoryPass(llvm::PassRegistry&);
+void initializeCombineCastsPass(llvm::PassRegistry&);
+void initializeCombineZExtTruncPass(llvm::PassRegistry&);
+void initializeSimplifyPointerPass(llvm::PassRegistry&);
+
+/* Analysis */
+void initializeInnerLoopAnalysisWrapperPassPass(llvm::PassRegistry&);
+}
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/llvm-soft-perfmon.h b/src/llvm/include/llvm-soft-perfmon.h
new file mode 100644
index 0000000..c55201e
--- /dev/null
+++ b/src/llvm/include/llvm-soft-perfmon.h
@@ -0,0 +1,74 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_SOFT_PERFMON_H
+#define __LLVM_SOFT_PERFMON_H
+
+#include "utils.h"
+
+#define MAX_SPM_THREADS 256
+
+#define SPM_NONE (uint64_t)0
+#define SPM_BASIC ((uint64_t)1 << 0)
+#define SPM_TRACE ((uint64_t)1 << 1)
+#define SPM_CACHE ((uint64_t)1 << 2)
+#define SPM_PASS ((uint64_t)1 << 3)
+#define SPM_HPM ((uint64_t)1 << 4)
+#define SPM_EXIT ((uint64_t)1 << 5)
+#define SPM_HOTSPOT ((uint64_t)1 << 6)
+#define SPM_ALL SPM_BASIC | SPM_TRACE | SPM_CACHE | SPM_PASS | SPM_HPM | \
+ SPM_EXIT | SPM_HOTSPOT
+#define SPM_NUM 9
+
+
+/*
+ * Software Performance Monitor (SPM)
+ */
+class SoftwarePerfmon {
+public:
+ typedef void (*ExitFuncPtr)(void);
+
+ uint64_t Mode; /* Profile level */
+ uint64_t NumInsns; /* Number of instructions */
+ uint64_t NumBranches; /* Number of branches */
+ uint64_t NumLoads; /* Number of memory loads */
+ uint64_t NumStores; /* Number of memory stores */
+ uint64_t NumTraceExits; /* Count of trace exits */
+ uint64_t SampleTime; /* Process time of the sampling handler. */
+ unsigned CoverSet;
+ std::vector<std::vector<uint64_t> *> SampleListVec;
+
+ SoftwarePerfmon()
+ : Mode(SPM_NONE), NumInsns(0), NumBranches(0), NumLoads(0), NumStores(0),
+ NumTraceExits(0), SampleTime(0), CoverSet(90) {}
+ SoftwarePerfmon(std::string &ProfileLevel) : SoftwarePerfmon() {
+ ParseProfileMode(ProfileLevel);
+ }
+
+ bool isEnabled() {
+ return Mode != SPM_NONE;
+ }
+
+ void registerExitFn(ExitFuncPtr F) {
+ ExitFunc.push_back(F);
+ }
+
+ void printProfile();
+
+private:
+ std::vector<ExitFuncPtr> ExitFunc;
+
+ void ParseProfileMode(std::string &ProfileLevel);
+ void printBlockProfile();
+ void printTraceProfile();
+};
+
+extern SoftwarePerfmon *SP;
+
+#endif /* __LLVM_SOFT_PERFMON_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/llvm-state.h b/src/llvm/include/llvm-state.h
new file mode 100644
index 0000000..e573073
--- /dev/null
+++ b/src/llvm/include/llvm-state.h
@@ -0,0 +1,194 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * This file implements the basic optimization schemes including indirect
+ * branch target cache (IBTC), indirect branch chain (IB chain), and trace
+ * profiling and prediction routines.
+ */
+
+#ifndef __LLVM_STATE_H
+#define __LLVM_STATE_H
+
+#define COPY_STATE(_dst, _src, _e) do { _dst->_e = _src->_e; } while(0)
+
+/*
+ * The following data structure and routine are used to save/restore the states
+ * of CPUArchState. Only the states that could affect decoding the guest binary by
+ * the TCG front-end are saved/restored. Such states are saved when translating
+ * the block at the first time because the states could change later and are
+ * restored to the saved values when the block is decoded again during the
+ * trace formation.
+ */
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+typedef struct i386_env {
+ int singlestep_enabled;
+ uint32_t hflags;
+ target_ulong eflags;
+} cpustate;
+#elif defined(TARGET_ARM)
+typedef struct arm_env {
+ int singlestep_enabled;
+ uint32_t pstate;
+ uint32_t aarch64;
+ struct {
+ uint32_t c15_cpar;
+ uint64_t scr_el3;
+ } cp15;
+ uint32_t uncached_cpsr;
+ uint64_t features;
+} cpustate;
+#elif defined(TARGET_PPC) || defined(TARGET_PPC64)
+typedef struct ppc_env {
+ int singlestep_enabled;
+ target_ulong msr;
+ int mmu_idx;
+ uint32_t flags;
+ uint64_t insns_flags;
+ uint64_t insns_flags2;
+ target_ulong hflags;
+} cpustate;
+#elif defined(TARGET_SH4)
+typedef struct sh4_env {
+ int singlestep_enabled;
+ uint32_t sr; /* status register */
+ uint32_t fpscr; /* floating point status/control register */
+ uint32_t features;
+} cpustate;
+#elif defined(TARGET_M68K)
+typedef struct m68k_env {
+ int singlestep_enabled;
+ uint32_t sr; /* status register */
+ uint32_t fpcr; /* floating point status/control register */
+} cpustate;
+#elif defined(TARGET_MIPS)
+typedef struct mips_env {
+ int singlestep_enabled;
+ target_ulong btarget;
+} cpustate;
+#else
+typedef struct dummy_env {
+ int dummy;
+} cpustate;
+#endif
+
+static inline void tcg_save_state(CPUArchState *env, TranslationBlock *tb)
+{
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct i386_env *s = new struct i386_env;
+ COPY_STATE(s, cpu, singlestep_enabled);
+ COPY_STATE(s, env, hflags);
+ COPY_STATE(s, env, eflags);
+#elif defined(TARGET_ARM)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct arm_env *s = new struct arm_env;
+ COPY_STATE(s, cpu, singlestep_enabled);
+ COPY_STATE(s, env, cp15.c15_cpar);
+ COPY_STATE(s, env, cp15.scr_el3);
+ COPY_STATE(s, env, uncached_cpsr);
+ COPY_STATE(s, env, features);
+ COPY_STATE(s, env, pstate);
+ COPY_STATE(s, env, aarch64);
+#elif defined(TARGET_PPC) || defined(TARGET_PPC64)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct ppc_env *s = new struct ppc_env;
+ COPY_STATE(s, cpu, singlestep_enabled);
+ COPY_STATE(s, env, msr);
+ COPY_STATE(s, env, mmu_idx);
+ COPY_STATE(s, env, flags);
+ COPY_STATE(s, env, insns_flags);
+ COPY_STATE(s, env, insns_flags2);
+ COPY_STATE(s, env, hflags);
+#elif defined(TARGET_SH4)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct sh4_env *s = new struct sh4_env;
+ COPY_STATE(s, cpu, singlestep_enabled);
+ COPY_STATE(s, env, sr);
+ COPY_STATE(s, env, fpscr);
+ COPY_STATE(s, env, features);
+#elif defined(TARGET_M68K)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct m68k_env *s = new struct m68k_env;
+ COPY_STATE(s, cpu, singlestep_enabled);
+ COPY_STATE(s, env, sr);
+ COPY_STATE(s, env, fpcr);
+#elif defined(TARGET_MIPS)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct mips_env *s = new struct mips_env;
+ COPY_STATE(s, cpu, singlestep_enabled);
+ COPY_STATE(s, env, btarget);
+#else
+ void *s = nullptr;
+#endif
+
+ tb->state = (void *)s;
+}
+
+/*
+ * tcg_restore_state()
+ * Reset states to those when the block is first translated.
+ */
+static inline void tcg_copy_state(CPUArchState *env, TranslationBlock *tb)
+{
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct i386_env *i386e = (struct i386_env *)tb->state;
+ COPY_STATE(cpu, i386e, singlestep_enabled);
+ COPY_STATE(env, i386e, hflags);
+ COPY_STATE(env, i386e, eflags);
+#elif defined(TARGET_ARM)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct arm_env *arme = (struct arm_env *)tb->state;
+ COPY_STATE(cpu, arme, singlestep_enabled);
+ COPY_STATE(env, arme, cp15.c15_cpar);
+ COPY_STATE(env, arme, cp15.scr_el3);
+ COPY_STATE(env, arme, uncached_cpsr);
+ COPY_STATE(env, arme, features);
+ COPY_STATE(env, arme, pstate);
+ COPY_STATE(env, arme, aarch64);
+#elif defined(TARGET_PPC) || defined(TARGET_PPC64)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct ppc_env *ppce = (struct ppc_env *)tb->state;
+ COPY_STATE(cpu, ppce, singlestep_enabled);
+ COPY_STATE(env, ppce, msr);
+ COPY_STATE(env, ppce, mmu_idx);
+ COPY_STATE(env, ppce, flags);
+ COPY_STATE(env, ppce, insns_flags);
+ COPY_STATE(env, ppce, insns_flags2);
+ COPY_STATE(env, ppce, hflags);
+#elif defined(TARGET_SH4)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct sh4_env *sh4e = (struct sh4_env *)tb->state;
+ COPY_STATE(cpu, sh4e, singlestep_enabled);
+ COPY_STATE(env, sh4e, sr);
+ COPY_STATE(env, sh4e, fpscr);
+ COPY_STATE(env, sh4e, features);
+#elif defined(TARGET_M68K)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct m68k_env *m68ke = (struct m68k_env *)tb->state;
+ COPY_STATE(cpu, m68ke, singlestep_enabled);
+ COPY_STATE(env, m68ke, sr);
+ COPY_STATE(env, m68ke, fpcr);
+#elif defined(TARGET_MIPS)
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct mips_env *mipse = (struct mips_env *)tb->state;
+ COPY_STATE(cpu, mipse, singlestep_enabled);
+ COPY_STATE(env, mipse, btarget);
+#endif
+}
+
+static inline void delete_state(TranslationBlock *tb)
+{
+ delete (cpustate *)tb->state;
+ tb->state = nullptr;
+}
+
+#undef COPY_STATE
+#endif /* __LLVM_STATE_H */
+
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/include/llvm-target.h b/src/llvm/include/llvm-target.h
new file mode 100644
index 0000000..1784942
--- /dev/null
+++ b/src/llvm/include/llvm-target.h
@@ -0,0 +1,116 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_TARGET_H
+#define __LLVM_TARGET_H
+
+#include "llvm/ExecutionEngine/JITEventListener.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm-types.h"
+#include "llvm-translator.h"
+
+#ifndef __PRI64_PREFIX
+# if __WORDSIZE == 64
+# define __PRI64_PREFIX "l"
+# else
+# define __PRI64_PREFIX "ll"
+# endif
+#endif
+
+#if TARGET_LONG_BITS == 32
+# define PRId "d"
+# define PRIx "x"
+#else
+# define PRId __PRI64_PREFIX "d"
+# define PRIx __PRI64_PREFIX "x"
+#endif
+
+#define PRId64 __PRI64_PREFIX "d"
+#define PRIu64 __PRI64_PREFIX "u"
+
+class code_ostream {
+ char *OutBufStart;
+ char *OutBufCur;
+public:
+ void Skip(unsigned Size) {
+ OutBufCur += Size;
+ }
+
+ code_ostream(uintptr_t Ptr)
+ : OutBufStart((char *)Ptr), OutBufCur((char *)Ptr) {}
+ code_ostream &operator<<(char C) {
+ *OutBufCur = C;
+ OutBufCur++;
+ return *this;
+ }
+ code_ostream &operator<<(unsigned char C) {
+ *(unsigned char *)OutBufCur = C;
+ OutBufCur++;
+ return *this;
+ }
+ code_ostream &operator<<(unsigned int C) {
+ *(unsigned int *)OutBufCur = C;
+ OutBufCur += sizeof(unsigned int);
+ return *this;
+ }
+ code_ostream &operator<<(unsigned long C) {
+ *(unsigned long *)OutBufCur = C;
+ OutBufCur += sizeof(unsigned long);
+ return *this;
+ }
+};
+
+static inline void EmitByte(code_ostream &OS, unsigned char C)
+{
+ OS << (char)C;
+}
+static inline void EmitConstant(code_ostream &OS, uint64_t Val, unsigned Size)
+{
+ for (unsigned i = 0; i != Size; ++i) {
+ EmitByte(OS, Val & 255);
+ Val >>= 8;
+ }
+}
+
+/*
+ * EventListener is used by the JIT to notify clients about significant events
+ * during compilation.
+ */
+class EventListener : public JITEventListener {
+ NotifyInfo &NI;
+
+public:
+ EventListener(NotifyInfo &NI) : NI(NI) {}
+ ~EventListener() {}
+ virtual void NotifyFunctionEmitted(const Function &F, void *Code, size_t Size,
+ const EmittedFunctionDetails &Details);
+#if defined(LLVM_V35)
+ virtual void NotifyObjectEmitted(const ObjectImage &Obj);
+#else
+ virtual void NotifyObjectEmitted(const object::ObjectFile &Obj,
+ const RuntimeDyld::LoadedObjectInfo &L);
+#endif
+};
+
+
+const char *getMMUFName(const void *func);
+bool isMMUFunction(std::string &Name);
+bool isLMTFunction(std::string &Name);
+bool isIllegalHelper(const void *func);
+bool isLibcall(std::string &Name);
+bool isSoftFPcall(std::string &Name);
+void AddDependentSymbols(LLVMTranslator *Translator);
+Value *StripPointer(Value *Ptr);
+Value *StripPointerWithConstantOffset(const DataLayout *DL, Value *Ptr,
+ APInt &Offset, Value *GuestBase);
+Value *getBaseWithConstantOffset(const DataLayout *DL, Value *Ptr, intptr_t &Offset);
+void ProcessErase(IVec &toErase);
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/include/llvm-translator.h b/src/llvm/include/llvm-translator.h
new file mode 100644
index 0000000..d1d92c5
--- /dev/null
+++ b/src/llvm/include/llvm-translator.h
@@ -0,0 +1,270 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_TRANSLATOR_H
+#define __LLVM_TRANSLATOR_H
+
+#include <map>
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Analysis/CodeMetrics.h"
+#include "llvm-types.h"
+#include "llvm-pass.h"
+#include "llvm.h"
+
+
+class OptimizationInfo;
+class EventListener;
+class NotifyInfo;
+class IRFactory;
+class TraceBuilder;
+
+
+/*
+ * BaseRegister is used to describe the `reserved' registers by QEMU TCG.
+ * Ex: R14 for the x86 host or R7 for the ARM host.
+ */
+struct BaseRegister {
+ BaseRegister() : Base(nullptr) {}
+ int RegNo; /* Register number */
+ std::string Name; /* Register name string */
+ Type *Ty; /* Type (struct CPUArchState) */
+ Instruction *Base; /* CallInst to retrieve basereg */
+};
+
+struct GuestBaseRegister {
+ GuestBaseRegister() : Name(""), Base(nullptr) {}
+ std::string Name; /* Register name string */
+ Value *Base; /* CallInst to retrieve basereg */
+};
+
+/*
+ * Information of helper functions defined in llvm-helper.h.
+ */
+struct HelperInfo {
+ HelperInfo()
+ : ConflictSize(0), mayConflictArg(false), hasNestedCall(false) {}
+
+ struct ArgInfo {
+ unsigned ConstantWeight; /* Weight if the argument is a constant */
+ unsigned AllocaWeight; /* Weight if the argument is a alloca */
+ ArgInfo(unsigned CWeight, unsigned AWeight)
+ : ConstantWeight(CWeight), AllocaWeight(AWeight) {}
+ };
+
+ Function *Func; /* Function symbol to be inlined */
+ Function *FuncNoInline; /* Function symbol not to be inlined */
+ std::vector<std::pair<Instruction*, intptr_t> > States;
+ std::vector<CallInst*> NestedCalls;
+ StateRange StateUse;
+ StateRange StateDef;
+ CodeMetrics Metrics; /* Inlining metrics */
+ std::vector<ArgInfo> ArgumentWeights; /* Weight of the function arguments */
+ intptr_t ConflictSize;
+
+ bool mayConflictArg; /* Arguments conflict with state mapping or not */
+ bool hasNestedCall; /* This function has nested function or not */
+
+ void CalculateMetrics(Function *F);
+
+ void insertState(StateRange &Range, bool isWrite) {
+ if (isWrite)
+ StateDef.insert(Range.begin(), Range.end());
+ else
+ StateUse.insert(Range.begin(), Range.end());
+ }
+};
+
+/*
+ * NotifyInfo is used to pass information between LLVMTranslator, IRFactory and
+ * the JIT listener.
+ */
+class NotifyInfo {
+#define MAX_CHAINSLOT 256
+public:
+ struct SlotInfo {
+ size_t Key;
+ uintptr_t Addr;
+ };
+
+ struct PatchInfo {
+ PatchInfo(unsigned ty, unsigned idx, uintptr_t addr)
+ : Type(ty), Idx(idx), Addr(addr) {}
+ unsigned Type;
+ unsigned Idx;
+ uintptr_t Addr;
+ };
+
+ NotifyInfo() : Func(nullptr) {
+ ChainSlot = new SlotInfo[MAX_CHAINSLOT];
+ }
+ ~NotifyInfo() {
+ delete ChainSlot;
+ }
+
+ Function *Func; /* LLVM Function of this translation unit */
+ TCGOp *Op;
+ TranslationBlock *TB;
+ uint16_t NumInsts;
+ RestoreVec Restore;
+ unsigned NumChainSlot;
+ SlotInfo *ChainSlot;
+
+ uint32_t Size; /* Size of the translated host code */
+ uint8_t *Code; /* Start PC of the translated host code */
+ std::vector<PatchInfo> Patches;
+
+ void reset() {
+ Restore.clear();
+ Patches.clear();
+ NumInsts = 0;
+ NumChainSlot = 0;
+ }
+ unsigned setChainSlot(size_t Key) {
+ if (NumChainSlot >= MAX_CHAINSLOT)
+ hqemu_error("run out of chain slot.\n");
+ unsigned Curr = NumChainSlot;
+ ChainSlot[NumChainSlot++].Key = Key;
+ return Curr;
+ }
+ uintptr_t getChainSlotAddr(unsigned Idx) {
+ if (NumChainSlot >= MAX_CHAINSLOT)
+ hqemu_error("invalid chain slot index.\n");
+ return (uintptr_t)&ChainSlot[Idx].Addr;
+ }
+ void addPatch(unsigned Type, unsigned Idx, uintptr_t Addr) {
+ Patches.push_back(PatchInfo(Type, Idx, Addr));
+ }
+ void setOp(TCGOp *op) { Op = op; }
+ void setTB(TranslationBlock *tb) {
+ TB = tb;
+ NumInsts = 0;
+ }
+ uint32_t setRestorePoint() {
+ uint32_t Idx = Restore.size();
+ if (Idx != (uint16_t)Idx)
+ hqemu_error("key value too large.\n");
+ Restore.push_back(std::make_pair(TB->id, NumInsts));
+ return Idx;
+ }
+};
+
+/*
+ * LLVM Translator
+ */
+class LLVMTranslator {
+ unsigned MyID; /* Translator ID */
+ CPUArchState *Env;
+
+ /* 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;
+ PointerType *FloatPtrTy;
+ PointerType *DoublePtrTy;
+
+ LLVMContext Context; /* Translator local context */
+ Module *Mod; /* The LLVM module */
+ const DataLayout *DL; /* Data layout */
+ NotifyInfo NI; /* Info to set/use by the JIT listener */
+
+ std::vector<BaseRegister> BaseReg; /* Reserved base registers */
+ GuestBaseRegister GuestBaseReg; /* Reserved guest base register */
+ FlatType StateType; /* Offset and type of guest registers */
+ TCGHelperMap TCGHelpers;
+ HelperMap Helpers;
+ std::set<std::string> ConstHelpers;
+ SymbolMap Symbols;
+
+ MCDisasm *GuestDisAsm;
+ MCDisasm *HostDisAsm;
+
+ IRFactory *IF; /* TCG-to-LLVM IR converter */
+
+ /* Initialize the LLVM module. */
+ void InitializeModule();
+
+ /* Create the JIT compiler. */
+ void InitializeJIT();
+
+ /* Initialize required LLVM types. */
+ void InitializeType();
+
+ /* Setup guest and host dependent structures. */
+ void InitializeTarget();
+
+ /* Setup special registers. */
+ void DefineSpecialReg(std::map<Type*, Type*> &SpecialReg);
+
+ /* Convert the CPUArchState structure type to a list of primitive types. */
+ void FlattenCPUState(Type *Ty, intptr_t &Off, std::map<Type*, Type*> &SpecialReg);
+
+ /* Initialize helper functions. */
+ void InitializeHelpers();
+
+ /* Analyze and optimize a helper function. */
+ bool OptimizeHelper(HelperInfo &Helper);
+
+ void InitializeDisasm();
+
+ void InitializeConstHelpers();
+
+ void Commit(TraceBuilder &Builder);
+
+ void Abort(TraceBuilder &Builder);
+
+ void dump(CPUArchState *env, TranslationBlock *tb);
+
+ LLVMTranslator(unsigned id, CPUArchState *env);
+
+public:
+ ~LLVMTranslator();
+
+ void GenBlock(CPUArchState *env, OptimizationInfo *Opt);
+ void GenTrace(CPUArchState *env, OptimizationInfo *Opt);
+
+ unsigned getID() { return MyID; }
+ LLVMContext *getContext() { return &Context; }
+ Module *getModule() { return Mod; }
+ NotifyInfo &getNotifyInfo() { return NI; }
+ std::vector<BaseRegister> &getBaseReg() { return BaseReg; }
+ GuestBaseRegister &getGuestBaseReg() { return GuestBaseReg; }
+ TCGHelperMap &getTCGHelpers() { return TCGHelpers; }
+ HelperMap &getHelpers() { return Helpers; }
+ std::set<std::string> &getConstHelpers() { return ConstHelpers; }
+ FlatType &getStateType() { return StateType; }
+ SymbolMap &getSymbols() { return Symbols; }
+ MCDisasm *getHostDisAsm() { return HostDisAsm;}
+
+ void AddSymbol(std::string Name, void *FP) {
+ Symbols[Name] = (uintptr_t)FP;
+ }
+
+ /* Create the LLVMTranslator instrance. */
+ static LLVMTranslator *CreateLLVMTranslator(int id, CPUArchState *env) {
+ return new LLVMTranslator(id, env);
+ }
+
+ /* Show guest assembly code for each compiled TB. */
+ void printAsm(CPUArchState *env, TranslationBlock *tb);
+
+ /* Show TCG micro ops for each compiled TB. */
+ void printOp(CPUArchState *env, TranslationBlock *tb);
+};
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/llvm-types.h b/src/llvm/include/llvm-types.h
new file mode 100644
index 0000000..1b8d09c
--- /dev/null
+++ b/src/llvm/include/llvm-types.h
@@ -0,0 +1,127 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_TYPES_H
+#define __LLVM_TYPES_H
+
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/CallSite.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/GetElementPtrTypeIterator.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/IR/ValueSymbolTable.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Analysis/CFG.h"
+#include "llvm/Analysis/CodeMetrics.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+#if defined(LLVM_V35)
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/ExecutionEngine/ObjectImage.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Support/MemoryObject.h"
+#elif defined(LLVM_V38)
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/Object/SymbolSize.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Support/MemoryObject.h"
+#elif defined(LLVM_V39)
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/Object/SymbolSize.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/MemoryObject.h"
+#else
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/Object/SymbolSize.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#endif
+
+#include <vector>
+#include <set>
+#include <map>
+#include "llvm-macro.h"
+#include "qemu-types.h"
+
+using namespace llvm;
+
+class HelperInfo;
+
+typedef std::vector<TranslationBlock *> TBVec;
+typedef std::vector<std::pair<BlockID, uint16_t> > RestoreVec;
+typedef std::map<uintptr_t, std::string> TCGHelperMap; /* <func_ptr, func_name> */
+typedef std::map<std::string, HelperInfo*> HelperMap;
+typedef std::map<std::string, uintptr_t> SymbolMap;
+typedef std::map<intptr_t, Type *> FlatType; /* <state_off, state_ty> */
+typedef std::vector<Instruction *> IVec;
+typedef std::vector<BasicBlock *> BBVec;
+
+
+static inline const DataLayout *getDataLayout(Module *Mod) {
+#if defined(LLVM_V35)
+ return Mod->getDataLayout();
+#else
+ return &Mod->getDataLayout();
+#endif
+}
+
+static inline AllocaInst *CreateAlloca(Type *Ty, unsigned AddrSpace,
+ const Twine &Name,
+ Instruction *InsertBefore = nullptr) {
+#if defined(LLVM_V35) || defined(LLVM_V38) || defined(LLVM_V39)
+ return new AllocaInst(Ty, Name, InsertBefore);
+#else
+ return new AllocaInst(Ty, AddrSpace, Name, InsertBefore);
+#endif
+}
+
+static inline AllocaInst *CreateAlloca(Type *Ty, unsigned AddrSpace,
+ Value *ArraySize = nullptr,
+ const Twine &Name = "",
+ Instruction *InsertBefore = nullptr) {
+#if defined(LLVM_V35) || defined(LLVM_V38) || defined(LLVM_V39)
+ return new AllocaInst(Ty, ArraySize, Name, InsertBefore);
+#else
+ return new AllocaInst(Ty, AddrSpace, ArraySize, Name, InsertBefore);
+#endif
+}
+
+static inline void InlineFunc(CallInst *CI) {
+#if defined(LLVM_V38) || defined(LLVM_V39)
+ AssumptionCacheTracker ACT;
+ InlineFunctionInfo IFI(nullptr, &ACT);
+#else
+ InlineFunctionInfo IFI;
+#endif
+ InlineFunction(CI, IFI);
+}
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/llvm.h b/src/llvm/include/llvm.h
new file mode 100644
index 0000000..67bff2f
--- /dev/null
+++ b/src/llvm/include/llvm.h
@@ -0,0 +1,278 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __LLVM_H
+#define __LLVM_H
+
+#include <memory>
+#include <vector>
+#include "llvm/ADT/STLExtras.h"
+#include "llvm-types.h"
+#include "llvm-debug.h"
+#include "utils.h"
+
+#if defined(ENABLE_MCJIT)
+#include "llvm/ExecutionEngine/MCJIT.h"
+#include "MCJITMemoryManager.h"
+typedef class DefaultMCJITMemoryManager MemoryManager;
+#else
+#if defined(LLVM_V35)
+#include "JIT.h"
+#include "JITMemoryManager.h"
+#else
+# error "LLVM version >3.5 supports MCJIT only. ENABLE_MCJIT must be enabled."
+#endif
+typedef class DefaultJITMemoryManager MemoryManager;
+#endif
+
+
+extern cl::OptionCategory CategoryHQEMU;
+
+class LLVMTranslator;
+class OptimizationInfo;
+class TranslatedCode;
+
+typedef std::unique_ptr<OptimizationInfo> OptRequest;
+
+
+/*
+ * LLVMEnv is the top level container of whole LLVM translation environment
+ * which manages the LLVM translator(s) and globally shared resources. The
+ * LLVMEnv instance must be initialized before using the underlying transaltion
+ * service and can only be initialized ONCE.
+ */
+class LLVMEnv {
+public:
+ typedef std::vector<TranslatedCode *> TransCodeList;
+ typedef std::map<uintptr_t, TranslatedCode *> TransCodeMap;
+ typedef std::vector<uintptr_t> ChainSlot;
+ typedef std::pair<size_t, uintptr_t> SlotInfo;
+
+private:
+ std::shared_ptr<MemoryManager> MM; /* Trace cache manager */
+ unsigned NumTranslator; /* The amount of LLVM translators */
+ std::vector<LLVMTranslator *> Translator; /* LLVM translators */
+ std::vector<pthread_t> HelperThread; /* LLVM translation threads */
+ std::vector<CPUState *> ThreadEnv;
+
+ TransCodeList TransCode; /* Translated traces. */
+ TransCodeMap SortedCode; /* Sorted traces in code cache address order. */
+ ChainSlot ChainPoint; /* Address of stubs for trace-to-block linking */
+
+ bool UseThreading; /* Whether multithreaded translators are used or not. */
+ unsigned NumFlush;
+
+ LLVMEnv();
+
+ /* Parse the command line options. */
+ void ParseCommandLineOptions();
+
+ /* Test whether HQEMU is running in Intel VTune. */
+ void ProbeIntelVTune();
+
+public:
+ QemuMutex mutex;
+
+ ~LLVMEnv();
+
+ /* Start/stop/restart LLVM translators and worker threads. */
+ void CreateTranslator();
+ void DeleteTranslator();
+ void RestartTranslator();
+ void StartThread();
+ void StopThread();
+
+ /* Get the LLVM translator with index. */
+ LLVMTranslator *getTranslator(unsigned ID) {
+ if (ID >= Translator.size())
+ hqemu_error("invalid translator ID.\n");
+ return Translator[ID];
+ }
+
+ /* Acquire and lock the first LLVM translator. */
+ LLVMTranslator *AcquireSingleTranslator();
+
+ /* Release the first LLVM translator. */
+ void ReleaseSingleTranslator();
+
+ /* Get CPUState of the LLVM translator with index. */
+ CPUState *getThreadEnv(int ID) { return ThreadEnv[ID]; }
+
+ std::vector<pthread_t> &getHelperThread() { return HelperThread; }
+ std::shared_ptr<MemoryManager> getMemoryManager() { return MM; }
+ TransCodeList &getTransCode() { return TransCode; }
+ TransCodeMap &getSortedCode() { return SortedCode; }
+ ChainSlot &getChainPoint() { return ChainPoint; }
+ TraceID insertTransCode(TranslatedCode *TC);
+ SlotInfo getChainSlot();
+
+ bool isThreading() { return UseThreading; }
+ void incNumFlush() { NumFlush++; }
+ unsigned getNumFlush() { return NumFlush; }
+
+ /*
+ * static public members
+ */
+ static bool InitOnce; /* LLVMEnv is initialized or not? */
+ static int TransMode;
+ static uint8_t *TraceCache;
+ static size_t TraceCacheSize;
+ static bool RunWithVTune;
+
+ static void CreateLLVMEnv();
+ static void DeleteLLVMEnv();
+ static int OptimizeBlock(CPUArchState *env, OptRequest Request);
+ static int OptimizeTrace(CPUArchState *env, OptRequest Request);
+ static void setTransMode(int Mode) { TransMode = Mode; }
+ static int isTraceMode() {
+ return (TransMode == TRANS_MODE_HYBRIDS ||
+ TransMode == TRANS_MODE_HYBRIDM);
+ }
+};
+
+class QueueManager {
+ std::vector<Queue *> ActiveQueue;
+ Queue *CurrentQueue;
+
+public:
+ QueueManager();
+ ~QueueManager();
+ void Enqueue(OptimizationInfo *Opt);
+ void *Dequeue();
+ void Flush();
+};
+
+/*
+ * OptimizationInfo is the description to an optimization request. It consists
+ * of the optimization mode and the control-flow-graph of the trace.
+ */
+class OptimizationInfo {
+public:
+ typedef std::set<TranslationBlock *> TraceNode;
+ typedef std::map<TranslationBlock *, TraceNode> TraceEdge;
+
+ ~OptimizationInfo() {
+ if (CFG)
+ GraphNode::DeleteCFG(CFG);
+ }
+
+ void ComposeCFG();
+ GraphNode *getCFG() { return CFG; }
+ bool isTrace() { return !isBlock; }
+
+ static OptRequest CreateRequest(TranslationBlock *tb) {
+ return OptRequest(new OptimizationInfo(tb));
+ }
+ static OptRequest CreateRequest(TBVec &trace, int idx) {
+ return OptRequest(new OptimizationInfo(trace, idx));
+ }
+ static OptRequest CreateRequest(TranslationBlock *head, TraceEdge &edges) {
+ return OptRequest(new OptimizationInfo(head, edges));
+ }
+
+private:
+ TBVec Trace; /* Trace of a list of TBs */
+ int LoopHeadIdx; /* Index to the loopback block */
+ bool isUserTrace; /* Trace of all user-mode blocks */
+ bool isBlock; /* Trace of a single block */
+ GraphNode *CFG; /* CFG of the trace */
+
+ OptimizationInfo(TranslationBlock *tb)
+ : isUserTrace(true), isBlock(true) {
+ Trace.push_back(tb);
+ LoopHeadIdx = -1;
+ CFG = new GraphNode(tb);
+ }
+ OptimizationInfo(TBVec &trace, int idx)
+ : isUserTrace(true), isBlock(false), CFG(nullptr) {
+ if (trace.empty())
+ hqemu_error("trace length cannot be zero.\n");
+ Trace = trace;
+ LoopHeadIdx = idx;
+ }
+ OptimizationInfo(TranslationBlock *HeadTB, TraceEdge &Edges);
+
+ void SearchCycle(TraceNode &SearchNodes, TraceNode &Nodes,
+ TraceEdge &Edges, TBVec &Visited, int Depth);
+ void ExpandTrace(TranslationBlock *HeadTB, TraceEdge &Edges);
+};
+
+class TraceInfo {
+public:
+ TBVec TBs;
+ unsigned NumLoop;
+ unsigned NumExit;
+ unsigned NumIndirectBr;
+ uint64_t **ExecCount;
+ uint64_t TransTime;
+ uint32_t Attribute;
+
+ TraceInfo(NodeVec &Nodes, uint32_t Attr = A_None)
+ : NumLoop(0), NumExit(0), NumIndirectBr(0), ExecCount(nullptr),
+ TransTime(0), Attribute(Attr)
+ {
+ if (Nodes.empty())
+ hqemu_error("number of nodes cannot be zero.\n");
+ for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
+ TBs.push_back(Nodes[i]->getTB());
+ }
+
+ TranslationBlock *getEntryTB() { return TBs[0]; }
+ target_ulong getEntryPC() { return TBs[0]->pc; }
+ unsigned getNumBlock() { return TBs.size(); }
+ void setTransTime(struct timeval *start, struct timeval *end) {
+ struct timeval t;
+ timersub(end, start, &t);
+ TransTime = t.tv_sec * 1e6 + t.tv_usec;
+ }
+ bool hasAttribute(uint32_t Attr) {
+ return Attribute & Attr;
+ }
+};
+
+struct ChainInfo {
+ std::vector<uintptr_t> Chains;
+ std::vector<BlockID> DepTraces;
+
+ void insertChain(uintptr_t addr) {
+ Chains.push_back(addr);
+ }
+ void insertDepTrace(BlockID id) {
+ DepTraces.push_back(id);
+ }
+ static ChainInfo *get(TranslationBlock *tb) {
+ if (!tb->chain)
+ tb->chain = (ChainInfo *)new ChainInfo;
+ return (ChainInfo *)tb->chain;
+ }
+ static void free(TranslationBlock *tb) {
+ delete (ChainInfo *)tb->chain;
+ tb->chain = nullptr;
+ }
+};
+
+class TranslatedCode {
+public:
+ TranslatedCode() : Trace(nullptr), SampleCount(0) {}
+ ~TranslatedCode() {
+ if (Trace)
+ delete Trace;
+ }
+
+ bool Active;
+ uint32_t Size; /* Size of the translated host code */
+ uint8_t *Code; /* Start PC of the translated host code */
+ TranslationBlock *EntryTB; /* The entry block of the region */
+ RestoreVec Restore;
+ TraceInfo *Trace;
+ uint64_t SampleCount;
+};
+
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/optimization.h b/src/llvm/include/optimization.h
new file mode 100644
index 0000000..bdafb3a
--- /dev/null
+++ b/src/llvm/include/optimization.h
@@ -0,0 +1,261 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __OPTIMIZATION_H
+#define __OPTIMIZATION_H
+
+#include <iostream>
+#include <list>
+#include "qemu-types.h"
+
+
+extern "C" TranslationBlock *tbs;
+
+/*
+ * Instruction TLB (iTLB)
+ */
+#define ITLB_CACHE_BITS (10)
+#define ITLB_CACHE_SIZE (1U << ITLB_CACHE_BITS)
+#define ITLB_CACHE_MASK (ITLB_CACHE_SIZE - 1)
+
+class ITLB {
+ struct itlb_t { tb_page_addr_t paddr; };
+ itlb_t Cache[ITLB_CACHE_SIZE];
+
+public:
+ ITLB() { reset(); }
+ ~ITLB() {}
+
+ inline itlb_t &cache(target_ulong vaddr) {
+ return Cache[(vaddr >> TARGET_PAGE_BITS) & ITLB_CACHE_MASK];
+ }
+ void reset() {
+ for (unsigned i = 0; i < ITLB_CACHE_SIZE; ++i)
+ Cache[i].paddr = (tb_page_addr_t)-1;
+ }
+ void flush(target_ulong vaddr) {
+ cache(vaddr).paddr = (tb_page_addr_t)-1;
+ }
+ void insert(target_ulong vaddr, tb_page_addr_t paddr) {
+ cache(vaddr).paddr = paddr;
+ }
+ tb_page_addr_t get(target_ulong vaddr) {
+ return cache(vaddr).paddr;
+ }
+};
+
+
+/*
+ * Indirect Branch Target Cache (IBTC)
+ */
+#define IBTC_CACHE_BITS (16)
+#define IBTC_CACHE_SIZE (1U << IBTC_CACHE_BITS)
+#define IBTC_CACHE_MASK (IBTC_CACHE_SIZE - 1)
+
+class IBTC {
+ typedef std::pair<target_ulong, TranslationBlock *> ibtc_t;
+ ibtc_t Cache[IBTC_CACHE_SIZE];
+ bool NeedUpdate;
+ uint64_t Total; /* Total access count */
+ uint64_t Miss; /* Miss count */
+
+public:
+ IBTC() : NeedUpdate(false), Total(0), Miss(0) { reset(); }
+ ~IBTC() {}
+
+ inline ibtc_t &cache(target_ulong pc) {
+ return Cache[(pc >> 2) & IBTC_CACHE_MASK];
+ }
+ void reset() {
+ for (unsigned i = 0; i < IBTC_CACHE_SIZE; ++i)
+ Cache[i].first = (target_ulong)-1;
+ }
+ void remove(TranslationBlock *tb) {
+ ibtc_t &c = cache(tb->pc);
+ if (c.first == tb->pc)
+ c.first = (target_ulong)-1;
+ }
+ void insert(target_ulong pc, TranslationBlock *tb) {
+ cache(pc) = std::make_pair(pc, tb);
+ }
+ TranslationBlock *get(target_ulong pc) {
+ ibtc_t &c = cache(pc);
+ return (c.first == pc) ? c.second : nullptr;
+ }
+ void setUpdate() { NeedUpdate = true; }
+ void resetUpdate() { NeedUpdate = false; }
+ bool needUpdate() { return NeedUpdate; }
+ inline void incTotal() { Total++; }
+ inline void incMiss() { Miss++; }
+ void dump() {
+ double HitRate = (double)(Total - Miss) * 100 / Total;
+ std::cerr << "\nibtc.miss = " << Miss << "/" << Total <<
+ " (hit rate=" << HitRate << "%)\n";
+ }
+};
+
+/*
+ * Cross-Page Block Linking (CPBL)
+ */
+class CPBL {
+ uint64_t Total; /* Total access count */
+ uint64_t Miss; /* Miss count */
+ uint64_t ValidateTotal; /* Total validation count */
+ uint64_t ValidateMiss; /* Miss validation count */
+public:
+ CPBL() : Total(0), Miss(0), ValidateTotal(0), ValidateMiss(0) {}
+
+ inline void incTotal() { Total++; }
+ inline void incMiss() { Miss++; }
+ inline void incValidateTotal() { ValidateTotal++; }
+ inline void incValidateMiss() { ValidateMiss++; }
+ void dump() {
+ double HitRate = (double)(Total - Miss) * 100 / Total;
+ double HitRate2 = (double)(ValidateTotal - ValidateMiss) * 100 / Total;
+ std::cerr << "cpbl.miss = " << Miss << "/" << Total <<
+ " (hit rate=" << HitRate << "%)\n" <<
+ "validate.miss = " << ValidateMiss << "/" << ValidateTotal <<
+ " (hit rate=" << HitRate2 << "%)\n";
+ }
+};
+
+/*
+ * Large Page Table
+ *
+ * This handling is to track every large page created by the guest system.
+ * Once a `possibly' large page is invalidated, do a search with the tracked
+ * pages to determine if it is really a large page invalidation. If it cannot
+ * be found, this is a false alert and we can fall back to the default-size
+ * page flushing. Otherwise, SoftTLB, IBTC/CPBL optimization, etc. are
+ * partial or full cleanup due to the true large page flushing.
+ */
+#define MAX_NUM_LARGEPAGE (1024)
+
+class LargePageTable {
+ typedef std::pair<target_ulong, target_ulong> PTE;
+ typedef std::list<PTE> PTEList;
+ PTEList Used;
+ PTEList Free;
+ CPUState *CS;
+ uint64_t Total;
+ uint64_t Miss;
+
+public:
+ LargePageTable(CPUState *cpu) : Total(0), Miss(0) {
+ CS = cpu;
+ Used.clear();
+ Free.resize(MAX_NUM_LARGEPAGE);
+ }
+ ~LargePageTable() {}
+
+ enum {
+ SEARCH = 0,
+ FLUSH,
+ };
+
+ void reset() {
+ Free.splice(Free.end(), Used);
+ }
+ void remove(PTEList::iterator I) {
+ Free.splice(Free.begin(), Used, I);
+ }
+ void allocate(PTE pte) {
+ /* If the free list is empty, we need to clear softtlb by calling
+ * tlb_flush() which will then invoke LTP::reset() to clear LPT. */
+ if (Free.empty())
+ tlb_flush(CS, 0);
+ Free.front() = pte;
+ Used.splice(Used.begin(), Free, Free.begin());
+ }
+ void insert(target_ulong addr, target_ulong size) {
+ for (PTEList::iterator I = Used.begin(), E = Used.end(); I != E; ++I) {
+ if (I->first == (addr & I->second)) {
+ Used.splice(Used.begin(), Used, I);
+ return;
+ }
+ }
+ target_ulong mask = ~(size - 1);
+ allocate(PTE(addr & mask, mask));
+ }
+ bool search(target_ulong addr, bool mode, target_ulong *addrp,
+ target_ulong *sizep) {
+ for (PTEList::iterator I = Used.begin(), E = Used.end(); I != E; ++I) {
+ if (I->first != (addr & I->second))
+ continue;
+ *addrp = I->first;
+ *sizep = ~I->second + 1;
+ if (mode == FLUSH)
+ remove(I);
+ return true;
+ }
+ return false;
+ }
+ void incTotal() { Total++; }
+ void incMiss() { Miss++; }
+ void dump() {
+ double Rate = (double)(Total - Miss) * 100 / Total;
+ std::cerr << "lpt.miss = " << Miss << "/" << Total <<
+ " (false flushing=" << Rate << "% #pages=" <<
+ Used.size() << ")\n";
+ }
+};
+
+
+class BaseTracer;
+
+struct CPUOptimization {
+ CPUOptimization(CPUState *cpu, BaseTracer *tracer)
+ : lpt(LargePageTable(cpu)), pt(tracer) {}
+
+ ITLB itlb; /* instruction TLB */
+ IBTC ibtc; /* indirect branch target cache */
+ CPBL cpbl; /* cross-page block linking */
+ LargePageTable lpt; /* large page handling */
+ BaseTracer *pt; /* processor tracer */
+};
+
+
+static inline int isUserTB(TranslationBlock *tb) {
+ int is_user = 1;
+#if defined(CONFIG_SOFTMMU)
+#if defined(TARGET_ALPHA)
+ is_user = (tb->flags & TB_FLAGS_USER_MODE);
+#elif defined(TARGET_ARM)
+ is_user = ((ARM_TBFLAG_MMUIDX(tb->flags) & 3) == 0);
+#elif defined(TARGET_I386)
+ is_user = ((tb->flags >> HF_CPL_SHIFT) & 3) == 3;
+#elif defined(TARGET_MIPS)
+ is_user = (tb->flags & MIPS_HFLAG_UM);
+#elif defined(TARGET_PPC)
+ is_user = ((tb->flags >> MSR_PR) & 1);
+#else
+#error "unsupported processor type"
+#endif
+#endif
+ return is_user;
+}
+
+static inline ITLB &cpu_get_itlb(CPUArchState *env) {
+ return ((CPUOptimization *)env->opt_link)->itlb;
+}
+static inline IBTC &cpu_get_ibtc(CPUArchState *env) {
+ return ((CPUOptimization *)env->opt_link)->ibtc;
+}
+static inline CPBL &cpu_get_cpbl(CPUArchState *env) {
+ return ((CPUOptimization *)env->opt_link)->cpbl;
+}
+static inline LargePageTable &cpu_get_lpt(CPUArchState *env) {
+ return ((CPUOptimization *)env->opt_link)->lpt;
+}
+static inline BaseTracer *cpu_get_tracer(CPUArchState *env) {
+ return ((CPUOptimization *)env->opt_link)->pt;
+}
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/include/pmu/arm/arm-events.h b/src/llvm/include/pmu/arm/arm-events.h
new file mode 100644
index 0000000..b3bb1d7
--- /dev/null
+++ b/src/llvm/include/pmu/arm/arm-events.h
@@ -0,0 +1,35 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __ARM_EVENTS_H
+#define __ARM_EVENTS_H
+
+#include <vector>
+#include "pmu/pmu.h"
+
+namespace pmu {
+
+class PMUEvent;
+
+#if defined(__arm__)
+#define pmu_mb() ((void(*)(void))0xffff0fa0)()
+#define pmu_rmb() ((void(*)(void))0xffff0fa0)()
+#define pmu_wmb() ((void(*)(void))0xffff0fa0)()
+#elif defined(__aarch64__)
+#define pmu_mb() asm volatile("dmb ish" ::: "memory")
+#define pmu_rmb() asm volatile("dmb ishld" ::: "memory")
+#define pmu_wmb() asm volatile("dmb ishst" ::: "memory")
+#endif
+
+
+int ARMInit(void);
+
+} /* namespace pmu */
+
+#endif /* __ARM_EVENTS_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/pmu/perf_event.h b/src/llvm/include/pmu/perf_event.h
new file mode 100644
index 0000000..81fed4a
--- /dev/null
+++ b/src/llvm/include/pmu/perf_event.h
@@ -0,0 +1,992 @@
+/*
+ * This file is copied from linux-4.11/include/uapi/linux/perf_event.h.
+ *
+ * Performance events:
+ *
+ * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
+ * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
+ *
+ * Data type definitions, declarations, prototypes.
+ *
+ * Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _UAPI_LINUX_PERF_EVENT_H
+#define _UAPI_LINUX_PERF_EVENT_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ * User-space ABI bits:
+ */
+
+/*
+ * attr.type
+ */
+enum perf_type_id {
+ PERF_TYPE_HARDWARE = 0,
+ PERF_TYPE_SOFTWARE = 1,
+ PERF_TYPE_TRACEPOINT = 2,
+ PERF_TYPE_HW_CACHE = 3,
+ PERF_TYPE_RAW = 4,
+ PERF_TYPE_BREAKPOINT = 5,
+
+ PERF_TYPE_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized performance event event_id types, used by the
+ * attr.event_id parameter of the sys_perf_event_open()
+ * syscall:
+ */
+enum perf_hw_id {
+ /*
+ * Common hardware events, generalized by the kernel:
+ */
+ PERF_COUNT_HW_CPU_CYCLES = 0,
+ PERF_COUNT_HW_INSTRUCTIONS = 1,
+ PERF_COUNT_HW_CACHE_REFERENCES = 2,
+ PERF_COUNT_HW_CACHE_MISSES = 3,
+ PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
+ PERF_COUNT_HW_BRANCH_MISSES = 5,
+ PERF_COUNT_HW_BUS_CYCLES = 6,
+ PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
+ PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
+ PERF_COUNT_HW_REF_CPU_CYCLES = 9,
+
+ PERF_COUNT_HW_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized hardware cache events:
+ *
+ * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
+ * { read, write, prefetch } x
+ * { accesses, misses }
+ */
+enum perf_hw_cache_id {
+ PERF_COUNT_HW_CACHE_L1D = 0,
+ PERF_COUNT_HW_CACHE_L1I = 1,
+ PERF_COUNT_HW_CACHE_LL = 2,
+ PERF_COUNT_HW_CACHE_DTLB = 3,
+ PERF_COUNT_HW_CACHE_ITLB = 4,
+ PERF_COUNT_HW_CACHE_BPU = 5,
+ PERF_COUNT_HW_CACHE_NODE = 6,
+
+ PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_id {
+ PERF_COUNT_HW_CACHE_OP_READ = 0,
+ PERF_COUNT_HW_CACHE_OP_WRITE = 1,
+ PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
+
+ PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_result_id {
+ PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
+ PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
+
+ PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
+};
+
+/*
+ * Special "software" events provided by the kernel, even if the hardware
+ * does not support performance events. These events measure various
+ * physical and sw events of the kernel (and allow the profiling of them as
+ * well):
+ */
+enum perf_sw_ids {
+ PERF_COUNT_SW_CPU_CLOCK = 0,
+ PERF_COUNT_SW_TASK_CLOCK = 1,
+ PERF_COUNT_SW_PAGE_FAULTS = 2,
+ PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
+ PERF_COUNT_SW_CPU_MIGRATIONS = 4,
+ PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
+ PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
+ PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
+ PERF_COUNT_SW_EMULATION_FAULTS = 8,
+ PERF_COUNT_SW_DUMMY = 9,
+ PERF_COUNT_SW_BPF_OUTPUT = 10,
+
+ PERF_COUNT_SW_MAX, /* non-ABI */
+};
+
+/*
+ * Bits that can be set in attr.sample_type to request information
+ * in the overflow packets.
+ */
+enum perf_event_sample_format {
+ PERF_SAMPLE_IP = 1U << 0,
+ PERF_SAMPLE_TID = 1U << 1,
+ PERF_SAMPLE_TIME = 1U << 2,
+ PERF_SAMPLE_ADDR = 1U << 3,
+ PERF_SAMPLE_READ = 1U << 4,
+ PERF_SAMPLE_CALLCHAIN = 1U << 5,
+ PERF_SAMPLE_ID = 1U << 6,
+ PERF_SAMPLE_CPU = 1U << 7,
+ PERF_SAMPLE_PERIOD = 1U << 8,
+ PERF_SAMPLE_STREAM_ID = 1U << 9,
+ PERF_SAMPLE_RAW = 1U << 10,
+ PERF_SAMPLE_BRANCH_STACK = 1U << 11,
+ PERF_SAMPLE_REGS_USER = 1U << 12,
+ PERF_SAMPLE_STACK_USER = 1U << 13,
+ PERF_SAMPLE_WEIGHT = 1U << 14,
+ PERF_SAMPLE_DATA_SRC = 1U << 15,
+ PERF_SAMPLE_IDENTIFIER = 1U << 16,
+ PERF_SAMPLE_TRANSACTION = 1U << 17,
+ PERF_SAMPLE_REGS_INTR = 1U << 18,
+
+ PERF_SAMPLE_MAX = 1U << 19, /* non-ABI */
+};
+
+/*
+ * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
+ *
+ * If the user does not pass priv level information via branch_sample_type,
+ * the kernel uses the event's priv level. Branch and event priv levels do
+ * not have to match. Branch priv level is checked for permissions.
+ *
+ * The branch types can be combined, however BRANCH_ANY covers all types
+ * of branches and therefore it supersedes all the other types.
+ */
+enum perf_branch_sample_type_shift {
+ PERF_SAMPLE_BRANCH_USER_SHIFT = 0, /* user branches */
+ PERF_SAMPLE_BRANCH_KERNEL_SHIFT = 1, /* kernel branches */
+ PERF_SAMPLE_BRANCH_HV_SHIFT = 2, /* hypervisor branches */
+
+ PERF_SAMPLE_BRANCH_ANY_SHIFT = 3, /* any branch types */
+ PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT = 4, /* any call branch */
+ PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT = 5, /* any return branch */
+ PERF_SAMPLE_BRANCH_IND_CALL_SHIFT = 6, /* indirect calls */
+ PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT = 7, /* transaction aborts */
+ PERF_SAMPLE_BRANCH_IN_TX_SHIFT = 8, /* in transaction */
+ PERF_SAMPLE_BRANCH_NO_TX_SHIFT = 9, /* not in transaction */
+ PERF_SAMPLE_BRANCH_COND_SHIFT = 10, /* conditional branches */
+
+ PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = 11, /* call/ret stack */
+ PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT = 12, /* indirect jumps */
+ PERF_SAMPLE_BRANCH_CALL_SHIFT = 13, /* direct call */
+
+ PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT = 14, /* no flags */
+ PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT = 15, /* no cycles */
+
+ PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */
+};
+
+enum perf_branch_sample_type {
+ PERF_SAMPLE_BRANCH_USER = 1U << PERF_SAMPLE_BRANCH_USER_SHIFT,
+ PERF_SAMPLE_BRANCH_KERNEL = 1U << PERF_SAMPLE_BRANCH_KERNEL_SHIFT,
+ PERF_SAMPLE_BRANCH_HV = 1U << PERF_SAMPLE_BRANCH_HV_SHIFT,
+
+ PERF_SAMPLE_BRANCH_ANY = 1U << PERF_SAMPLE_BRANCH_ANY_SHIFT,
+ PERF_SAMPLE_BRANCH_ANY_CALL = 1U << PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT,
+ PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT,
+ PERF_SAMPLE_BRANCH_IND_CALL = 1U << PERF_SAMPLE_BRANCH_IND_CALL_SHIFT,
+ PERF_SAMPLE_BRANCH_ABORT_TX = 1U << PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT,
+ PERF_SAMPLE_BRANCH_IN_TX = 1U << PERF_SAMPLE_BRANCH_IN_TX_SHIFT,
+ PERF_SAMPLE_BRANCH_NO_TX = 1U << PERF_SAMPLE_BRANCH_NO_TX_SHIFT,
+ PERF_SAMPLE_BRANCH_COND = 1U << PERF_SAMPLE_BRANCH_COND_SHIFT,
+
+ PERF_SAMPLE_BRANCH_CALL_STACK = 1U << PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT,
+ PERF_SAMPLE_BRANCH_IND_JUMP = 1U << PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT,
+ PERF_SAMPLE_BRANCH_CALL = 1U << PERF_SAMPLE_BRANCH_CALL_SHIFT,
+
+ PERF_SAMPLE_BRANCH_NO_FLAGS = 1U << PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT,
+ PERF_SAMPLE_BRANCH_NO_CYCLES = 1U << PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT,
+
+ PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
+};
+
+#define PERF_SAMPLE_BRANCH_PLM_ALL \
+ (PERF_SAMPLE_BRANCH_USER|\
+ PERF_SAMPLE_BRANCH_KERNEL|\
+ PERF_SAMPLE_BRANCH_HV)
+
+/*
+ * Values to determine ABI of the registers dump.
+ */
+enum perf_sample_regs_abi {
+ PERF_SAMPLE_REGS_ABI_NONE = 0,
+ PERF_SAMPLE_REGS_ABI_32 = 1,
+ PERF_SAMPLE_REGS_ABI_64 = 2,
+};
+
+/*
+ * Values for the memory transaction event qualifier, mostly for
+ * abort events. Multiple bits can be set.
+ */
+enum {
+ PERF_TXN_ELISION = (1 << 0), /* From elision */
+ PERF_TXN_TRANSACTION = (1 << 1), /* From transaction */
+ PERF_TXN_SYNC = (1 << 2), /* Instruction is related */
+ PERF_TXN_ASYNC = (1 << 3), /* Instruction not related */
+ PERF_TXN_RETRY = (1 << 4), /* Retry possible */
+ PERF_TXN_CONFLICT = (1 << 5), /* Conflict abort */
+ PERF_TXN_CAPACITY_WRITE = (1 << 6), /* Capacity write abort */
+ PERF_TXN_CAPACITY_READ = (1 << 7), /* Capacity read abort */
+
+ PERF_TXN_MAX = (1 << 8), /* non-ABI */
+
+ /* bits 32..63 are reserved for the abort code */
+
+ PERF_TXN_ABORT_MASK = (0xffffffffULL << 32),
+ PERF_TXN_ABORT_SHIFT = 32,
+};
+
+/*
+ * The format of the data returned by read() on a perf event fd,
+ * as specified by attr.read_format:
+ *
+ * struct read_format {
+ * { u64 value;
+ * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ * { u64 id; } && PERF_FORMAT_ID
+ * } && !PERF_FORMAT_GROUP
+ *
+ * { u64 nr;
+ * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
+ * { u64 value;
+ * { u64 id; } && PERF_FORMAT_ID
+ * } cntr[nr];
+ * } && PERF_FORMAT_GROUP
+ * };
+ */
+enum perf_event_read_format {
+ PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
+ PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
+ PERF_FORMAT_ID = 1U << 2,
+ PERF_FORMAT_GROUP = 1U << 3,
+
+ PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
+};
+
+#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
+#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
+#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
+#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
+ /* add: sample_stack_user */
+#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */
+#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */
+
+/*
+ * Hardware event_id to monitor via a performance monitoring event:
+ *
+ * @sample_max_stack: Max number of frame pointers in a callchain,
+ * should be < /proc/sys/kernel/perf_event_max_stack
+ */
+struct perf_event_attr {
+
+ /*
+ * Major type: hardware/software/tracepoint/etc.
+ */
+ uint32_t type;
+
+ /*
+ * Size of the attr structure, for fwd/bwd compat.
+ */
+ uint32_t size;
+
+ /*
+ * Type specific configuration information.
+ */
+ uint64_t config;
+
+ union {
+ uint64_t sample_period;
+ uint64_t sample_freq;
+ };
+
+ uint64_t sample_type;
+ uint64_t read_format;
+
+ uint64_t disabled : 1, /* off by default */
+ inherit : 1, /* children inherit it */
+ pinned : 1, /* must always be on PMU */
+ exclusive : 1, /* only group on PMU */
+ exclude_user : 1, /* don't count user */
+ exclude_kernel : 1, /* ditto kernel */
+ exclude_hv : 1, /* ditto hypervisor */
+ exclude_idle : 1, /* don't count when idle */
+ mmap : 1, /* include mmap data */
+ comm : 1, /* include comm data */
+ freq : 1, /* use freq, not period */
+ inherit_stat : 1, /* per task counts */
+ enable_on_exec : 1, /* next exec enables */
+ task : 1, /* trace fork/exit */
+ watermark : 1, /* wakeup_watermark */
+ /*
+ * precise_ip:
+ *
+ * 0 - SAMPLE_IP can have arbitrary skid
+ * 1 - SAMPLE_IP must have constant skid
+ * 2 - SAMPLE_IP requested to have 0 skid
+ * 3 - SAMPLE_IP must have 0 skid
+ *
+ * See also PERF_RECORD_MISC_EXACT_IP
+ */
+ precise_ip : 2, /* skid constraint */
+ mmap_data : 1, /* non-exec mmap data */
+ sample_id_all : 1, /* sample_type all events */
+
+ exclude_host : 1, /* don't count in host */
+ exclude_guest : 1, /* don't count in guest */
+
+ exclude_callchain_kernel : 1, /* exclude kernel callchains */
+ exclude_callchain_user : 1, /* exclude user callchains */
+ mmap2 : 1, /* include mmap with inode data */
+ comm_exec : 1, /* flag comm events that are due to an exec */
+ use_clockid : 1, /* use @clockid for time fields */
+ context_switch : 1, /* context switch data */
+ write_backward : 1, /* Write ring buffer from end to beginning */
+ __reserved_1 : 36;
+
+ union {
+ uint32_t wakeup_events; /* wakeup every n events */
+ uint32_t wakeup_watermark; /* bytes before wakeup */
+ };
+
+ uint32_t bp_type;
+ union {
+ uint64_t bp_addr;
+ uint64_t config1; /* extension of config */
+ };
+ union {
+ uint64_t bp_len;
+ uint64_t config2; /* extension of config1 */
+ };
+ uint64_t branch_sample_type; /* enum perf_branch_sample_type */
+
+ /*
+ * Defines set of user regs to dump on samples.
+ * See asm/perf_regs.h for details.
+ */
+ uint64_t sample_regs_user;
+
+ /*
+ * Defines size of the user stack to dump on samples.
+ */
+ uint32_t sample_stack_user;
+
+ int32_t clockid;
+ /*
+ * Defines set of regs to dump for each sample
+ * state captured on:
+ * - precise = 0: PMU interrupt
+ * - precise > 0: sampled instruction
+ *
+ * See asm/perf_regs.h for details.
+ */
+ uint64_t sample_regs_intr;
+
+ /*
+ * Wakeup watermark for AUX area
+ */
+ uint32_t aux_watermark;
+ uint16_t sample_max_stack;
+ uint16_t __reserved_2; /* align to uint64_t */
+};
+
+#define perf_flags(attr) (*(&(attr)->read_format + 1))
+
+/*
+ * Ioctls that can be done on a perf event fd:
+ */
+#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
+#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
+#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
+#define PERF_EVENT_IOC_RESET _IO ('$', 3)
+#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, uint64_t)
+#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
+#define PERF_EVENT_IOC_ID _IOR('$', 7, uint64_t *)
+#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, uint32_t)
+#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, uint32_t)
+
+enum perf_event_ioc_flags {
+ PERF_IOC_FLAG_GROUP = 1U << 0,
+};
+
+/*
+ * Structure of the page that can be mapped via mmap
+ */
+struct perf_event_mmap_page {
+ uint32_t version; /* version number of this structure */
+ uint32_t compat_version; /* lowest version this is compat with */
+
+ /*
+ * Bits needed to read the hw events in user-space.
+ *
+ * u32 seq, time_mult, time_shift, index, width;
+ * u64 count, enabled, running;
+ * u64 cyc, time_offset;
+ * s64 pmc = 0;
+ *
+ * do {
+ * seq = pc->lock;
+ * barrier()
+ *
+ * enabled = pc->time_enabled;
+ * running = pc->time_running;
+ *
+ * if (pc->cap_usr_time && enabled != running) {
+ * cyc = rdtsc();
+ * time_offset = pc->time_offset;
+ * time_mult = pc->time_mult;
+ * time_shift = pc->time_shift;
+ * }
+ *
+ * index = pc->index;
+ * count = pc->offset;
+ * if (pc->cap_user_rdpmc && index) {
+ * width = pc->pmc_width;
+ * pmc = rdpmc(index - 1);
+ * }
+ *
+ * barrier();
+ * } while (pc->lock != seq);
+ *
+ * NOTE: for obvious reason this only works on self-monitoring
+ * processes.
+ */
+ uint32_t lock; /* seqlock for synchronization */
+ uint32_t index; /* hardware event identifier */
+ int64_t offset; /* add to hardware event value */
+ uint64_t time_enabled; /* time event active */
+ uint64_t time_running; /* time event on cpu */
+ union {
+ uint64_t capabilities;
+ struct {
+ uint64_t cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
+ cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
+
+ cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
+ cap_user_time : 1, /* The time_* fields are used */
+ cap_user_time_zero : 1, /* The time_zero field is used */
+ cap_____res : 59;
+ };
+ };
+
+ /*
+ * If cap_user_rdpmc this field provides the bit-width of the value
+ * read using the rdpmc() or equivalent instruction. This can be used
+ * to sign extend the result like:
+ *
+ * pmc <<= 64 - width;
+ * pmc >>= 64 - width; // signed shift right
+ * count += pmc;
+ */
+ uint16_t pmc_width;
+
+ /*
+ * If cap_usr_time the below fields can be used to compute the time
+ * delta since time_enabled (in ns) using rdtsc or similar.
+ *
+ * u64 quot, rem;
+ * u64 delta;
+ *
+ * quot = (cyc >> time_shift);
+ * rem = cyc & (((u64)1 << time_shift) - 1);
+ * delta = time_offset + quot * time_mult +
+ * ((rem * time_mult) >> time_shift);
+ *
+ * Where time_offset,time_mult,time_shift and cyc are read in the
+ * seqcount loop described above. This delta can then be added to
+ * enabled and possible running (if index), improving the scaling:
+ *
+ * enabled += delta;
+ * if (index)
+ * running += delta;
+ *
+ * quot = count / running;
+ * rem = count % running;
+ * count = quot * enabled + (rem * enabled) / running;
+ */
+ uint16_t time_shift;
+ uint32_t time_mult;
+ uint64_t time_offset;
+ /*
+ * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
+ * from sample timestamps.
+ *
+ * time = timestamp - time_zero;
+ * quot = time / time_mult;
+ * rem = time % time_mult;
+ * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
+ *
+ * And vice versa:
+ *
+ * quot = cyc >> time_shift;
+ * rem = cyc & (((u64)1 << time_shift) - 1);
+ * timestamp = time_zero + quot * time_mult +
+ * ((rem * time_mult) >> time_shift);
+ */
+ uint64_t time_zero;
+ uint32_t size; /* Header size up to __reserved[] fields. */
+
+ /*
+ * Hole for extension of the self monitor capabilities
+ */
+
+ uint8_t __reserved[118*8+4]; /* align to 1k. */
+
+ /*
+ * Control data for the mmap() data buffer.
+ *
+ * User-space reading the @data_head value should issue an smp_rmb(),
+ * after reading this value.
+ *
+ * When the mapping is PROT_WRITE the @data_tail value should be
+ * written by userspace to reflect the last read data, after issueing
+ * an smp_mb() to separate the data read from the ->data_tail store.
+ * In this case the kernel will not over-write unread data.
+ *
+ * See perf_output_put_handle() for the data ordering.
+ *
+ * data_{offset,size} indicate the location and size of the perf record
+ * buffer within the mmapped area.
+ */
+ uint64_t data_head; /* head in the data section */
+ uint64_t data_tail; /* user-space written tail */
+ uint64_t data_offset; /* where the buffer starts */
+ uint64_t data_size; /* data buffer size */
+
+ /*
+ * AUX area is defined by aux_{offset,size} fields that should be set
+ * by the userspace, so that
+ *
+ * aux_offset >= data_offset + data_size
+ *
+ * prior to mmap()ing it. Size of the mmap()ed area should be aux_size.
+ *
+ * Ring buffer pointers aux_{head,tail} have the same semantics as
+ * data_{head,tail} and same ordering rules apply.
+ */
+ uint64_t aux_head;
+ uint64_t aux_tail;
+ uint64_t aux_offset;
+ uint64_t aux_size;
+};
+
+#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
+#define PERF_RECORD_MISC_KERNEL (1 << 0)
+#define PERF_RECORD_MISC_USER (2 << 0)
+#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
+#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
+#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
+
+/*
+ * Indicates that /proc/PID/maps parsing are truncated by time out.
+ */
+#define PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT (1 << 12)
+/*
+ * PERF_RECORD_MISC_MMAP_DATA and PERF_RECORD_MISC_COMM_EXEC are used on
+ * different events so can reuse the same bit position.
+ * Ditto PERF_RECORD_MISC_SWITCH_OUT.
+ */
+#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
+#define PERF_RECORD_MISC_COMM_EXEC (1 << 13)
+#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13)
+/*
+ * Indicates that the content of PERF_SAMPLE_IP points to
+ * the actual instruction that triggered the event. See also
+ * perf_event_attr::precise_ip.
+ */
+#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
+/*
+ * Reserve the last bit to indicate some extended misc field
+ */
+#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
+
+struct perf_event_header {
+ uint32_t type;
+ uint16_t misc;
+ uint16_t size;
+};
+
+enum perf_event_type {
+
+ /*
+ * If perf_event_attr.sample_id_all is set then all event types will
+ * have the sample_type selected fields related to where/when
+ * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
+ * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
+ * just after the perf_event_header and the fields already present for
+ * the existing fields, i.e. at the end of the payload. That way a newer
+ * perf.data file will be supported by older perf tools, with these new
+ * optional fields being ignored.
+ *
+ * struct sample_id {
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 id; } && PERF_SAMPLE_IDENTIFIER
+ * } && perf_event_attr::sample_id_all
+ *
+ * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
+ * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
+ * relative to header.size.
+ */
+
+ /*
+ * The MMAP events record the PROT_EXEC mappings so that we can
+ * correlate userspace IPs to code. They have the following structure:
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP = 1,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 id;
+ * u64 lost;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_LOST = 2,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * char comm[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_COMM = 3,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_EXIT = 4,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 time;
+ * u64 id;
+ * u64 stream_id;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_THROTTLE = 5,
+ PERF_RECORD_UNTHROTTLE = 6,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_FORK = 7,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, tid;
+ *
+ * struct read_format values;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_READ = 8,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * #
+ * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
+ * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
+ * # is fixed relative to header.
+ * #
+ *
+ * { u64 id; } && PERF_SAMPLE_IDENTIFIER
+ * { u64 ip; } && PERF_SAMPLE_IP
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 addr; } && PERF_SAMPLE_ADDR
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 period; } && PERF_SAMPLE_PERIOD
+ *
+ * { struct read_format values; } && PERF_SAMPLE_READ
+ *
+ * { u64 nr,
+ * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
+ *
+ * #
+ * # The RAW record below is opaque data wrt the ABI
+ * #
+ * # That is, the ABI doesn't make any promises wrt to
+ * # the stability of its content, it may vary depending
+ * # on event, hardware, kernel version and phase of
+ * # the moon.
+ * #
+ * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
+ * #
+ *
+ * { u32 size;
+ * char data[size];}&& PERF_SAMPLE_RAW
+ *
+ * { u64 nr;
+ * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+ *
+ * { u64 abi; # enum perf_sample_regs_abi
+ * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
+ *
+ * { u64 size;
+ * char data[size];
+ * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
+ *
+ * { u64 weight; } && PERF_SAMPLE_WEIGHT
+ * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
+ * { u64 transaction; } && PERF_SAMPLE_TRANSACTION
+ * { u64 abi; # enum perf_sample_regs_abi
+ * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
+ * };
+ */
+ PERF_RECORD_SAMPLE = 9,
+
+ /*
+ * The MMAP2 records are an augmented version of MMAP, they add
+ * maj, min, ino numbers to be used to uniquely identify each mapping
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * u32 maj;
+ * u32 min;
+ * u64 ino;
+ * u64 ino_generation;
+ * u32 prot, flags;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP2 = 10,
+
+ /*
+ * Records that new data landed in the AUX buffer part.
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u64 aux_offset;
+ * u64 aux_size;
+ * u64 flags;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_AUX = 11,
+
+ /*
+ * Indicates that instruction trace has started
+ *
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid;
+ * u32 tid;
+ * };
+ */
+ PERF_RECORD_ITRACE_START = 12,
+
+ /*
+ * Records the dropped/lost sample number.
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u64 lost;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_LOST_SAMPLES = 13,
+
+ /*
+ * Records a context switch in or out (flagged by
+ * PERF_RECORD_MISC_SWITCH_OUT). See also
+ * PERF_RECORD_SWITCH_CPU_WIDE.
+ *
+ * struct {
+ * struct perf_event_header header;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_SWITCH = 14,
+
+ /*
+ * CPU-wide version of PERF_RECORD_SWITCH with next_prev_pid and
+ * next_prev_tid that are the next (switching out) or previous
+ * (switching in) pid/tid.
+ *
+ * struct {
+ * struct perf_event_header header;
+ * u32 next_prev_pid;
+ * u32 next_prev_tid;
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_SWITCH_CPU_WIDE = 15,
+
+ PERF_RECORD_MAX, /* non-ABI */
+};
+
+#define PERF_MAX_STACK_DEPTH 127
+#define PERF_MAX_CONTEXTS_PER_STACK 8
+
+enum perf_callchain_context {
+ PERF_CONTEXT_HV = (uint64_t)-32,
+ PERF_CONTEXT_KERNEL = (uint64_t)-128,
+ PERF_CONTEXT_USER = (uint64_t)-512,
+
+ PERF_CONTEXT_GUEST = (uint64_t)-2048,
+ PERF_CONTEXT_GUEST_KERNEL = (uint64_t)-2176,
+ PERF_CONTEXT_GUEST_USER = (uint64_t)-2560,
+
+ PERF_CONTEXT_MAX = (uint64_t)-4095,
+};
+
+/**
+ * PERF_RECORD_AUX::flags bits
+ */
+#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */
+#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */
+
+#define PERF_FLAG_FD_NO_GROUP (1UL << 0)
+#define PERF_FLAG_FD_OUTPUT (1UL << 1)
+#define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
+#define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
+
+union perf_mem_data_src {
+ uint64_t val;
+ struct {
+ uint64_t mem_op:5, /* type of opcode */
+ mem_lvl:14, /* memory hierarchy level */
+ mem_snoop:5, /* snoop mode */
+ mem_lock:2, /* lock instr */
+ mem_dtlb:7, /* tlb access */
+ mem_rsvd:31;
+ };
+};
+
+/* type of opcode (load/store/prefetch,code) */
+#define PERF_MEM_OP_NA 0x01 /* not available */
+#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
+#define PERF_MEM_OP_STORE 0x04 /* store instruction */
+#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
+#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
+#define PERF_MEM_OP_SHIFT 0
+
+/* memory hierarchy (memory level, hit or miss) */
+#define PERF_MEM_LVL_NA 0x01 /* not available */
+#define PERF_MEM_LVL_HIT 0x02 /* hit level */
+#define PERF_MEM_LVL_MISS 0x04 /* miss level */
+#define PERF_MEM_LVL_L1 0x08 /* L1 */
+#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
+#define PERF_MEM_LVL_L2 0x20 /* L2 */
+#define PERF_MEM_LVL_L3 0x40 /* L3 */
+#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
+#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
+#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
+#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
+#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
+#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
+#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
+#define PERF_MEM_LVL_SHIFT 5
+
+/* snoop mode */
+#define PERF_MEM_SNOOP_NA 0x01 /* not available */
+#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
+#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
+#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
+#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
+#define PERF_MEM_SNOOP_SHIFT 19
+
+/* locked instruction */
+#define PERF_MEM_LOCK_NA 0x01 /* not available */
+#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
+#define PERF_MEM_LOCK_SHIFT 24
+
+/* TLB access */
+#define PERF_MEM_TLB_NA 0x01 /* not available */
+#define PERF_MEM_TLB_HIT 0x02 /* hit level */
+#define PERF_MEM_TLB_MISS 0x04 /* miss level */
+#define PERF_MEM_TLB_L1 0x08 /* L1 */
+#define PERF_MEM_TLB_L2 0x10 /* L2 */
+#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
+#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
+#define PERF_MEM_TLB_SHIFT 26
+
+#define PERF_MEM_S(a, s) \
+ (((uint64_t)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
+
+/*
+ * single taken branch record layout:
+ *
+ * from: source instruction (may not always be a branch insn)
+ * to: branch target
+ * mispred: branch target was mispredicted
+ * predicted: branch target was predicted
+ *
+ * support for mispred, predicted is optional. In case it
+ * is not supported mispred = predicted = 0.
+ *
+ * in_tx: running in a hardware transaction
+ * abort: aborting a hardware transaction
+ * cycles: cycles from last branch (or 0 if not supported)
+ */
+struct perf_branch_entry {
+ uint64_t from;
+ uint64_t to;
+ uint64_t mispred:1, /* target mispredicted */
+ predicted:1,/* target predicted */
+ in_tx:1, /* in transaction */
+ abort:1, /* transaction abort */
+ cycles:16, /* cycle count to last branch */
+ reserved:44;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UAPI_LINUX_PERF_EVENT_H */
diff --git a/src/llvm/include/pmu/pmu-events.h b/src/llvm/include/pmu/pmu-events.h
new file mode 100644
index 0000000..2c31ae9
--- /dev/null
+++ b/src/llvm/include/pmu/pmu-events.h
@@ -0,0 +1,131 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __PMU_EVENTS_H
+#define __PMU_EVENTS_H
+
+#include <list>
+#include <vector>
+#include <signal.h>
+#include "pmu-global.h"
+#include "pmu.h"
+
+namespace pmu {
+
+#define PMU_MAX_EVENTS (1024)
+
+class Timer;
+
+/* Mode of the event. */
+enum {
+ MODE_NONE = 0,
+ MODE_COUNTER = ((uint32_t)1U << 1),
+ MODE_SAMPLE = ((uint32_t)1U << 2),
+ MODE_SAMPLE_IP = ((uint32_t)1U << 3),
+ MODE_SAMPLE_READ = ((uint32_t)1U << 4),
+};
+
+/* State of the event. */
+enum {
+ STATE_STOP = 0,
+ STATE_START = ((uint32_t)1U << 1),
+ STATE_GOTO_STOP = ((uint32_t)1U << 2),
+ STATE_GOTO_START = ((uint32_t)1U << 3),
+};
+
+/* Sampling mmap buffer information. */
+struct MMap {
+ void *Base;
+ uint64_t Size;
+ uint64_t Prev;
+};
+
+/* Event. */
+struct PMUEvent {
+ PMUEvent() : Hndl(0), Mode(MODE_NONE), State(STATE_STOP) {}
+
+ Handle Hndl; /* Unique handle value */
+ int Mode; /* Event mode */
+ int State; /* Current event state */
+ std::vector<int> FD; /* Opened fd(s) of this event */
+ MMap Data; /* mmap data info */
+ MMap Aux; /* mmap aux info */
+ uint64_t Watermark; /* The bytes before wakeup */
+ /* Overflow handling function pointer */
+ union {
+ void *OverflowHandler;
+ SampleHandlerTy SampleHandler;
+ };
+ void *Opaque; /* Opaque pointer passed to the overflow handler. */
+
+ int getFD() { return FD[0]; } /* Group leader fd */
+};
+
+/*
+ * Event Manager.
+ */
+class EventManager {
+ typedef std::list<PMUEvent *> EventList;
+
+ PMUEvent Events[PMU_MAX_EVENTS]; /* Pre-allocated events */
+ EventList FreeEvents; /* Free events */
+ EventList SampleEvents; /* Sampling events */
+ Timer *EventTimer; /* Timer for sampling events. */
+ std::vector<PMUEvent *> ChangedEvents;
+
+public:
+ EventManager();
+ ~EventManager();
+
+ /* Return the event of the input handle. */
+ PMUEvent *GetEvent(Handle Hndl);
+
+ /* Add a counting event and return its handle. */
+ Handle AddEvent(int fd);
+
+ /* Add a sampling event and return its handle. */
+ Handle AddSampleEvent(unsigned NumFDs, int *FD, uint64_t DataSize, void *Data,
+ uint32_t Mode, SampleConfig &Config);
+
+ /* Notify that an event is started. */
+ void StartEvent(PMUEvent *Event, bool ShouldLock = true);
+
+ /* Notify that an event is stopped. */
+ void StopEvent(PMUEvent *Event, bool ShouldLock = true);
+
+ /* Notify that an event is deleted. */
+ void DeleteEvent(PMUEvent *Event);
+
+ /* Stop the event manager. */
+ void Pause();
+
+ /* Restart the event manager. */
+ void Resume();
+
+ friend void DefaultHandler(int signum, siginfo_t *info, void *data);
+};
+
+/* Interval timer. */
+class Timer {
+ timer_t T;
+
+public:
+ Timer(int Signum, int TID);
+ ~Timer();
+
+ /* Start a timer that expires just once. */
+ void Start();
+
+ /* Stop a timer.*/
+ void Stop();
+};
+
+} /* namespace pmu */
+
+#endif /* __PMU_EVENTS_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/pmu/pmu-global.h b/src/llvm/include/pmu/pmu-global.h
new file mode 100644
index 0000000..ed059a4
--- /dev/null
+++ b/src/llvm/include/pmu/pmu-global.h
@@ -0,0 +1,52 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __PMU_GLOBAL_H
+#define __PMU_GLOBAL_H
+
+#if defined(__i386__) || defined(__x86_64__)
+#include "pmu/x86/x86-events.h"
+#elif defined(__arm__) || defined(__aarch64__)
+#include "pmu/arm/arm-events.h"
+#elif defined(_ARCH_PPC) || defined(_ARCH_PPC64)
+#include "pmu/ppc/ppc-events.h"
+#endif
+
+#include "pmu/pmu-utils.h"
+#include "pmu/pmu.h"
+
+namespace pmu {
+
+#define PMU_SIGNAL_NUM SIGIO
+#define PMU_SAMPLE_PERIOD 1e6
+#define PMU_SAMPLE_PAGES 4
+
+class EventManager;
+
+/* Pre-defined event identity. */
+struct EventID {
+ int Type; /* Perf major type: hardware/software/etc */
+ int Config; /* Perf type specific configuration information */
+};
+
+/* System-wide configuration. */
+struct GlobalConfig {
+ int PageSize; /* Host page size */
+ int SignalReceiver; /* TID of the signal receiver */
+ uint32_t Timeout; /* Timer period in nanosecond */
+ int PerfVersion; /* Perf version used in this PMU tool */
+ int OSPerfVersion; /* Perf version used in the OS kernel */
+};
+
+extern EventManager *EventMgr;
+extern GlobalConfig SysConfig;
+
+} /* namespace pmu */
+
+#endif /* __PMU_GLOBAL_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/pmu/pmu-utils.h b/src/llvm/include/pmu/pmu-utils.h
new file mode 100644
index 0000000..5e3e014
--- /dev/null
+++ b/src/llvm/include/pmu/pmu-utils.h
@@ -0,0 +1,106 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __PMU_UTILS_H
+#define __PMU_UTILS_H
+
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include "perf_event.h"
+
+#ifndef ACCESS_ONCE
+#define ACCESS_ONCE(x) (*(volatile decltype(x) *)&(x))
+#endif
+
+namespace pmu {
+
+static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid,
+ int cpu, int group_fd,
+ unsigned long flags) {
+ return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
+}
+
+static inline void perf_attr_init(struct perf_event_attr *attr, int type,
+ int config) {
+ memset(attr, 0, sizeof(struct perf_event_attr));
+ attr->type = type;
+ attr->config = config;
+ attr->size = sizeof(struct perf_event_attr);
+ attr->disabled = 1;
+ attr->exclude_kernel = 1;
+ attr->exclude_guest = 1;
+ attr->exclude_hv = 1;
+}
+
+static inline int perf_event_start(int fd) {
+ return ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
+}
+
+static inline int perf_event_stop(int fd) {
+ return ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
+}
+
+static inline int perf_event_reset(int fd) {
+ return ioctl(fd, PERF_EVENT_IOC_RESET, 0);
+}
+
+static inline int perf_event_set_filter(int fd, const char *arg) {
+ return ioctl(fd, PERF_EVENT_IOC_SET_FILTER, (void *)arg);
+}
+
+static inline uint64_t perf_read_data_head(void *header) {
+ struct perf_event_mmap_page *pc = (struct perf_event_mmap_page *)header;
+ uint64_t head = ACCESS_ONCE(pc->data_head);
+ pmu_rmb();
+ return head;
+}
+
+static inline void perf_write_data_tail(void *header, uint64_t val) {
+ struct perf_event_mmap_page *pc = (struct perf_event_mmap_page *)header;
+ pmu_mb();
+ pc->data_tail = val;
+}
+
+static inline uint64_t perf_read_aux_head(void *header) {
+ struct perf_event_mmap_page *pc = (struct perf_event_mmap_page *)header;
+ uint64_t head = ACCESS_ONCE(pc->aux_head);
+ pmu_rmb();
+ return head;
+}
+
+static inline void perf_write_aux_tail(void *header, uint64_t val) {
+ struct perf_event_mmap_page *pc = (struct perf_event_mmap_page *)header;
+ pmu_mb();
+ pc->aux_tail = val;
+}
+
+static inline int isPowerOf2(uint64_t value) {
+ if (!value)
+ return 0;
+ return !(value & (value - 1));
+}
+
+/* Convert system errno to PMU error code. */
+static inline int ErrorCode(int err)
+{
+ switch (err) {
+ case EPERM:
+ case EACCES: return PMU_EPERM;
+ case ENOMEM: return PMU_ENOMEM;
+ default: return PMU_EEVENT;
+ }
+}
+
+} /* namespace pmu */
+
+#endif /* __PMU_UTILS_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/pmu/pmu.h b/src/llvm/include/pmu/pmu.h
new file mode 100644
index 0000000..89a7c98
--- /dev/null
+++ b/src/llvm/include/pmu/pmu.h
@@ -0,0 +1,170 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * Hardware Performance Monitoring Unit (PMU), C++ interfaces.
+ */
+
+#ifndef __PMU_H
+#define __PMU_H
+
+#include <vector>
+#include <memory>
+#include <stdint.h>
+
+namespace pmu {
+
+#define PMU_GROUP_EVENTS (8)
+#define PMU_TIMER_PERIOD (400) /* micro-second */
+#define PMU_INVALID_HNDL ((Handle)-1)
+
+typedef unsigned Handle;
+/* Sampling event overflow handling. */
+typedef std::vector<uint64_t> SampleList;
+typedef std::unique_ptr<SampleList> SampleDataPtr;
+typedef void (*SampleHandlerTy)(Handle Hndl, SampleDataPtr Data, void *Opaque);
+
+/* Error code. */
+enum {
+ PMU_OK = 0, /* No error */
+ PMU_EINVAL = -1, /* Invalid argument */
+ PMU_ENOMEM = -2, /* Insufficient memory */
+ PMU_ENOEVENT = -3, /* Pre-defined event not available */
+ PMU_EEVENT = -4, /* Hardware event error */
+ PMU_EPERM = -5, /* Permission denied */
+ PMU_EINTER = -6, /* Internal error */
+ PMU_EDECODER = -7, /* Instruction trace decoder error */
+};
+
+/* Pre-defined event code. */
+enum {
+ /* Basic events */
+ PMU_CPU_CYCLES = 0,
+ PMU_REF_CPU_CYCLES,
+ PMU_INSTRUCTIONS,
+ PMU_LLC_REFERENCES,
+ PMU_LLC_MISSES,
+ PMU_BRANCH_INSTRUCTIONS,
+ PMU_BRANCH_MISSES,
+ /* Instruction cache events */
+ PMU_ICACHE_HITS,
+ PMU_ICACHE_MISSES,
+ /* Memory instruction events */
+ PMU_MEM_LOADS,
+ PMU_MEM_STORES,
+
+ PMU_EVENT_MAX,
+};
+
+/* PMU initial configuration. */
+struct PMUConfig {
+ /* Input */
+ int SignalReceiver; /* TID of the signal receiver. 0 for auto-select. */
+ uint32_t Timeout; /* Timer period in micro-second. 0 for auto-select. */
+
+ /* Output */
+ int PerfVersion; /* Perf version used in this PMU tool */
+ int OSPerfVersion; /* Perf version used in the OS kernel */
+};
+
+/* Config for sampling with one or multiple event(s).*/
+struct SampleConfig {
+ unsigned NumEvents; /* Number of events in the event group */
+ unsigned EventCode[PMU_GROUP_EVENTS]; /* Event group. The 1st event is the leader. */
+ unsigned NumPages; /* Number of pages as the sample buffer size. (must be 2^n) */
+ uint64_t Period; /* Sampling period of the group leader. */
+ uint64_t Watermark; /* Bytes before wakeup. 0 for every timer period. */
+ SampleHandlerTy SampleHandler; /* User handler routine */
+ void *Opaque; /* An opaque pointer passed to the overflow handler. */
+};
+
+/* Config for sampling with only one event. */
+struct Sample1Config {
+ unsigned EventCode; /* Pre-defined event to trigger counter overflow */
+ unsigned NumPages; /* Number of pages as the sample buffer size. (must be 2^n) */
+ uint64_t Period; /* Sampling period */
+ uint64_t Watermark; /* Bytes before wakeup. 0 for every timer period. */
+ SampleHandlerTy SampleHandler; /* User handler routine */
+ void *Opaque; /* An opaque pointer passed to the overflow handler. */
+};
+
+/*
+ * PMU main tools.
+ */
+class PMU {
+ PMU() = delete;
+ ~PMU() = delete;
+
+public:
+ /* Initialize the PMU module. */
+ static int Init(PMUConfig &Config);
+
+ /* Finalize the PMU module. */
+ static int Finalize(void);
+
+ /* Stop the PMU module. When the PMU module is paused, the user can continue
+ * to use counting events, but the overflow handler will not be invoked. */
+ static int Pause(void);
+
+ /* Restart the PMU module. After the PMU module is resumed, the overflow
+ * handler will be invoked. */
+ static int Resume(void);
+
+ /* Start a counting/sampling/tracing event. */
+ static int Start(Handle Hndl);
+
+ /* Stop a counting/sampling/tracing event. */
+ static int Stop(Handle Hndl);
+
+ /* Reset the hardware counter. */
+ static int Reset(Handle Hndl);
+
+ /* Remove an event. */
+ static int Cleanup(Handle Hndl);
+
+ /* Start/stop a sampling/tracing event without acquiring a lock.
+ * Note that these two function should only be used within the overflow
+ * handler. Since the overflow handling is already in a locked section,
+ * acquiring a lock is not required. */
+ static int StartUnlocked(Handle Hndl);
+ static int StopUnlocked(Handle Hndl);
+
+ /* Open an event using the pre-defined event code. */
+ static int CreateEvent(unsigned EventCode, Handle &Hndl);
+
+ /* Open an event using the raw event number and umask value.
+ * The raw event code is computed as (RawEvent | (Umask << 8)). */
+ static int CreateRawEvent(unsigned RawEvent, unsigned Umask, Handle &Hndl);
+
+ /* Open a sampling event, with the 1st EventCode as the interrupt event.
+ * The sample data will be recorded in a vector of type 'uint64_t'.
+ * The following vector shows the data format of sampling with N events:
+ * { pc, val1, val2, ..., valN, # 1st sample
+ * ...
+ * pc, val1, val2, ..., valN }; # nth sample
+ *
+ * Note that ownwership of the output vector is transferred to the user.
+ * It is the user's responsibility to free the resource of the vector. */
+ static int CreateSampleEvent(SampleConfig &Config, Handle &Hndl);
+
+ /* Generate an IP histogram, using EventCode as the interrupt event.
+ * The IP histogram will be recorded in a vector of type 'uint64_t' with
+ * the format: { pc1, pc2, pc3, ..., pcN }.
+ * Note that ownwership of the output vector is transferred to the user.
+ * It is the user's responsibility to free the resource of the vector. */
+ static int CreateSampleIP(Sample1Config &Config, Handle &Hndl);
+
+ /* Read value from the hardware counter. */
+ static int ReadEvent(Handle Hndl, uint64_t &Value);
+
+ /* Convert error code to string. */
+ static const char *strerror(int ErrCode);
+};
+
+} /* namespace pmu */
+
+#endif /* __PMU_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/pmu/ppc/ppc-events.h b/src/llvm/include/pmu/ppc/ppc-events.h
new file mode 100644
index 0000000..f48e10d
--- /dev/null
+++ b/src/llvm/include/pmu/ppc/ppc-events.h
@@ -0,0 +1,30 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __PPC_EVENTS_H
+#define __PPC_EVENTS_H
+
+#include <vector>
+#include "pmu/pmu.h"
+
+namespace pmu {
+
+class PMUEvent;
+
+#if defined(_ARCH_PPC) || defined(_ARCH_PPC64)
+#define pmu_mb() __asm__ __volatile__ ("sync" : : : "memory")
+#define pmu_rmb() __asm__ __volatile__ ("sync" : : : "memory")
+#define pmu_wmb() __asm__ __volatile__ ("sync" : : : "memory")
+#endif
+
+int PPCInit(void);
+
+} /* namespace pmu */
+
+#endif /* __PPC_EVENTS_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/pmu/x86/x86-events.h b/src/llvm/include/pmu/x86/x86-events.h
new file mode 100644
index 0000000..c6fdb95
--- /dev/null
+++ b/src/llvm/include/pmu/x86/x86-events.h
@@ -0,0 +1,38 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __X86_EVENTS_H
+#define __X86_EVENTS_H
+
+#include <vector>
+#include "pmu/pmu.h"
+
+namespace pmu {
+
+class PMUEvent;
+
+#if defined(__i386__)
+/*
+ * Some non-Intel clones support out of order store. wmb() ceases to be a
+ * nop for these.
+ */
+#define pmu_mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
+#define pmu_rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
+#define pmu_wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
+#elif defined(__x86_64__)
+#define pmu_mb() asm volatile("mfence" ::: "memory")
+#define pmu_rmb() asm volatile("lfence" ::: "memory")
+#define pmu_wmb() asm volatile("sfence" ::: "memory")
+#endif
+
+int X86Init(void);
+
+} /* namespace pmu */
+
+#endif /* __X86_EVENTS_H */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/include/qemu-types.h b/src/llvm/include/qemu-types.h
new file mode 100644
index 0000000..f2430e0
--- /dev/null
+++ b/src/llvm/include/qemu-types.h
@@ -0,0 +1,33 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __QEMU_TYPES_H
+#define __QEMU_TYPES_H
+
+extern "C" {
+#include "cpu.h"
+#include "exec/tb-hash.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
+#include "tcg/tcg.h"
+#include "qemu/atomic.h"
+#include "hqemu.h"
+
+extern uint8_t *tb_ret_addr;
+extern uint8_t *ibtc_ret_addr;
+
+}
+
+#ifdef inline
+#undef inline
+#endif
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/include/tcg-opc-vector.h b/src/llvm/include/tcg-opc-vector.h
new file mode 100644
index 0000000..bc03ea1
--- /dev/null
+++ b/src/llvm/include/tcg-opc-vector.h
@@ -0,0 +1,80 @@
+DEF(vector_start, 0, 0, 0, 0)
+
+DEF(vmov_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vload_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vstore_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vsitofp_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vuitofp_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vfptosi_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vfptoui_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vadd_i8_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vadd_i16_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vadd_i32_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vadd_i64_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vadd_i8_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vadd_i16_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vadd_i32_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vsub_i8_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vsub_i16_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vsub_i32_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vsub_i64_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vsub_i8_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vsub_i16_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vsub_i32_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vadd_f32_128, 0, 0, 0, 0)
+DEF(vadd_f64_128, 0, 0, 0, 0)
+DEF(vadd_f32_64, 0, 0, 0, 0)
+DEF(vpadd_f32_128, 0, 0, 0, 0)
+DEF(vpadd_f64_128, 0, 0, 0, 0)
+DEF(vpadd_f32_64, 0, 0, 0, 0)
+DEF(vsub_f32_128, 0, 0, 0, 0)
+DEF(vsub_f64_128, 0, 0, 0,0)
+DEF(vsub_f32_64, 0, 0, 0, 0)
+DEF(vabd_f32_128, 0, 0, 0 ,0)
+DEF(vabd_f64_128, 0, 0, 0 ,0)
+DEF(vabd_f32_64, 0, 0, 0, 0)
+
+DEF(vfma_f32_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vfma_f64_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vfma_f32_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vfms_f32_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vfms_f64_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vfms_f32_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vmul_f32_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vmul_f64_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vmul_f32_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vmla_f32_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vmla_f64_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vmla_f32_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vmls_f32_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vmls_f64_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vmls_f32_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vdiv_f32_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vdiv_f64_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vdiv_f32_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vand_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vand_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vbic_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vbic_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vorr_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vorr_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vorn_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vorn_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(veor_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(veor_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vbif_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vbif_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vbit_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vbit_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vbsl_128, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+DEF(vbsl_64, 0, 0, 0, TCG_OPF_SIDE_EFFECTS)
+
+DEF(vector_end, 0, 0, 0, 0)
diff --git a/src/llvm/include/tracer.h b/src/llvm/include/tracer.h
new file mode 100644
index 0000000..2813e0e
--- /dev/null
+++ b/src/llvm/include/tracer.h
@@ -0,0 +1,109 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __TRACE_H
+#define __TRACE_H
+
+#include <vector>
+#include <iostream>
+#include "qemu-types.h"
+#include "optimization.h"
+#include "utils.h"
+
+
+/*
+ * Base processor tracer
+ */
+class BaseTracer {
+public:
+ CPUArchState *Env;
+ void *Perf;
+
+ BaseTracer(CPUArchState *env) : Env(env), Perf(nullptr) {}
+ virtual ~BaseTracer() {}
+ virtual void Reset() {}
+ virtual void Record(uintptr_t next_tb, TranslationBlock *tb) {}
+
+ /* Create and return the tracer object based on LLVM_MODE. */
+ static BaseTracer *CreateTracer(CPUArchState *env);
+
+ /* Release the trace resources. */
+ static void DeleteTracer(CPUArchState *env);
+};
+
+
+/*
+ * Trace of a single basic block
+ */
+class SingleBlockTracer : public BaseTracer {
+ TranslationBlock *TB;
+
+public:
+ SingleBlockTracer(CPUArchState *env);
+
+ void Record(uintptr_t next_tb, TranslationBlock *tb) override;
+};
+
+
+/*
+ * Trace with NET trace formation algorithm
+ */
+#define NET_PROFILE_THRESHOLD 50
+#if defined(CONFIG_SOFTMMU)
+# define NET_PREDICT_THRESHOLD 16
+#else
+# define NET_PREDICT_THRESHOLD 64
+#endif
+class NETTracer : public BaseTracer {
+ bool isTraceHead(uintptr_t next_tb, TranslationBlock *tb, bool NewTB);
+
+public:
+ typedef std::vector<TranslationBlock *> TBVec;
+ TBVec TBs;
+
+ NETTracer(CPUArchState *env, int Mode);
+ ~NETTracer();
+
+ void Reset() override;
+ void Record(uintptr_t next_tb, TranslationBlock *tb) override;
+ inline void Profile(TranslationBlock *tb);
+ inline void Predict(TranslationBlock *tb);
+};
+
+/* Return the address of the patch point to the trace code. */
+static inline uintptr_t tb_get_jmp_entry(TranslationBlock *tb) {
+ return (uintptr_t)tb->tc_ptr + tb->patch_jmp;
+}
+/* Return the initial jump target address of the patch point. */
+static inline uintptr_t tb_get_jmp_next(TranslationBlock *tb) {
+ return (uintptr_t)tb->tc_ptr + tb->patch_next;
+}
+static inline SingleBlockTracer &getSingleBlockTracer(CPUArchState *env) {
+ return *static_cast<SingleBlockTracer *>(cpu_get_tracer(env));
+}
+static inline NETTracer &getNETTracer(CPUArchState *env) {
+ return *static_cast<NETTracer *>(cpu_get_tracer(env));
+}
+
+static inline void delete_image(TranslationBlock *tb)
+{
+#if defined(CONFIG_LLVM) && defined(CONFIG_SOFTMMU)
+ delete (char *)tb->image;
+ tb->image = nullptr;
+#endif
+}
+
+static inline bool update_tb_mode(TranslationBlock *tb, int from, int to) {
+ if (tb->mode != from)
+ return false;
+ return Atomic<int>::testandset(&tb->mode, from, to);
+}
+
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/include/utils.h b/src/llvm/include/utils.h
new file mode 100644
index 0000000..90b36d9
--- /dev/null
+++ b/src/llvm/include/utils.h
@@ -0,0 +1,260 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#ifndef __UTILS_H
+#define __UTILS_H
+
+#include <cstdint>
+#include <cstdlib>
+#include <sstream>
+#include <iomanip>
+#include <set>
+#include <map>
+#include <vector>
+#include "qemu-types.h"
+
+
+#ifndef timersub
+# define timersub(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
+
+#if !defined(__i386__) && !defined(__x86_64__)
+#define USE_PTHREAD_MUTEX
+#endif
+
+#if defined(USE_PTHREAD_MUTEX)
+# define hqemu_lock_t pthread_mutex_t
+# define hqemu_lock_init(lock) pthread_mutex_init(lock, nullptr)
+# define hqemu_lock(lock) pthread_mutex_lock(lock)
+# define hqemu_unlock(lock) pthread_mutex_unlock(lock)
+#else
+# define hqemu_lock_t volatile int
+# define hqemu_lock_init(lock) do { *lock = 0; } while(0)
+# define hqemu_lock(lock) \
+ do { \
+ while (!Atomic<int>::testandset(lock,0,1)) { \
+ while(*(lock)) _mm_pause(); \
+ } \
+ } while(0)
+# define hqemu_unlock(lock) \
+ do { \
+ barrier(); \
+ *(lock) = 0; \
+ } while(0)
+#endif /* USE_PTHREAD_MUTEX */
+
+
+/*
+ * Atomic Utilities
+ */
+template<class T>
+class Atomic {
+public:
+ static T inc_return(volatile T *p) {
+ return __sync_fetch_and_add(p, 1) + 1;
+ }
+ static bool testandset(volatile T *p, T _old, T _new) {
+ return __sync_bool_compare_and_swap(p, _old, _new);
+ }
+};
+
+
+/*
+ * Mutex
+ */
+namespace hqemu {
+class Mutex {
+ hqemu_lock_t M;
+public:
+ Mutex() { hqemu_lock_init(&M); }
+ inline void acquire() { hqemu_lock(&M); }
+ inline void release() { hqemu_unlock(&M); }
+};
+
+class MutexGuard {
+ Mutex &M;
+public:
+ MutexGuard(Mutex &M) : M(M) { M.acquire(); }
+ ~MutexGuard() { M.release(); }
+};
+};
+
+
+/*
+ * GraphNode is used to describe the information of one node in a CFG.
+ */
+class GraphNode;
+typedef std::vector<GraphNode *> NodeVec;
+typedef std::set<GraphNode *> NodeSet;
+
+class GraphNode {
+ TranslationBlock *TB;
+ NodeVec Children;
+
+public:
+ GraphNode(TranslationBlock *tb) : TB(tb) {}
+
+ TranslationBlock *getTB() { return TB; }
+ target_ulong getGuestPC() { return TB->pc; }
+ NodeVec &getChildren() { return Children; }
+ void insertChild(GraphNode *Node) {
+ Children.push_back(Node);
+ }
+
+ static void DeleteCFG(GraphNode *Root);
+};
+
+/*
+ * ControlFlowGraph is used to build the whole program control flow graph (CFG).
+ * GlobalCFG uses this structure to maintain a whole program CFG connected by
+ * direct branches.
+ */
+class ControlFlowGraph {
+ hqemu::Mutex lock;
+
+public:
+ typedef std::vector<TranslationBlock *> TBVec;
+ typedef std::map<TranslationBlock*, TBVec> SuccMap;
+ SuccMap SuccCFG;
+
+ ControlFlowGraph() {}
+
+ hqemu::Mutex &getLock() { return lock; }
+ TBVec &getSuccessor(TranslationBlock *tb) {
+ return SuccCFG[tb];
+ }
+
+ void reset() {
+ hqemu::MutexGuard locked(lock);
+ SuccCFG.clear();
+ }
+ void insertLink(TranslationBlock *src, TranslationBlock *dst) {
+ hqemu::MutexGuard locked(lock);
+ SuccCFG[src].push_back(dst);
+ }
+};
+
+
+/*
+ * Queue
+ */
+#if defined(__x86_64__)
+#define LOCK_FREE
+#endif
+
+#ifdef LOCK_FREE
+struct pointer_t {
+ struct node_t *ptr;
+ unsigned long int count;
+};
+
+struct node_t {
+ struct pointer_t next;
+ void *value;
+};
+
+/* Lock-free MS-queue */
+class Queue {
+ struct queue_t {
+ struct pointer_t head;
+ struct pointer_t tail;
+ };
+
+ node_t *new_node(void *value) {
+ node_t *node = new node_t;
+ node->next.ptr = nullptr;
+ node->value = value;
+ return node;
+ }
+ void delete_node(node_t *node) {
+ delete node;
+ }
+
+ queue_t Q;
+
+public:
+ Queue();
+ void enqueue(void *data);
+ void *dequeue();
+};
+#else
+class Queue {
+ struct node_t {
+ struct node_t *next;
+ void *value;
+ node_t(void *v) : next(nullptr), value(v) {}
+ };
+ struct queue_t {
+ struct node_t *head;
+ struct node_t *tail;
+ };
+
+ pthread_mutex_t lock;
+ queue_t Q;
+
+public:
+ Queue();
+ void enqueue(void *data);
+ void *dequeue();
+};
+#endif
+
+
+class UUID {
+ static uint64_t uuid;
+
+public:
+#if defined(__x86_64__)
+ static uint64_t gen() {
+ uint64_t i = 1;
+ asm volatile("lock; xaddq %0, %1"
+ : "+r" (i), "+m" (uuid) :: "memory");
+ return i + 1;
+ }
+#else
+ static uint64_t gen() {
+ static pthread_mutex_t uuid_lock = PTHREAD_MUTEX_INITIALIZER;
+ pthread_mutex_lock(&uuid_lock);
+ uint64_t id = uuid++;
+ pthread_mutex_unlock(&uuid_lock);
+ return id;
+ }
+#endif
+};
+
+/* Return the string of a hexadecimal number. */
+template <class T>
+static inline std::string toHexString(T Num) {
+ std::stringstream ss;
+ ss << "0x" << std::hex << Num;
+ return ss.str();
+}
+
+/* Return the string of a zero extended number. */
+template <class T>
+static inline std::string toZextStr(T Num) {
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(16) << Num;
+ return ss.str();
+}
+
+/* Misc utilities */
+pid_t gettid();
+void patch_jmp(volatile uintptr_t patch_addr, volatile uintptr_t addr);
+void patch_jmp(volatile uintptr_t patch_addr, volatile void *addr);
+
+#endif
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/llvm-annotate.cpp b/src/llvm/llvm-annotate.cpp
new file mode 100644
index 0000000..040c771
--- /dev/null
+++ b/src/llvm/llvm-annotate.cpp
@@ -0,0 +1,136 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "xml/tinyxml2.h"
+#include "optimization.h"
+#include "llvm-debug.h"
+#include "llvm-annotate.h"
+
+
+using namespace tinyxml2;
+static hqemu::Mutex Lock;
+
+#if defined(CONFIG_USER_ONLY)
+extern "C" const char *filename;
+#endif
+
+AnnotationFactory::AnnotationFactory()
+{
+#if defined(CONFIG_USER_ONLY)
+ int ret;
+ MetaFile = std::string(filename).append(".xml");
+ ret = ParseXML(MetaFile.c_str());
+ if (ret != 0)
+ return;
+#endif
+}
+
+AnnotationFactory::~AnnotationFactory()
+{
+ for (auto L : Loops)
+ delete L.second;
+}
+
+static inline const char *getAttrName(XMLElement *Attr)
+{
+ return Attr->Name();
+}
+
+static inline const char *getAttrValue(XMLElement *Attr)
+{
+ return Attr->FirstChild() ? Attr->FirstChild()->ToText()->Value() : "";
+}
+
+static LoopMetadata *ParseXMLLoop(XMLElement *LoopNode)
+{
+ if (LoopNode == nullptr)
+ return nullptr;
+
+ LoopMetadata *LoopMD = new LoopMetadata();
+ XMLElement *Attr = LoopNode->FirstChildElement();
+ while (Attr) {
+ std::string Name = getAttrName(Attr);
+ const char *Val = getAttrValue(Attr);
+ if (strlen(Val) == 0)
+ goto next;
+
+ if (Name == "address")
+ LoopMD->Address = (target_ulong)strtoull(Val, nullptr, 16);
+ else if (Name == "length")
+ LoopMD->Length = (uint32_t)strtoul(Val, nullptr, 10);
+ else if (Name == "vs")
+ LoopMD->VS = (uint32_t)strtoul(Val, nullptr, 10);
+ else if (Name == "vf")
+ LoopMD->VF = (uint32_t)strtoul(Val, nullptr, 10);
+ else if (Name == "distance") {
+ LoopMD->Distance = atoi(Val);
+ if (LoopMD->Distance == 0)
+ LoopMD->Distance = INT_MAX;
+ }
+ else if (Name == "start") LoopMD->Start = atoi(Val);
+ else if (Name == "end") LoopMD->End = atoi(Val);
+ else if (Name == "stride") LoopMD->Stride = atoi(Val);
+next:
+ Attr = Attr->NextSiblingElement();
+ }
+
+ if (LoopMD->Address == (target_ulong)-1) {
+ delete LoopMD;
+ return nullptr;
+ }
+
+ return LoopMD;
+}
+
+int AnnotationFactory::ParseXML(const char *name)
+{
+ XMLDocument Doc;
+ XMLElement *RootNode, *LoopNode;
+
+ if (Doc.LoadFile(name) != 0) {
+ dbg() << DEBUG_ANNOTATE << "Disable annotation support."
+ << " (cannot find " << name << ")\n";
+ return 1;
+ }
+
+ dbg() << DEBUG_ANNOTATE << "Found an annotation file " << name << "\n";
+
+ /* A legal annoation should be embedded within the <hqemu> tag. For example:
+ * <hqemu><loop><addr>...</addr></loop></hqemu> */
+ RootNode = Doc.FirstChildElement("hqemu");
+ if (RootNode == nullptr)
+ return 1;
+
+ LoopNode = RootNode->FirstChildElement("loop");
+ while (LoopNode) {
+ LoopMetadata *LoopMD = ParseXMLLoop(LoopNode);
+ if (LoopMD)
+ Loops[LoopMD->Address] = LoopMD;
+ LoopNode = LoopNode->NextSiblingElement();
+ }
+
+ dbg() << DEBUG_ANNOTATE
+ << "Found " << Loops.size() << " loop annotation(s).\n";
+ return 0;
+}
+
+LoopMetadata *AnnotationFactory::getLoopAnnotation(target_ulong addr)
+{
+ hqemu::MutexGuard locked(Lock);
+
+ if (Loops.find(addr) == Loops.end())
+ return nullptr;
+ return Loops[addr];
+}
+
+bool AnnotationFactory::hasLoopAnnotation(target_ulong addr)
+{
+ hqemu::MutexGuard locked(Lock);
+ return Loops.count(addr) ? true : false;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/llvm-debug.cpp b/src/llvm/llvm-debug.cpp
new file mode 100644
index 0000000..e5d715a
--- /dev/null
+++ b/src/llvm/llvm-debug.cpp
@@ -0,0 +1,229 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrAnalysis.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm-debug.h"
+#include "llvm.h"
+
+
+static const Target *getTarget(std::string TripleName)
+{
+ /* Get the target specific parser. */
+ std::string Error;
+ const Target *TheTarget = TargetRegistry::lookupTarget(
+ TripleName.c_str(), Error);
+ if (!TheTarget)
+ return nullptr;
+
+ return TheTarget;
+}
+
+MCDisasm *MCDisasm::CreateMCDisasm(std::string TripleName, bool isHost)
+{
+ if (TripleName.empty() || TripleName == "UnknownArch")
+ return nullptr;
+
+ const Target *TheTarget = getTarget(TripleName);
+ if (!TheTarget)
+ return nullptr;
+
+ return new MCDisasm(TheTarget, TripleName, isHost);
+}
+
+MCDisasm::MCDisasm(const llvm::Target *TheTarget, std::string TripleName,
+ bool isHost)
+ : HostDisAsm(isHost), NoShowRawInsn(false)
+{
+ const char *triple = TripleName.c_str();
+ Triple TheTriple(Triple::normalize(TripleName));
+
+ switch (TheTriple.getArch()) {
+ case Triple::x86:
+ case Triple::x86_64:
+ NoShowRawInsn = true;
+ break;
+ default:
+ NoShowRawInsn = false;
+ break;
+ }
+
+ const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(TripleName);
+ if (!MRI)
+ hqemu_error("no register info for target %s.\n", triple);
+ const MCAsmInfo *MAI = TheTarget->createMCAsmInfo(*MRI, TripleName);
+ if (!MAI)
+ hqemu_error("no assembly info for target %s\n", triple);
+ const MCSubtargetInfo *STI = TheTarget->createMCSubtargetInfo(TripleName, "", "");
+ if (!STI)
+ hqemu_error("no subtarget info for target %s\n", triple);
+ const MCInstrInfo *MII = TheTarget->createMCInstrInfo();
+ if (!MII)
+ hqemu_error("no instruction info for target %s\n", triple);
+
+ MCContext Ctx(MAI, MRI, nullptr);
+ const MCDisassembler *DisAsm = TheTarget->createMCDisassembler(*STI, Ctx);
+
+ if (!DisAsm)
+ hqemu_error("no disassembler for target %s\n", TripleName.c_str());
+
+ const MCInstrAnalysis *MIA = TheTarget->createMCInstrAnalysis(MII);
+
+ int AsmPrinterVariant = MAI->getAssemblerDialect();
+#if defined(LLVM_V35)
+ MCInstPrinter *IP = TheTarget->createMCInstPrinter(
+ AsmPrinterVariant, *MAI, *MII, *MRI, *STI);
+#else
+ MCInstPrinter *IP = TheTarget->createMCInstPrinter(Triple(TripleName),
+ AsmPrinterVariant, *MAI, *MII, *MRI);
+#endif
+ if (!IP)
+ hqemu_error("no instruction printer for target %s\n", TripleName.c_str());
+
+ IP->setPrintImmHex(true);
+
+ this->DisAsm = DisAsm;
+ this->STI = STI;
+ this->IP = IP;
+ this->MIA = MIA;
+}
+
+MCDisasm::~MCDisasm()
+{
+}
+
+
+void MCDisasm::DumpBytes(ArrayRef<uint8_t> bytes, raw_ostream &OS)
+{
+ if (NoShowRawInsn)
+ return;
+
+ static const char hex_rep[] = "0123456789abcdef";
+ OS << " ";
+ for (auto I = bytes.rbegin(), E = bytes.rend(); I != E; ++I) {
+ char c = *I;
+ OS << hex_rep[(c & 0xF0) >> 4];
+ OS << hex_rep[c & 0xF];
+ OS << ' ';
+ }
+}
+
+#if defined(LLVM_V35)
+class DisasmMemoryObject : public MemoryObject {
+ uint8_t *Bytes;
+ uint64_t Size;
+ uint64_t BasePC;
+public:
+ DisasmMemoryObject(uint8_t *bytes, uint64_t size, uint64_t basePC) :
+ Bytes(bytes), Size(size), BasePC(basePC) {}
+
+ uint64_t getBase() const override { return BasePC; }
+ uint64_t getExtent() const override { return Size; }
+
+ int readByte(uint64_t Addr, uint8_t *Byte) const override {
+ if (Addr - BasePC >= Size)
+ return -1;
+ *Byte = Bytes[Addr - BasePC];
+ return 0;
+ }
+ ArrayRef<uint8_t> slice(size_t N, size_t M) const {
+ return makeArrayRef<uint8_t>(Bytes+N, M);
+ }
+};
+
+void MCDisasm::PrintInAsm(uint64_t Addr, uint64_t Size, uint64_t GuestAddr)
+{
+ uint64_t Len;
+ DisasmMemoryObject MemoryObject((uint8_t *)Addr, Size, Addr);
+
+ for (uint64_t Start = 0; Start < Size; Start += Len) {
+ MCInst Inst;
+ std::string Str;
+ raw_string_ostream OS(Str);
+ if (DisAsm->getInstruction(Inst, Len, MemoryObject,
+ Addr + Start, nulls(), nulls())) {
+ OS << format("0x%08" PRIx64 ":", GuestAddr);
+
+ DumpBytes(MemoryObject.slice(Start, Len), OS);
+ IP->printInst(&Inst, OS, "");
+
+ if (MIA && (MIA->isCall(Inst) || MIA->isUnconditionalBranch(Inst) ||
+ MIA->isConditionalBranch(Inst))) {
+ uint64_t Target;
+ if (MIA->evaluateBranch(Inst, GuestAddr, Len, Target)) {
+ OS << " <" << format("0x%08" PRIx64, Target) << ">";
+ if (HostDisAsm) {
+ if (Target == (uint64_t)tb_ret_addr)
+ OS << " !tb_ret_addr";
+ }
+ }
+ }
+ } else {
+ OS << "\t<internal disassembler error>";
+ if (Len == 0)
+ Len = 1;
+ }
+
+ DM.debug() << OS.str() << "\n";
+ GuestAddr += Len;
+ }
+}
+#else
+void MCDisasm::PrintInAsm(uint64_t Addr, uint64_t Size, uint64_t GuestAddr)
+{
+ uint64_t Len;
+ ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(Addr), Size);
+
+ for (uint64_t Start = 0; Start < Size; Start += Len) {
+ MCInst Inst;
+ std::string Str;
+ raw_string_ostream OS(Str);
+ if (DisAsm->getInstruction(Inst, Len, Bytes.slice(Start),
+ Addr + Start, nulls(), nulls())) {
+ OS << format("0x%08" PRIx64 ":", GuestAddr);
+
+ DumpBytes(Bytes.slice(Start, Len), OS);
+ IP->printInst(&Inst, OS, "", *STI);
+
+ if (MIA && (MIA->isCall(Inst) || MIA->isUnconditionalBranch(Inst) ||
+ MIA->isConditionalBranch(Inst))) {
+ uint64_t Target;
+ if (MIA->evaluateBranch(Inst, GuestAddr, Len, Target)) {
+ OS << " <" << format("0x%08" PRIx64, Target) << ">";
+ if (HostDisAsm) {
+ if (Target == (uint64_t)tb_ret_addr)
+ OS << " !tb_ret_addr";
+ }
+ }
+ }
+ } else {
+ OS << "\t<internal disassembler error>";
+ if (Len == 0)
+ Len = 1;
+ }
+
+ DM.debug() << OS.str() << "\n";
+ GuestAddr += Len;
+ }
+}
+#endif
+
+void MCDisasm::PrintOutAsm(uint64_t Addr, uint64_t Size)
+{
+ auto &OS = DM.debug();
+ OS << "\nOUT: [size=" << Size << "]\n";
+ PrintInAsm(Addr, Size, Addr);
+ OS << "\n";
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/llvm-hard-perfmon.cpp b/src/llvm/llvm-hard-perfmon.cpp
new file mode 100644
index 0000000..051ee02
--- /dev/null
+++ b/src/llvm/llvm-hard-perfmon.cpp
@@ -0,0 +1,289 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include <string.h>
+#include "config-target.h"
+#include "tracer.h"
+#include "llvm.h"
+#include "llvm-soft-perfmon.h"
+#include "llvm-hard-perfmon.h"
+
+using namespace pmu;
+
+
+HardwarePerfmon::HardwarePerfmon() : MonThreadID(-1), MonThreadStop(true)
+{
+}
+
+HardwarePerfmon::~HardwarePerfmon()
+{
+ if (LLVMEnv::RunWithVTune)
+ return;
+
+ PMU::Finalize();
+
+ if (!MonThreadStop)
+ MonThreadStop = true;
+}
+
+/* Set up HPM with the monitor thread id */
+void HardwarePerfmon::Init(int monitor_thread_tid)
+{
+ if (LLVMEnv::RunWithVTune)
+ return;
+
+ MonThreadID = monitor_thread_tid;
+
+#if defined(ENABLE_HPM_THREAD)
+ /* Start HPM thread. */
+ StartMonThread();
+#else
+ /* If we attempt to profile hotspot but do not run the HPM translation mode,
+ * we enable the HPM monitor thread for the hotspot profiling in order to
+ * avoid deadlock. */
+ if (SP->Mode & SPM_HOTSPOT)
+ StartMonThread();
+#endif
+
+ /* Initialize the PMU tools. */
+ PMUConfig Config;
+ memset(&Config, 0, sizeof(PMUConfig));
+ Config.SignalReceiver = MonThreadID;
+ Config.Timeout = 400;
+ int EC = PMU::Init(Config);
+ if (EC != PMU_OK) {
+ dbg() << DEBUG_HPM << "Failed to initialize PMU (" << PMU::strerror(EC)
+ << ").\n";
+ return;
+ }
+}
+
+/* Stop the monitor. */
+void HardwarePerfmon::Pause()
+{
+ if (LLVMEnv::RunWithVTune)
+ return;
+
+ PMU::Pause();
+}
+
+/* Restart the monitor. */
+void HardwarePerfmon::Resume()
+{
+ if (LLVMEnv::RunWithVTune)
+ return;
+
+ PMU::Resume();
+}
+
+/* Start monitor thread. */
+void HardwarePerfmon::StartMonThread()
+{
+ /* Start HPM thread. */
+ MonThreadID = -1;
+ MonThreadStop = false;
+ MonThread = std::thread(
+ [=]() { MonitorFunc(); }
+ );
+
+ MonThread.detach();
+ while (MonThreadID == -1)
+ usleep(200);
+}
+
+/* Monitor thread routine. */
+void HardwarePerfmon::MonitorFunc()
+{
+ MonThreadID = gettid();
+ copy_tcg_context();
+
+ while (!MonThreadStop)
+ usleep(10000);
+}
+
+static void CoverSetHandler(Handle Hndl, std::unique_ptr<SampleList> DataPtr,
+ void *Opaque)
+{
+ /* Just attach the sampled IPs to the profile list. The soft-perfmon will
+ * release the resource later. */
+ SP->SampleListVec.push_back(DataPtr.release());
+}
+
+void HardwarePerfmon::RegisterThread(BaseTracer *Tracer)
+{
+ hqemu::MutexGuard Locked(Lock);
+
+ dbg() << DEBUG_HPM << "Register thread " << gettid() << ".\n";
+
+ if (LLVMEnv::RunWithVTune)
+ return;
+
+ PerfmonData *Perf = new PerfmonData(gettid());
+ Perf->MonitorBasic(HPM_INIT);
+ Perf->MonitorCoverSet(HPM_INIT);
+
+ Tracer->Perf = static_cast<void *>(Perf);
+}
+
+void HardwarePerfmon::UnregisterThread(BaseTracer *Tracer)
+{
+ hqemu::MutexGuard Locked(Lock);
+
+ dbg() << DEBUG_HPM << "Unregister thread " << gettid() << ".\n";
+
+ if (LLVMEnv::RunWithVTune)
+ return;
+ if (!Tracer->Perf)
+ return;
+
+ auto Perf = static_cast<PerfmonData *>(Tracer->Perf);
+ Perf->MonitorBasic(HPM_FINALIZE);
+ Perf->MonitorCoverSet(HPM_FINALIZE);
+
+ delete Perf;
+ Tracer->Perf = nullptr;
+}
+
+void HardwarePerfmon::NotifyCacheEnter(BaseTracer *Tracer)
+{
+ hqemu::MutexGuard Locked(Lock);
+
+ if (!Tracer->Perf)
+ return;
+ auto Perf = static_cast<PerfmonData *>(Tracer->Perf);
+ Perf->MonitorBasic(HPM_START);
+}
+
+void HardwarePerfmon::NotifyCacheLeave(BaseTracer *Tracer)
+{
+ hqemu::MutexGuard Locked(Lock);
+
+ if (!Tracer->Perf)
+ return;
+ auto Perf = static_cast<PerfmonData *>(Tracer->Perf);
+ Perf->MonitorBasic(HPM_STOP);
+}
+
+/*
+ * PerfmonData
+ */
+PerfmonData::PerfmonData(int tid) : TID(tid)
+{
+}
+
+PerfmonData::~PerfmonData()
+{
+}
+
+void PerfmonData::MonitorBasic(HPMControl Ctl)
+{
+ if (!(SP->Mode & SPM_HPM))
+ return;
+
+ switch (Ctl) {
+ case HPM_INIT:
+ if (PMU::CreateEvent(PMU_INSTRUCTIONS, ICountHndl) == PMU_OK) {
+ dbg() << DEBUG_HPM << "Register event: # instructions.\n";
+ PMU::Start(ICountHndl);
+ }
+ if (PMU::CreateEvent(PMU_BRANCH_INSTRUCTIONS, BranchHndl) == PMU_OK) {
+ dbg() << DEBUG_HPM << "Register event: # branch instructions.\n";
+ PMU::Start(BranchHndl);
+ }
+ if (PMU::CreateEvent(PMU_MEM_LOADS, MemLoadHndl) == PMU_OK) {
+ dbg() << DEBUG_HPM << "Register event: # load instructions.\n";
+ PMU::Start(MemLoadHndl);
+ }
+ if (PMU::CreateEvent(PMU_MEM_STORES, MemStoreHndl) == PMU_OK) {
+ dbg() << DEBUG_HPM << "Register event: # store instructions.\n";
+ PMU::Start(MemStoreHndl);
+ }
+ break;
+ case HPM_FINALIZE:
+ {
+ uint64_t NumInsns = 0, NumBranches = 0, NumLoads = 0, NumStores = 0;
+ if (ICountHndl != PMU_INVALID_HNDL) {
+ PMU::ReadEvent(ICountHndl, NumInsns);
+ PMU::Cleanup(ICountHndl);
+ }
+ if (BranchHndl != PMU_INVALID_HNDL) {
+ PMU::ReadEvent(BranchHndl, NumBranches);
+ PMU::Cleanup(BranchHndl);
+ }
+ if (MemLoadHndl != PMU_INVALID_HNDL) {
+ PMU::ReadEvent(MemLoadHndl, NumLoads);
+ PMU::Cleanup(MemLoadHndl);
+ }
+ if (MemStoreHndl != PMU_INVALID_HNDL) {
+ PMU::ReadEvent(MemStoreHndl, NumStores);
+ PMU::Cleanup(MemStoreHndl);
+ }
+
+ SP->NumInsns += NumInsns;
+ SP->NumBranches += NumBranches;
+ SP->NumLoads += NumLoads;
+ SP->NumStores += NumStores;
+ break;
+ }
+ case HPM_START:
+ if (BranchHndl != PMU_INVALID_HNDL)
+ PMU::ReadEvent(BranchHndl, LastNumBranches);
+ if (MemLoadHndl != PMU_INVALID_HNDL)
+ PMU::ReadEvent(MemLoadHndl, LastNumLoads);
+ if (MemStoreHndl != PMU_INVALID_HNDL)
+ PMU::ReadEvent(MemStoreHndl, LastNumStores);
+ break;
+ case HPM_STOP:
+ {
+ uint64_t NumBranches = 0, NumLoads = 0, NumStores = 0;
+ if (BranchHndl != PMU_INVALID_HNDL)
+ PMU::ReadEvent(BranchHndl, NumBranches);
+ if (MemLoadHndl != PMU_INVALID_HNDL)
+ PMU::ReadEvent(MemLoadHndl, NumLoads);
+ if (MemStoreHndl != PMU_INVALID_HNDL)
+ PMU::ReadEvent(MemStoreHndl, NumStores);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void PerfmonData::MonitorCoverSet(HPMControl Ctl)
+{
+ if (!(SP->Mode & SPM_HOTSPOT))
+ return;
+
+ switch (Ctl) {
+ case HPM_INIT: {
+ Sample1Config IPConfig;
+ memset(&IPConfig, 0, sizeof(Sample1Config));
+ IPConfig.EventCode = PMU_INSTRUCTIONS;
+ IPConfig.NumPages = 4;
+ IPConfig.Period = 1e5;
+ IPConfig.Watermark = IPConfig.NumPages * getpagesize() / 2;
+ IPConfig.SampleHandler = CoverSetHandler;
+ IPConfig.Opaque = static_cast<void *>(this);
+
+ if (PMU::CreateSampleIP(IPConfig, CoverSetHndl) == PMU_OK) {
+ dbg() << DEBUG_HPM << "Register event: cover set sampling.\n";
+ PMU::Start(CoverSetHndl);
+ }
+ break;
+ }
+ case HPM_FINALIZE:
+ if (CoverSetHndl != PMU_INVALID_HNDL)
+ PMU::Cleanup(CoverSetHndl);
+ break;
+ case HPM_START:
+ case HPM_STOP:
+ default:
+ break;
+ }
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/llvm-opc-mmu.cpp b/src/llvm/llvm-opc-mmu.cpp
new file mode 100644
index 0000000..9d2e60f
--- /dev/null
+++ b/src/llvm/llvm-opc-mmu.cpp
@@ -0,0 +1,344 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * This file provides LLVM IR generator in terms of basic block and trace.
+ */
+
+#include "llvm-debug.h"
+#include "llvm.h"
+#include "llvm-opc.h"
+#include "llvm-target.h"
+#include "utils.h"
+
+#if defined(CONFIG_SOFTMMU)
+extern "C" {
+extern const void * const llvm_ld_helpers[16];
+extern const void * const llvm_st_helpers[16];
+};
+#endif
+
+
+#if defined(CONFIG_USER_ONLY)
+Value *IRFactory::QEMULoad(Value *AddrL, Value *AddrH, TCGMemOpIdx oi)
+{
+ TCGMemOp opc = get_memop(oi);
+ Value *Base = AddrL;
+ PointerType *PtrTy = getPointerTy(getSizeInBits(opc), Segment);
+ LoadInst *LI;
+
+ if (GUEST_BASE == 0 || Segment != 0) {
+ Base = ITP(Base, PtrTy);
+ LI = new LoadInst(Base, "", true, LastInst);
+ } else {
+ Base = ITP(Base, Int8PtrTy);
+ Base = GetElementPtrInst::CreateInBounds(Base, GuestBaseReg.Base, "", LastInst);
+ if (Base->getType() != PtrTy)
+ Base = CAST(Base, PtrTy);
+ LI = new LoadInst(Base, "", true, LastInst);
+ }
+ MF->setGuestMemory(LI);
+
+ return ConvertEndian(LI, opc);
+}
+
+void IRFactory::QEMUStore(Value *Data, Value *AddrL, Value *AddrH, TCGMemOpIdx oi)
+{
+ TCGMemOp opc = get_memop(oi);
+ Value *Base = AddrL;
+ PointerType *PtrTy = getPointerTy(getSizeInBits(opc), Segment);
+ StoreInst *SI;
+
+ Data = ConvertEndian(Data, opc);
+
+ if (GUEST_BASE == 0 || Segment != 0) {
+ Base = ITP(Base, PtrTy);
+ SI = new StoreInst(Data, Base, true, LastInst);
+ } else {
+ Base = ITP(Base, Int8PtrTy);
+ Base = GetElementPtrInst::CreateInBounds(Base, GuestBaseReg.Base, "", LastInst);
+ if (Base->getType() != PtrTy)
+ Base = CAST(Base, PtrTy);
+ SI = new StoreInst(Data, Base, true, LastInst);
+ }
+ MF->setGuestMemory(SI);
+}
+
+#else /* !CONFIG_USER_ONLY */
+
+inline long getTLBOffset(int mem_index)
+{
+ long Offset = 0;
+
+ switch (mem_index) {
+#if NB_MMU_MODES > 0
+ case 0: Offset = offsetof(CPUArchState, tlb_table[0][0]); break;
+#endif
+#if NB_MMU_MODES > 1
+ case 1: Offset = offsetof(CPUArchState, tlb_table[1][0]); break;
+#endif
+#if NB_MMU_MODES > 2
+ case 2: Offset = offsetof(CPUArchState, tlb_table[2][0]); break;
+#endif
+#if NB_MMU_MODES > 3
+ case 3: Offset = offsetof(CPUArchState, tlb_table[3][0]); break;
+#endif
+#if NB_MMU_MODES > 4
+ case 4: Offset = offsetof(CPUArchState, tlb_table[4][0]); break;
+#endif
+#if NB_MMU_MODES > 5
+ case 5: Offset = offsetof(CPUArchState, tlb_table[5][0]);
+#endif
+ default:
+ IRError("%s: internal error. mem_index=%d\n", __func__, mem_index);
+ }
+
+ return Offset;
+}
+
+Value *IRFactory::ConcatTLBVersion(Value *GVA)
+{
+#if defined(ENABLE_TLBVERSION_EXT)
+ GVA = ZEXT64(GVA);
+#endif
+ Type *PtrTy = getPointerTy(DL->getTypeSizeInBits(GVA->getType()));
+ Value *TLBVersion = GetElementPtrInst::CreateInBounds(CPU,
+ CONSTPtr(offsetof(CPUArchState, tlb_version)), "", LastInst);
+ TLBVersion = new BitCastInst(TLBVersion, PtrTy, "", LastInst);
+ TLBVersion = new LoadInst(TLBVersion, "version", true, LastInst);
+ return OR(GVA, TLBVersion);
+}
+
+Value *IRFactory::QEMULoad(Value *AddrL, Value *AddrH, TCGMemOpIdx oi)
+{
+ TCGMemOp opc = get_memop(oi);
+ int mem_index = get_mmuidx(oi);
+ IntegerType *AccessTy;
+ PointerType *GuestPtrTy, *HostPtrTy;
+ int Size, s_bits = opc & MO_SIZE;
+
+ Size = 8 * 1 << s_bits; /* data size (bits) for this load */
+
+ const void *helper = llvm_ld_helpers[opc & (MO_BSWAP | MO_SIZE)];
+ Function *MissFunc = ResolveFunction(getMMUFName(helper));
+ if (!MissFunc)
+ IRError("%s: internal error.\n", __func__);
+
+ GuestPtrTy = (TARGET_LONG_BITS == 32) ? Int32PtrTy : Int64PtrTy;
+ HostPtrTy = (TCG_TARGET_REG_BITS == 32) ? Int32PtrTy : Int64PtrTy;
+
+#if defined(ENABLE_TLBVERSION_EXT)
+ GuestPtrTy = Int64PtrTy;
+#endif
+
+ /* Create TLB basic blocks. */
+ BasicBlock *tlb_hit = BasicBlock::Create(*Context, "tlb_hit", Func);
+ BasicBlock *tlb_miss = BasicBlock::Create(*Context, "tlb_miss", Func);
+ BasicBlock *tlb_exit = BasicBlock::Create(*Context, "tlb_exit", Func);
+ toSink.push_back(tlb_miss);
+
+ /* Load compared value in TLB. QEMU uses only addrlo to index the TLB entry. */
+ Value *TLBEntry, *TLBValue, *CPUAddr;
+ AccessTy = (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 64) ? Int64Ty : Int32Ty;
+ size_t Offset = getTLBOffset(mem_index) + offsetof(CPUTLBEntry, addr_read);
+ TLBEntry = LSHR(AddrL, ConstantInt::get(AccessTy, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS));
+ TLBEntry = AND(TLBEntry, ConstantInt::get(AccessTy, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS));
+ TLBEntry = ADD(TLBEntry, ConstantInt::get(AccessTy, Offset));
+
+ if (TLBEntry->getType() != IntPtrTy)
+ TLBEntry = new ZExtInst(TLBEntry, IntPtrTy, "", LastInst);
+
+ CPUAddr = new PtrToIntInst(CPU, IntPtrTy, "", LastInst);
+ TLBEntry = ADD(CPUAddr, TLBEntry);
+ TLBValue = new IntToPtrInst(TLBEntry, GuestPtrTy, "", LastInst);
+ TLBValue = new LoadInst(TLBValue, "tlb.read", false, LastInst);
+
+ /* Compare GVA and TLB value. */
+ Value *GVA, *Cond, *GuestPC = AddrL;
+ AccessTy = (TARGET_LONG_BITS == 32) ? Int32Ty : Int64Ty;
+ if (AddrH) { /* guest is 64-bit and host is 32-bit. */
+ GuestPC = SHL(ZEXT64(AddrH), CONST64(32));
+ GuestPC = OR(GuestPC, ZEXT64(AddrL));
+ }
+#if defined(ALIGNED_ONLY)
+ GVA = AND(GuestPC, ConstantInt::get(AccessTy,
+ TARGET_PAGE_MASK | ((1 << s_bits) - 1)));
+#elif defined(ENABLE_TLBVERSION)
+ GVA = ADD(GuestPC, ConstantInt::get(AccessTy, (1 << s_bits) - 1));
+ GVA = AND(GVA, ConstantInt::get(AccessTy, TARGET_PAGE_MASK));
+ GVA = ConcatTLBVersion(GVA);
+#else
+ GVA = ADD(GuestPC, ConstantInt::get(AccessTy, (1 << s_bits) - 1));
+ GVA = AND(GVA, ConstantInt::get(AccessTy, TARGET_PAGE_MASK));
+#endif
+ Cond = ICMP(GVA, TLBValue, ICmpInst::ICMP_EQ);
+ BranchInst::Create(tlb_hit, tlb_miss, Cond, LastInst);
+ LastInst->eraseFromParent();
+
+ /* TLB hit. */
+ Value *PhyAddr, *Addend, *HitData, *Addr=AddrL;
+
+ LastInst = BranchInst::Create(tlb_exit, tlb_hit);
+ if (Addr->getType() != IntPtrTy)
+ Addr = new ZExtInst(Addr, IntPtrTy, "", LastInst);
+
+ Offset = offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read);
+ Addend = ADD(TLBEntry, ConstantInt::get(IntPtrTy, Offset));
+ Addend = new IntToPtrInst(Addend, HostPtrTy, "", LastInst);
+ Addend = new LoadInst(Addend, "tlb.addend", false, LastInst);
+ PhyAddr = ADD(Addr, Addend);
+ PhyAddr = ITP(PhyAddr, getPointerTy(Size));
+ HitData = new LoadInst(PhyAddr, "hit", true, LastInst);
+
+ HitData = ConvertEndian(HitData, opc);
+
+ /* TLB miss. */
+ LastInst = BranchInst::Create(tlb_exit, tlb_miss);
+ SmallVector<Value *, 4> Params;
+ uint32_t restore_val = setRestorePoint(oi);
+ Params.push_back(CPUStruct);
+ Params.push_back(GuestPC);
+ Params.push_back(CONST32(restore_val));
+
+ CallInst *MissCall = CallInst::Create(MissFunc, Params, "", LastInst);
+ Value *MissData = MissCall;
+ switch (opc & MO_SSIZE) {
+ case MO_UB:
+ case MO_SB:
+ if (DL->getTypeSizeInBits(MissData->getType()) != 8)
+ MissData = TRUNC8(MissCall);
+ break;
+ case MO_UW:
+ case MO_SW:
+ if (DL->getTypeSizeInBits(MissData->getType()) != 16)
+ MissData = TRUNC16(MissCall);
+ break;
+ case MO_UL:
+ case MO_SL:
+ if (DL->getTypeSizeInBits(MissData->getType()) != 32)
+ MissData = TRUNC32(MissCall);
+ break;
+ case MO_Q:
+ if (DL->getTypeSizeInBits(MissData->getType()) != 64)
+ MissData = ZEXT64(MissCall);
+ break;
+ default:
+ IRError("%s: invalid size (opc=%d)\n", __func__, opc);
+ break;
+ }
+
+ /* TLB exit. */
+ CurrBB = tlb_exit;
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+ PHINode *PH = PHINode::Create(HitData->getType(), 2, "", LastInst);
+ PH->addIncoming(HitData, tlb_hit);
+ PH->addIncoming(MissData, tlb_miss);
+
+ return PH;
+}
+
+void IRFactory::QEMUStore(Value *Data, Value *AddrL, Value *AddrH, TCGMemOpIdx oi)
+{
+ TCGMemOp opc = get_memop(oi);
+ int mem_index = get_mmuidx(oi);
+ IntegerType *AccessTy;
+ PointerType *GuestPtrTy, *HostPtrTy;
+ int Size, s_bits = opc & MO_SIZE;
+
+ Size = 8 * 1 << s_bits; /* data size (bits) for this load */
+
+ const void *helper = llvm_st_helpers[opc & (MO_BSWAP | MO_SIZE)];
+ Function *MissFunc = ResolveFunction(getMMUFName(helper));
+ if (!MissFunc)
+ IRError("%s: internal error.\n", __func__);
+
+ GuestPtrTy = (TARGET_LONG_BITS == 32) ? Int32PtrTy : Int64PtrTy;
+ HostPtrTy = (TCG_TARGET_REG_BITS == 32) ? Int32PtrTy : Int64PtrTy;
+
+#if defined(ENABLE_TLBVERSION_EXT)
+ GuestPtrTy = Int64PtrTy;
+#endif
+
+ /* Create TLB basic blocks. */
+ BasicBlock *tlb_hit = BasicBlock::Create(*Context, "tlb_hit", Func);
+ BasicBlock *tlb_miss = BasicBlock::Create(*Context, "tlb_miss", Func);
+ BasicBlock *tlb_exit = BasicBlock::Create(*Context, "tlb_exit", Func);
+ toSink.push_back(tlb_miss);
+
+ /* Load compared value in TLB. QEMU uses only addrlo to index the TLB entry. */
+ Value *TLBEntry, *TLBValue, *CPUAddr;
+ AccessTy = (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 64) ? Int64Ty : Int32Ty;
+ size_t Offset = getTLBOffset(mem_index) + offsetof(CPUTLBEntry, addr_write);
+ TLBEntry = LSHR(AddrL, ConstantInt::get(AccessTy, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS));
+ TLBEntry = AND(TLBEntry, ConstantInt::get(AccessTy, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS));
+ TLBEntry = ADD(TLBEntry, ConstantInt::get(AccessTy, Offset));
+
+ if (TLBEntry->getType() != IntPtrTy)
+ TLBEntry = new ZExtInst(TLBEntry, IntPtrTy, "", LastInst);
+
+ CPUAddr = new PtrToIntInst(CPU, IntPtrTy, "", LastInst);
+ TLBEntry = ADD(CPUAddr, TLBEntry);
+ TLBValue = new IntToPtrInst(TLBEntry, GuestPtrTy, "", LastInst);
+ TLBValue = new LoadInst(TLBValue, "tlb.write", false, LastInst);
+
+ /* Compare GVA and TLB value. */
+ Value *GVA, *Cond, *GuestPC = AddrL;
+ AccessTy = (TARGET_LONG_BITS == 32) ? Int32Ty : Int64Ty;
+ if (AddrH != nullptr) { /* guest is 64-bit and host is 32-bit. */
+ GuestPC = SHL(ZEXT64(AddrH), CONST64(32));
+ GuestPC = OR(GuestPC, ZEXT64(AddrL));
+ }
+#if defined(ALIGNED_ONLY)
+ GVA = AND(GuestPC, ConstantInt::get(AccessTy,
+ TARGET_PAGE_MASK | ((1 << s_bits) - 1)));
+#elif defined(ENABLE_TLBVERSION)
+ GVA = ADD(GuestPC, ConstantInt::get(AccessTy, (1 << s_bits) - 1));
+ GVA = AND(GVA, ConstantInt::get(AccessTy, TARGET_PAGE_MASK));
+ GVA = ConcatTLBVersion(GVA);
+#else
+ GVA = ADD(GuestPC, ConstantInt::get(AccessTy, (1 << s_bits) - 1));
+ GVA = AND(GVA, ConstantInt::get(AccessTy, TARGET_PAGE_MASK));
+#endif
+ Cond = ICMP(GVA, TLBValue, ICmpInst::ICMP_EQ);
+ BranchInst::Create(tlb_hit, tlb_miss, Cond, LastInst);
+ LastInst->eraseFromParent();
+
+ /* TLB hit. */
+ Value *PhyAddr, *Addend, *Addr=AddrL;
+
+ LastInst = BranchInst::Create(tlb_exit, tlb_hit);
+ if (Addr->getType() != IntPtrTy)
+ Addr = new ZExtInst(Addr, IntPtrTy, "", LastInst);
+
+ Offset = offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write);
+ Addend = ADD(TLBEntry, ConstantInt::get(IntPtrTy, Offset));
+ Addend = new IntToPtrInst(Addend, HostPtrTy, "", LastInst);
+ Addend = new LoadInst(Addend, "tlb.addend", false, LastInst);
+ PhyAddr = ADD(Addr, Addend);
+ PhyAddr = ITP(PhyAddr, getPointerTy(Size));
+
+ Value *HitData = ConvertEndian(Data, opc);
+
+ new StoreInst(HitData, PhyAddr, true, LastInst);
+
+ /* TLB miss. */
+ LastInst = BranchInst::Create(tlb_exit, tlb_miss);
+ SmallVector<Value *, 4> Params;
+ uint32_t restore_val = setRestorePoint(oi);
+ Params.push_back(CPUStruct);
+ Params.push_back(GuestPC);
+ Params.push_back(Data);
+ Params.push_back(CONST32(restore_val));
+
+ CallInst::Create(MissFunc, Params, "", LastInst);
+
+ /* TLB exit. */
+ CurrBB = tlb_exit;
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+}
+
+#endif /* CONFIG_USER_ONLY */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/llvm-opc-vector.cpp b/src/llvm/llvm-opc-vector.cpp
new file mode 100644
index 0000000..3ce5f68
--- /dev/null
+++ b/src/llvm/llvm-opc-vector.cpp
@@ -0,0 +1,943 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * This file provides TCG vector IR to LLVM IR conversions.
+ */
+
+#include "llvm.h"
+#include "llvm-debug.h"
+#include "llvm-opc.h"
+#include "utils.h"
+
+
+extern TCGOpDef llvm_op_defs[];
+
+
+void IRFactory::op_vector_start(const TCGArg *args)
+{
+ IRError("%s: this function should never be called.\n", __func__);
+}
+
+void IRFactory::op_vector_end(const TCGArg *args)
+{
+ IRError("%s: this function should never be called.\n", __func__);
+}
+
+void IRFactory::op_vmov_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmov_128);
+
+ TCGArg DstOff = args[0];
+ TCGArg SrcOff = args[1];
+ Value *Dst, *Src;
+
+ VectorType *VectorTy = VectorType::get(Int8Ty, 16);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+ Src = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(SrcOff), "", LastInst);
+ Src = new BitCastInst(Src, PtrTy, "", LastInst);
+ Dst = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(DstOff), "", LastInst);
+ Dst = new BitCastInst(Dst, PtrTy, "", LastInst);
+
+ Src = new LoadInst(Src, "", false, LastInst);
+ new StoreInst(Src, Dst, false, LastInst);
+}
+
+void IRFactory::op_vload_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vload_128);
+
+ TCGArg Off = args[0];
+ Register &In = Reg[args[1]];
+ TCGArg Alignment = (args[2] == (TCGArg)-1) ? 4 : args[2] / 8;
+ Value *Base = LoadState(In);
+ LoadInst *LI;
+
+ AssertType(In.Size == 32 || In.Size == 64);
+
+ VectorType *VectorTy = VectorType::get(Int8Ty, 16);
+ PointerType *PtrTy = PointerType::get(VectorTy, Segment);
+
+ if (GUEST_BASE == 0 || Segment != 0) {
+ Base = ITP(Base, PtrTy);
+ LI = new LoadInst(Base, "", true, LastInst);
+ } else {
+ Base = ITP(Base, Int8PtrTy);
+ Base = GetElementPtrInst::CreateInBounds(Base, GuestBaseReg.Base, "", LastInst);
+ if (Base->getType() != PtrTy)
+ Base = CAST(Base, PtrTy);
+ LI = new LoadInst(Base, "", true, LastInst);
+ }
+ LI->setAlignment(Alignment);
+
+ MF->setGuestMemory(LI);
+
+ PtrTy = PointerType::getUnqual(VectorTy);
+ Value *V = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Off), "", LastInst);
+ V = new BitCastInst(V, PtrTy, "", LastInst);
+ new StoreInst(LI, V, false, LastInst);
+}
+
+void IRFactory::op_vstore_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vstore_128);
+
+ TCGArg Off = args[0];
+ Register &In = Reg[args[1]];
+ TCGArg Alignment = (args[2] == (TCGArg)-1) ? 4 : args[2] / 8;
+ Value *Base = LoadState(In);
+ StoreInst *SI;
+
+ AssertType(In.Size == 32 || In.Size == 64);
+
+ VectorType *VectorTy = VectorType::get(Int8Ty, 16);
+ PointerType *PtrTy = nullptr;
+
+ PtrTy = PointerType::getUnqual(VectorTy);
+ Value *V = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Off), "", LastInst);
+ V = new BitCastInst(V, PtrTy, "", LastInst);
+ V = new LoadInst(V, "", false, LastInst);
+
+ PtrTy = PointerType::get(VectorTy, Segment);
+ if (GUEST_BASE == 0 || Segment != 0) {
+ Base = ITP(Base, PtrTy);
+ SI = new StoreInst(V, Base, true, LastInst);
+ } else {
+ Base = ITP(Base, Int8PtrTy);
+ Base = GetElementPtrInst::CreateInBounds(Base, GuestBaseReg.Base, "", LastInst);
+ if (Base->getType() != PtrTy)
+ Base = CAST(Base, PtrTy);
+ SI = new StoreInst(V, Base, true, LastInst);
+ }
+
+ SI->setAlignment(Alignment);
+
+ MF->setGuestMemory(SI);
+}
+
+#define llvm_gen_vop(_Fn,_Num,_Ty) \
+do { \
+ TCGArg Out = args[0]; \
+ TCGArg In1 = args[1]; \
+ TCGArg In2 = args[2]; \
+ Value *OutPtr, *InPtr1, *InPtr2; \
+ VectorType *VectorTy = VectorType::get(_Ty, _Num); \
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy); \
+ \
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst); \
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst); \
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst); \
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst); \
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst); \
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst); \
+ \
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst); \
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst); \
+ InData1 = _Fn(InData1, InData2); \
+ new StoreInst(InData1, OutPtr, false, LastInst); \
+} while (0)
+
+#define llvm_gen_vop2(_Fn1,_Fn2,_Num,_Ty) \
+do { \
+ TCGArg Out = args[0]; \
+ TCGArg In1 = args[1]; \
+ TCGArg In2 = args[2]; \
+ Value *OutPtr, *InPtr1, *InPtr2; \
+ VectorType *VectorTy = VectorType::get(_Ty, _Num); \
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy); \
+ \
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst); \
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst); \
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst); \
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst); \
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst); \
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst); \
+ \
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst); \
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst); \
+ Value *InData3 = new LoadInst(OutPtr, "", false, LastInst); \
+ InData1 = _Fn2(InData3, _Fn1(InData1, InData2)); \
+ new StoreInst(InData1, OutPtr, false, LastInst); \
+} while (0)
+
+
+void IRFactory::op_vadd_i8_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_i8_128);
+ llvm_gen_vop(ADD, 16, Int8Ty);
+}
+
+void IRFactory::op_vadd_i16_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_i16_128);
+ llvm_gen_vop(ADD, 8, Int16Ty);
+}
+
+void IRFactory::op_vadd_i32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_i32_128);
+ llvm_gen_vop(ADD, 4, Int32Ty);
+}
+
+void IRFactory::op_vadd_i64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_i64_128);
+ llvm_gen_vop(ADD, 2, Int64Ty);
+}
+
+void IRFactory::op_vadd_i8_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_i8_64);
+ llvm_gen_vop(ADD, 8, Int8Ty);
+}
+
+void IRFactory::op_vadd_i16_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_i16_64);
+ llvm_gen_vop(ADD, 4, Int16Ty);
+}
+
+void IRFactory::op_vadd_i32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_i32_64);
+ llvm_gen_vop(ADD, 2, Int32Ty);
+}
+
+void IRFactory::op_vsub_i8_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_i8_128);
+ llvm_gen_vop(SUB, 16, Int8Ty);
+}
+
+void IRFactory::op_vsub_i16_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_i16_128);
+ llvm_gen_vop(SUB, 8, Int16Ty);
+}
+
+void IRFactory::op_vsub_i32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_i32_128);
+ llvm_gen_vop(SUB, 4, Int32Ty);
+}
+
+void IRFactory::op_vsub_i64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_i64_128);
+ llvm_gen_vop(SUB, 2, Int64Ty);
+}
+
+void IRFactory::op_vsub_i8_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_i8_64);
+ llvm_gen_vop(SUB, 8, Int8Ty);
+}
+
+void IRFactory::op_vsub_i16_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_i16_64);
+ llvm_gen_vop(SUB, 4, Int16Ty);
+}
+
+void IRFactory::op_vsub_i32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_i32_64);
+ llvm_gen_vop(SUB, 2, Int32Ty);
+}
+
+void IRFactory::op_vadd_f32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_f32_128);
+ llvm_gen_vop(FADD, 4, FloatTy);
+}
+
+void IRFactory::op_vadd_f64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_f64_128);
+ llvm_gen_vop(FADD, 2, DoubleTy);
+}
+
+void IRFactory::op_vadd_f32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vadd_f32_64);
+ llvm_gen_vop(FADD, 2, FloatTy);
+}
+
+void IRFactory::op_vpadd_f32_128(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vpadd_f64_128(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vpadd_f32_64(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vsub_f32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_f32_128);
+ llvm_gen_vop(FSUB, 4, FloatTy);
+}
+
+void IRFactory::op_vsub_f64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_f64_128);
+ llvm_gen_vop(FSUB, 2, DoubleTy);
+}
+
+void IRFactory::op_vsub_f32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsub_f32_64);
+ llvm_gen_vop(FSUB, 2, FloatTy);
+}
+
+void IRFactory::op_vabd_f32_128(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vabd_f64_128(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vabd_f32_64(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vfma_f32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vfma_f32_128);
+ llvm_gen_vop2(FMUL, FADD, 4, FloatTy);
+}
+
+void IRFactory::op_vfma_f64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vfma_f64_128);
+ llvm_gen_vop2(FMUL, FADD, 2, DoubleTy);
+}
+
+void IRFactory::op_vfma_f32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vfma_f32_64);
+ llvm_gen_vop2(FMUL, FADD, 2, FloatTy);
+}
+
+void IRFactory::op_vfms_f32_128(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vfms_f64_128(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vfms_f32_64(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_vmul_f32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmul_f32_128);
+ llvm_gen_vop(FMUL, 4, FloatTy);
+}
+
+void IRFactory::op_vmul_f64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmul_f64_128);
+ llvm_gen_vop(FMUL, 2, DoubleTy);
+}
+
+void IRFactory::op_vmul_f32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmul_f32_64);
+ llvm_gen_vop(FMUL, 2, FloatTy);
+}
+
+void IRFactory::op_vmla_f32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmla_f32_128);
+ llvm_gen_vop2(FMUL, FADD, 4, FloatTy);
+}
+
+void IRFactory::op_vmla_f64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmla_f64_128);
+ llvm_gen_vop2(FMUL, FADD, 2, DoubleTy);
+}
+
+void IRFactory::op_vmla_f32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmla_f32_64);
+ llvm_gen_vop2(FMUL, FADD, 2, FloatTy);
+}
+
+void IRFactory::op_vmls_f32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmls_f32_128);
+ llvm_gen_vop2(FMUL, FSUB, 4, FloatTy);
+}
+
+void IRFactory::op_vmls_f64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmls_f64_128);
+ llvm_gen_vop2(FMUL, FSUB, 2, DoubleTy);
+}
+
+void IRFactory::op_vmls_f32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vmls_f32_64);
+ llvm_gen_vop2(FMUL, FSUB, 2, FloatTy);
+}
+
+void IRFactory::op_vdiv_f32_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vdiv_f32_128);
+ llvm_gen_vop(FDIV, 4, FloatTy);
+}
+
+void IRFactory::op_vdiv_f64_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vdiv_f64_128);
+ llvm_gen_vop(FDIV, 2, DoubleTy);
+}
+
+void IRFactory::op_vdiv_f32_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vdiv_f32_64);
+ llvm_gen_vop(FDIV, 2, FloatTy);
+}
+
+void IRFactory::op_vand_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vand_128);
+ if (args[1] == args[2]) {
+ op_vmov_128(args);
+ return;
+ }
+ llvm_gen_vop(AND, 4, Int32Ty);
+}
+
+void IRFactory::op_vand_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vand_64);
+ llvm_gen_vop(AND, 2, Int32Ty);
+}
+
+void IRFactory::op_vbic_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vbic_128);
+
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 4);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 4; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ InData2 = XOR(InData2, VecMinusOne);
+ InData1 = AND(InData1, InData2);
+ new StoreInst(InData1, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vbic_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vbic_64);
+
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 2);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 2; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ InData2 = XOR(InData2, VecMinusOne);
+ InData1 = AND(InData1, InData2);
+ new StoreInst(InData1, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vorr_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vorr_128);
+ if (args[1] == args[2]) {
+ op_vmov_128(args);
+ return;
+ }
+ llvm_gen_vop(OR, 4, Int32Ty);
+}
+
+void IRFactory::op_vorr_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vorr_64);
+ llvm_gen_vop(OR, 2, Int32Ty);
+}
+
+void IRFactory::op_vorn_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vorn_128);
+
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 4);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 4; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ InData2 = XOR(InData2, VecMinusOne);
+ InData1 = OR(InData1, InData2);
+ new StoreInst(InData1, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vorn_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vorn_64);
+
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 2);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 2; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ InData2 = XOR(InData2, VecMinusOne);
+ InData1 = OR(InData1, InData2);
+ new StoreInst(InData1, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_veor_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_veor_128);
+ llvm_gen_vop(XOR, 4, Int32Ty);
+}
+
+void IRFactory::op_veor_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_veor_64);
+ llvm_gen_vop(XOR, 2, Int32Ty);
+}
+
+void IRFactory::op_vbif_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vbif_128);
+
+ /* vbif rd, rn, rm
+ * operation: rd <- (rd & rm) | (rn & ~rm) */
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 4);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 4; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ Value *InData3 = new LoadInst(OutPtr, "", false, LastInst);
+
+ InData3 = AND(InData3, InData2);
+ InData1 = AND(InData1, XOR(InData2, VecMinusOne));
+ InData3 = OR(InData1, InData3);
+ new StoreInst(InData3, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vbif_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vbif_64);
+
+ /* vbif rd, rn, rm
+ * operation: rd <- (rd & rm) | (rn & ~rm) */
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 2);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 2; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ Value *InData3 = new LoadInst(OutPtr, "", false, LastInst);
+
+ InData3 = AND(InData3, InData2);
+ InData1 = AND(InData1, XOR(InData2, VecMinusOne));
+ InData3 = OR(InData1, InData3);
+ new StoreInst(InData3, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vbit_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vbit_128);
+
+ /* vbit rd, rn, rm
+ * operation: rd <- (rn & rm) | (rd & ~rm) */
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 4);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 4; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ Value *InData3 = new LoadInst(OutPtr, "", false, LastInst);
+
+ InData1 = AND(InData1, InData2);
+ InData3 = AND(InData3, XOR(InData2, VecMinusOne));
+ InData3 = OR(InData1, InData3);
+ new StoreInst(InData3, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vbit_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vbit_64);
+
+ /* vbit rd, rn, rm
+ * operation: rd <- (rn & rm) | (rd & ~rm) */
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 2);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 2; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ Value *InData3 = new LoadInst(OutPtr, "", false, LastInst);
+
+ InData1 = AND(InData1, InData2);
+ InData3 = AND(InData3, XOR(InData2, VecMinusOne));
+ InData3 = OR(InData1, InData3);
+ new StoreInst(InData3, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vbsl_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vbsl_128);
+
+ /* vbsl rd, rn, rm
+ * operation: rd <- (rn & rd) | (rm & ~rd) */
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 4);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 4; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ Value *InData3 = new LoadInst(OutPtr, "", false, LastInst);
+
+ InData1 = AND(InData1, InData3);
+ InData2 = AND(InData2, XOR(InData3, VecMinusOne));
+ InData3 = OR(InData1, InData2);
+ new StoreInst(InData3, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vbsl_64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vbsl_64);
+
+ /* vbsl rd, rn, rm
+ * operation: rd <- (rn & rd) | (rm & ~rd) */
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg In2 = args[2];
+ Value *OutPtr, *InPtr1, *InPtr2;
+ VectorType *VectorTy = VectorType::get(Int32Ty, 2);
+ PointerType *PtrTy = PointerType::getUnqual(VectorTy);
+
+ InPtr1 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr1 = new BitCastInst(InPtr1, PtrTy, "", LastInst);
+ InPtr2 = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In2), "", LastInst);
+ InPtr2 = new BitCastInst(InPtr2, PtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, PtrTy, "", LastInst);
+
+ std::vector<Constant *> V;
+ for (int i = 0; i < 2; i++)
+ V.push_back(CONST32(-1U));
+ Value *VecMinusOne = ConstantVector::get(V);
+
+ Value *InData1 = new LoadInst(InPtr1, "", false, LastInst);
+ Value *InData2 = new LoadInst(InPtr2, "", false, LastInst);
+ Value *InData3 = new LoadInst(OutPtr, "", false, LastInst);
+
+ InData1 = AND(InData1, InData3);
+ InData2 = AND(InData2, XOR(InData3, VecMinusOne));
+ InData3 = OR(InData1, InData2);
+ new StoreInst(InData3, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vsitofp_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vsitofp_128);
+
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg Size = args[2];
+
+ unsigned NumElements = 0;
+ Type *SrcTy = nullptr, *DstTy = nullptr;
+ if (Size == 32) {
+ NumElements = 4;
+ SrcTy = Int32Ty;
+ DstTy = FloatTy;
+ } else if (Size == 64) {
+ NumElements = 2;
+ SrcTy = Int64Ty;
+ DstTy = DoubleTy;
+ } else
+ IRError("%s: invalid element size.\n", __func__);
+
+ Value *OutPtr, *InPtr;
+ VectorType *VectorInt = VectorType::get(SrcTy, NumElements);
+ PointerType *VIntPtrTy = PointerType::getUnqual(VectorInt);
+ VectorType *VectorFP = VectorType::get(DstTy, NumElements);
+ PointerType *VFPPtrTy = PointerType::getUnqual(VectorFP);
+
+ InPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr = new BitCastInst(InPtr, VIntPtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, VFPPtrTy, "", LastInst);
+
+ Value *InData = new LoadInst(InPtr, "", false, LastInst);
+ InData = new SIToFPInst(InData, VectorFP, "", LastInst);
+ new StoreInst(InData, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vuitofp_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vuitofp_128);
+
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg Size = args[2];
+
+ unsigned NumElements = 0;
+ Type *SrcTy = nullptr, *DstTy = nullptr;
+ if (Size == 32) {
+ NumElements = 4;
+ SrcTy = Int32Ty;
+ DstTy = FloatTy;
+ } else if (Size == 64) {
+ NumElements = 2;
+ SrcTy = Int64Ty;
+ DstTy = DoubleTy;
+ } else
+ IRError("%s: invalid element size.\n", __func__);
+
+ Value *OutPtr, *InPtr;
+ VectorType *VectorInt = VectorType::get(SrcTy, NumElements);
+ PointerType *VIntPtrTy = PointerType::getUnqual(VectorInt);
+ VectorType *VectorFP = VectorType::get(DstTy, NumElements);
+ PointerType *VFPPtrTy = PointerType::getUnqual(VectorFP);
+
+ InPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr = new BitCastInst(InPtr, VIntPtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, VFPPtrTy, "", LastInst);
+
+ Value *InData = new LoadInst(InPtr, "", false, LastInst);
+ InData = new UIToFPInst(InData, VectorFP, "", LastInst);
+ new StoreInst(InData, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vfptosi_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vfptosi_128);
+
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg Size = args[2];
+
+ unsigned NumElements = 0;
+ Type *SrcTy = nullptr, *DstTy = nullptr;
+ if (Size == 32) {
+ NumElements = 4;
+ SrcTy = FloatTy;
+ DstTy = Int32Ty;
+ } else if (Size == 64) {
+ NumElements = 2;
+ SrcTy = DoubleTy;
+ DstTy = Int64Ty;
+ } else
+ IRError("%s: invalid element size.\n", __func__);
+
+ Value *OutPtr, *InPtr;
+ VectorType *VectorFP = VectorType::get(SrcTy, NumElements);
+ PointerType *VFPPtrTy = PointerType::getUnqual(VectorFP);
+ VectorType *VectorInt = VectorType::get(DstTy, NumElements);
+ PointerType *VIntPtrTy = PointerType::getUnqual(VectorInt);
+
+ InPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr = new BitCastInst(InPtr, VFPPtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, VIntPtrTy, "", LastInst);
+
+ Value *InData = new LoadInst(InPtr, "", false, LastInst);
+ InData = new FPToSIInst(InData, VectorInt, "", LastInst);
+ new StoreInst(InData, OutPtr, false, LastInst);
+}
+
+void IRFactory::op_vfptoui_128(const TCGArg *args)
+{
+ IRDebug(INDEX_op_vfptoui_128);
+
+ TCGArg Out = args[0];
+ TCGArg In1 = args[1];
+ TCGArg Size = args[2];
+
+ unsigned NumElements = 0;
+ Type *SrcTy = nullptr, *DstTy = nullptr;
+ if (Size == 32) {
+ NumElements = 4;
+ SrcTy = FloatTy;
+ DstTy = Int32Ty;
+ } else if (Size == 64) {
+ NumElements = 2;
+ SrcTy = DoubleTy;
+ DstTy = Int64Ty;
+ } else
+ IRError("%s: invalid element size.\n", __func__);
+
+ Value *OutPtr, *InPtr;
+ VectorType *VectorFP = VectorType::get(SrcTy, NumElements);
+ PointerType *VFPPtrTy = PointerType::getUnqual(VectorFP);
+ VectorType *VectorInt = VectorType::get(DstTy, NumElements);
+ PointerType *VIntPtrTy = PointerType::getUnqual(VectorInt);
+
+ InPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(In1), "", LastInst);
+ InPtr = new BitCastInst(InPtr, VFPPtrTy, "", LastInst);
+ OutPtr = GetElementPtrInst::CreateInBounds(CPU, CONSTPtr(Out), "", LastInst);
+ OutPtr = new BitCastInst(OutPtr, VIntPtrTy, "", LastInst);
+
+ Value *InData = new LoadInst(InPtr, "", false, LastInst);
+ InData = new FPToUIInst(InData, VectorInt, "", LastInst);
+ new StoreInst(InData, OutPtr, false, LastInst);
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/llvm-opc.cpp b/src/llvm/llvm-opc.cpp
new file mode 100644
index 0000000..cc8436c
--- /dev/null
+++ b/src/llvm/llvm-opc.cpp
@@ -0,0 +1,4431 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * This file provides LLVM IR generator in terms of basic block and trace.
+ */
+
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Analysis/InlineCost.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm-debug.h"
+#include "llvm-pass.h"
+#include "llvm-translator.h"
+#include "llvm-target.h"
+#include "llvm-state.h"
+#include "llvm-opc.h"
+
+
+#define INLINE_THRESHOLD 100 /* max # inlined instructions */
+#define INLINE_INSTCOUNT 20 /* max instruction count for inlining a small function */
+
+/* Options enabled by default. */
+static cl::opt<bool> DisableStateMapping("disable-sm", cl::init(false),
+ cl::cat(CategoryHQEMU), cl::desc("Disable state mapping"));
+
+/* Options Disabled by default. */
+static cl::opt<bool> EnableSimplifyPointer("enable-simptr", cl::init(false),
+ cl::cat(CategoryHQEMU), cl::desc("Enable SimplifyPointer"));
+
+
+TCGOpDef llvm_op_defs[] = {
+#define DEF(s, oargs, iargs, cargs, flags) \
+ { #s , oargs, iargs, cargs, iargs + oargs + cargs, flags },
+#include "tcg-opc.h"
+#undef DEF
+};
+
+static IRFactory::FuncPtr OpcFunc[] = {
+#define DEF(name, oargs, iargs, cargs, flags) &IRFactory::op_ ## name,
+#include "tcg-opc.h"
+#undef DEF
+};
+
+extern LLVMEnv *LLEnv;
+extern hqemu::Mutex llvm_global_lock;
+extern hqemu::Mutex llvm_debug_lock;
+
+/*
+ * IRFactory()
+ */
+IRFactory::IRFactory(LLVMTranslator *Trans)
+ : InitOnce(false), Translator(*Trans), EE(nullptr),
+ HostDisAsm(Translator.getHostDisAsm()), Helpers(Translator.getHelpers()),
+ BaseReg(Translator.getBaseReg()), GuestBaseReg(Translator.getGuestBaseReg()),
+ NI(Translator.getNotifyInfo())
+{
+ /* Track TCG virtual registers. */
+ Reg.resize(TCG_MAX_TEMPS);
+
+ TCGContext *s = &tcg_ctx_global;
+ int NumGlobals = s->nb_globals;
+ for (int i = 0; i < NumGlobals; ++i) {
+ TCGTemp *T = &s->temps[i];
+ if (T->type != TCG_TYPE_I32 && T->type != TCG_TYPE_I64)
+ hqemu_error("unsupported register type.\n");
+
+ int Base = (T->fixed_reg) ? T->reg : T->mem_reg;
+ intptr_t Off = (T->fixed_reg) ? -1 : T->mem_offset;
+ Reg[i].set(Base, Off, T->name);
+ }
+
+ for (int i = 0; i < NumGlobals; ++i) {
+ TCGTemp *T1 = &s->temps[i];
+ for (int j = i + 1; j < NumGlobals; ++j) {
+ TCGTemp *T2 = &s->temps[j];
+ if (T1->fixed_reg || T2->fixed_reg)
+ continue;
+ if (Reg[j].Alias)
+ continue;
+ if (T1->mem_offset == T2->mem_offset && T1->type == T2->type)
+ Reg[j].Alias = &Reg[i];
+ }
+ }
+
+ Segment = 0;
+#if defined(__x86_64__) && defined(__linux__)
+ if (GUEST_BASE)
+ Segment = 256; /* GS: 256 */
+#endif
+
+ dbg() << DEBUG_LLVM << "LLVM IR Factory initialized.\n";
+}
+
+IRFactory::~IRFactory()
+{
+ if (EE) {
+ EE->UnregisterJITEventListener(Listener);
+ EE->removeModule(Mod);
+ delete Listener;
+ delete EE;
+ }
+}
+
+void IRFactory::CreateSession(TraceBuilder *builder)
+{
+ Builder = builder;
+
+ CreateJIT();
+ InitializeTypes();
+
+ MF = new MDFactory(Mod);
+ ExitAddr = CONSTPtr((uintptr_t)tb_ret_addr);
+
+ runPasses = true;
+
+ /* Reset data structures. */
+ StatePtr.clear();
+ InlineCalls.clear();
+ IndirectBrs.clear();
+ CommonBB.clear();
+ toErase.clear();
+ toSink.clear();
+ ClonedFuncs.clear();
+ NI.reset();
+}
+
+void IRFactory::DeleteSession()
+{
+ if (Func) {
+ Func->removeFromParent();
+ delete Func;
+ Func = nullptr;
+ }
+ delete MF;
+ DeleteJIT();
+}
+
+static void setHostAttrs(std::string &MCPU, std::vector<std::string> &MAttrs,
+ TargetOptions &Options)
+{
+ MCPU = sys::getHostCPUName();
+
+ StringMap<bool> HostFeatures;
+ sys::getHostCPUFeatures(HostFeatures);
+ for (auto &F : HostFeatures)
+ MAttrs.push_back((F.second ? "+" : "-") + F.first().str());
+
+ if (MCPU == "core-avx2" || MCPU == "haswell" || MCPU == "knl")
+ Options.AllowFPOpFusion = FPOpFusion::Fast;
+}
+
+#if defined(ENABLE_MCJIT)
+#if defined(LLVM_V35)
+void IRFactory::CreateJIT()
+{
+ Module *InitMod = Translator.getModule();
+ Context = &InitMod->getContext();
+ Mod = new Module(InitMod->getModuleIdentifier(), *Context);
+ Mod->setDataLayout(InitMod->getDataLayout());
+ Mod->setTargetTriple(InitMod->getTargetTriple());
+
+ DL = getDataLayout(Mod);
+
+ /* Create JIT execution engine. */
+ std::string ErrorMsg, MCPU;
+ std::vector<std::string> MAttrs;
+ TargetOptions Options;
+
+ setHostAttrs(MCPU, MAttrs, Options);
+
+ EngineBuilder builder(Mod);
+ builder.setMCPU(MCPU);
+ builder.setMAttrs(MAttrs);
+ builder.setErrorStr(&ErrorMsg);
+ builder.setEngineKind(EngineKind::JIT);
+ builder.setOptLevel(CodeGenOpt::Default);
+ builder.setUseMCJIT(true);
+ builder.setMCJITMemoryManager(LLEnv->getMemoryManager().get());
+ builder.setTargetOptions(Options);
+
+ EE = builder.create();
+
+ if (!EE)
+ hqemu_error("%s\n", ErrorMsg.c_str());
+
+ /* Create JIT event listener and link target machine. */
+ Listener = new EventListener(NI);
+
+ EE->RegisterJITEventListener(Listener);
+
+ /* Ask LLVM to reserve basereg. */
+ auto TM = EE->getTargetMachine();
+ auto TRI = const_cast<TargetRegisterInfo*>(TM->getRegisterInfo());
+ TRI->setHQEMUReservedRegs(BaseReg[TCG_AREG0].Name);
+
+ dbg() << DEBUG_LLVM << "LLVM MCJIT initialized.\n";
+}
+#else
+void IRFactory::CreateJIT()
+{
+ Module *InitMod = Translator.getModule();
+ Context = &InitMod->getContext();
+ std::unique_ptr<Module> Owner(
+ new Module(InitMod->getModuleIdentifier(), *Context));
+ Mod = Owner.get();
+ Mod->setDataLayout(InitMod->getDataLayout());
+ Mod->setTargetTriple(InitMod->getTargetTriple());
+
+ DL = getDataLayout(Mod);
+
+ /* Create JIT execution engine. */
+ std::string ErrorMsg, MCPU;
+ std::vector<std::string> MAttrs;
+ TargetOptions Options;
+
+ setHostAttrs(MCPU, MAttrs, Options);
+
+ EngineBuilder builder(std::move(Owner));
+ builder.setMCPU(MCPU);
+ builder.setMAttrs(MAttrs);
+ builder.setErrorStr(&ErrorMsg);
+ builder.setEngineKind(EngineKind::JIT);
+ builder.setOptLevel(CodeGenOpt::Default);
+ builder.setMCJITMemoryManager(LLEnv->getMemoryManager());
+ builder.setTargetOptions(Options);
+
+ EE = builder.create();
+
+ if (!EE)
+ hqemu_error("%s\n", ErrorMsg.c_str());
+
+ /* Create JIT event listener and link target machine. */
+ Listener = new EventListener(NI);
+ EE->RegisterJITEventListener(Listener);
+
+#if LLVM_USE_INTEL_JITEVENTS
+ IntelJIT = JITEventListener::createIntelJITEventListener();
+ EE->RegisterJITEventListener(IntelJIT);
+#endif
+
+ /* Ask LLVM to reserve basereg. */
+ auto TM = EE->getTargetMachine();
+ auto MII = const_cast<MCInstrInfo *>(TM->getMCInstrInfo());
+ MII->setHQEMUExitAddr((unsigned long)tb_ret_addr);
+
+ dbg() << DEBUG_LLVM << "LLVM MCJIT initialized.\n";
+}
+#endif
+
+void IRFactory::DeleteJIT()
+{
+ EE->UnregisterJITEventListener(Listener);
+#if LLVM_USE_INTEL_JITEVENTS
+ EE->UnregisterJITEventListener(IntelJIT);
+ delete IntelJIT;
+#endif
+ EE->removeModule(Mod);
+ delete Listener;
+ delete EE;
+ delete Mod;
+ EE = nullptr;
+}
+
+Function *IRFactory::ResolveFunction(std::string Name)
+{
+ Function *NF = Mod->getFunction(Name);
+ if(NF)
+ return NF;
+
+ ValueToValueMapTy VMap;
+ Module *InitMod = Translator.getModule();
+ Function *F = InitMod->getFunction(Name);
+ if (!F)
+ IRError("%s: unknown function %s.\n", __func__, Name.c_str());
+
+ NF = Function::Create(cast<FunctionType>(F->getType()->getElementType()),
+ F->getLinkage(), F->getName(), Mod);
+ NF->copyAttributesFrom(F);
+ VMap[F] = NF;
+
+ if (Helpers.find(Name) != Helpers.end() && !F->isDeclaration()) {
+ Function::arg_iterator DestI = NF->arg_begin();
+ for (auto J = F->arg_begin(); J != F->arg_end(); ++J) {
+ DestI->setName(J->getName());
+ VMap[&*J] = &*DestI++;
+ }
+ SmallVector<ReturnInst*, 8> Returns;
+ CloneFunctionInto(NF, F, VMap, /*ModuleLevelChanges=*/true, Returns);
+ }
+
+ ClonedFuncs.insert(NF);
+ return NF;
+}
+
+#else
+void IRFactory::CreateJIT()
+{
+ if (InitOnce)
+ return;
+
+ Context = Translator.getContext();
+ Mod = Translator.getModule();
+ DL = getDataLayout(Mod);
+
+ /* Create JIT execution engine. */
+ std::string ErrorMsg, MCPU;
+ std::vector<std::string> MAttrs;
+ TargetOptions Options;
+
+ setHostAttrs(MCPU, MAttrs, Options);
+
+ EngineBuilder builder(Mod);
+ builder.setMCPU(MCPU);
+ builder.setMAttrs(MAttrs);
+ builder.setAllocateGVsWithCode(false);
+ builder.setJITMemoryManager(LLEnv->getMemoryManager().get());
+ builder.setErrorStr(&ErrorMsg);
+ builder.setEngineKind(EngineKind::JIT);
+ builder.setOptLevel(CodeGenOpt::Default);
+ builder.setTargetOptions(Options);
+
+ EE = builder.create();
+
+ if (!EE)
+ hqemu_error("%s\n", ErrorMsg.c_str());
+
+ /* Create JIT event listener and link target machine. */
+ Listener = new EventListener(NI);
+
+ EE->RegisterJITEventListener(Listener);
+ EE->DisableLazyCompilation(false);
+
+ /* Ask LLVM to reserve basereg. */
+ auto TM = EE->getTargetMachine();
+ auto TRI = const_cast<TargetRegisterInfo*>(TM->getRegisterInfo());
+ TRI->setHQEMUReservedRegs(BaseReg[TCG_AREG0].Name);
+
+ /* Bind addresses to external symbols. */
+ SymbolMap &Symbols = Translator.getSymbols();
+ for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) {
+ std::string Name = I->first;
+ if (!Mod->getNamedValue(Name))
+ continue;
+ EE->updateGlobalMapping(Mod->getNamedValue(Name), (void*)I->second);
+ }
+
+ dbg() << DEBUG_LLVM << "LLVM JIT initialized.\n";
+
+ InitOnce = true;
+}
+
+void IRFactory::DeleteJIT()
+{
+ /* Do nothing with the old JIT. */
+}
+
+Function *IRFactory::ResolveFunction(std::string Name)
+{
+ Function *F = Mod->getFunction(Name);
+ if (!F)
+ IRError("%s: unknown function %s.\n", __func__, Name.c_str());
+ return F;
+}
+#endif
+
+/* Initialize basic types that will be used during IR conversion. */
+void IRFactory::InitializeTypes()
+{
+ VoidTy = Type::getVoidTy(*Context);
+ Int8Ty = IntegerType::get(*Context, 8);
+ Int16Ty = IntegerType::get(*Context, 16);
+ Int32Ty = IntegerType::get(*Context, 32);
+ Int64Ty = IntegerType::get(*Context, 64);
+ Int128Ty = IntegerType::get(*Context, 128);
+
+ IntPtrTy = DL->getIntPtrType(*Context);
+ Int8PtrTy = Type::getInt8PtrTy(*Context, 0);
+ Int16PtrTy = Type::getInt16PtrTy(*Context, 0);
+ Int32PtrTy = Type::getInt32PtrTy(*Context, 0);
+ Int64PtrTy = Type::getInt64PtrTy(*Context, 0);
+
+ FloatTy = Type::getFloatTy(*Context);
+ DoubleTy = Type::getDoubleTy(*Context);
+}
+
+/* Get the function pointer of the IR converion routines. */
+void *IRFactory::getOpcFunc()
+{
+ return OpcFunc;
+}
+
+
+/* Get the CPU pointer.
+ * If the CPU pointer is not in the first block of function F, return null. */
+Instruction *IRFactory::getDefaultCPU(Function &F)
+{
+ if (!CPU)
+ return nullptr;
+ if (!CPU->getParent() || CPU->getParent() != &F.getEntryBlock())
+ return nullptr;
+ return CPU;
+}
+
+static inline std::string getGuestSymbol(target_ulong pc)
+{
+#if defined(CONFIG_USER_ONLY)
+ hqemu::MutexGuard locked(llvm_global_lock);
+
+ std::string Symbol = lookup_symbol(pc);
+ if (Symbol != "")
+ Symbol = "<" + Symbol + ">:";
+ return Symbol;
+#else
+ return "";
+#endif
+}
+
+/* Prepare LLVM Function, initial BasicBlocks and variable declaration. */
+void IRFactory::CreateFunction()
+{
+ target_ulong pc = Builder->getEntryNode()->getGuestPC();
+ std::string Name = getGuestSymbol(pc) +
+ Builder->getPCString(Builder->getEntryNode());
+
+ dbg() << DEBUG_LLVM << "Requested trace info: pc "
+ << format("0x%" PRIx, pc) << " length " << Builder->getNumNodes()
+ << "\n";
+
+ FunctionType *FuncTy = FunctionType::get(IntPtrTy, false);
+ Func = Function::Create(FuncTy, GlobalVariable::ExternalLinkage, Name, Mod);
+ Func->setCallingConv(CallingConv::C);
+ Func->addFnAttr(Attribute::NoUnwind);
+ Func->addFnAttr(Attribute::Naked);
+ Func->addFnAttr("hqemu");
+
+ /* Prepare all basic blocks. */
+ InitBB = BasicBlock::Create(*Context, "init", Func);
+ ExitBB = BasicBlock::Create(*Context, "exit", Func);
+ CurrBB = BasicBlock::Create(*Context, "entry", Func);
+ LastInst = BranchInst::Create(CurrBB, InitBB);
+ new UnreachableInst(*Context, ExitBB);
+
+ /* Setup base register for CPUArchState pointer, and register for
+ * guest_base. */
+ for (int i = 0; i < TCG_TARGET_NB_REGS; i++)
+ BaseReg[i].Base = nullptr;
+
+ BaseRegister &CPUReg = BaseReg[TCG_AREG0];
+ char Constraint[16] = {'\0'};
+ sprintf(Constraint, "={%s}", CPUReg.Name.c_str());
+ auto IA = InlineAsm::get(FunctionType::get(Int8PtrTy, false), "",
+ Constraint, true);
+ CPUReg.Base = CallInst::Create(IA, "cpu", LastInst);
+
+ /* Set special register for guest base if necessary. */
+ GuestBaseReg.Base = CONSTPtr(GUEST_BASE);
+ if (GuestBaseReg.Name != "") {
+ sprintf(Constraint, "={%s}", GuestBaseReg.Name.c_str());
+ IA = InlineAsm::get(FunctionType::get(Int8PtrTy, false), "",
+ Constraint, true);
+ GuestBaseReg.Base = new PtrToIntInst(
+ CallInst::Create(IA, "", LastInst),
+ IntPtrTy, "guest_base", LastInst);
+ }
+
+ CPU = CPUReg.Base;
+ CPUStruct = new BitCastInst(CPU, CPUReg.Ty, "cpu.struct", LastInst);
+ GEPInsertPos = CPUStruct;
+}
+
+/* Prepare an LLVM BasicBlock for a new guest block. */
+void IRFactory::CreateBlock()
+{
+ GraphNode *CurrNode = Builder->getCurrNode();
+ bool isEntryNode = CurrNode == Builder->getEntryNode();
+ std::string pc = Builder->getPCString(CurrNode);
+
+ dbg() << DEBUG_LLVM << " - Process block pc "
+ << format("0x%" PRIx, CurrNode->getGuestPC()) << "\n";
+
+ if (!isEntryNode)
+ CurrBB = BasicBlock::Create(*Context, pc, Func);
+
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+ Builder->setBasicBlock(CurrNode, CurrBB);
+
+ /* Check if the register has legal type. */
+ int NumGlobals = tcg_ctx.nb_globals;
+ int NumTemps = tcg_ctx.nb_temps;
+ for (int i = 0; i < NumTemps; ++i) {
+ TCGTemp *T = &tcg_ctx.temps[i];
+ if (T->type != TCG_TYPE_I32 && T->type != TCG_TYPE_I64)
+ hqemu_error("unsupported register type.\n");
+ }
+
+ /* Initialize global registers. */
+ for (int i = 0; i < NumGlobals; ++i) {
+ TCGTemp *T = &tcg_ctx.temps[i];
+ int State = (T->fixed_reg) ? Register::STATE_REV | Register::STATE_MEM :
+ Register::STATE_MEM;
+ int Size = (T->type == TCG_TYPE_I32) ? 32 : 64;
+ Type *Ty = (T->type == TCG_TYPE_I32) ? Int32Ty : Int64Ty;
+ Reg[i].reset(State, Size, Ty);
+ }
+
+ /* Initialize temporary registers. */
+ for (int i = NumGlobals; i < NumTemps; ++i) {
+ TCGTemp *T = &tcg_ctx.temps[i];
+ int State = (T->temp_local) ? Register::STATE_LOC :
+ Register::STATE_TMP;
+ int Size = (T->type == TCG_TYPE_I32) ? 32 : 64;
+ Type *Ty = (T->type == TCG_TYPE_I32) ? Int32Ty : Int64Ty;
+ Reg[i].reset(State, Size, Ty);
+ }
+
+ Labels.clear();
+
+#ifdef VERIFY_TB
+ Function *F = ResolveFunction("helper_verify_tb");
+ SmallVector<Value *, 4> Params;
+ Params.push_back(CPUStruct);
+ Params.push_back(CONST32(CurrNode->getTB()->id));
+ CallInst *CI = CallInst::Create(F, Params, "", LastInst);
+ MF->setConst(CI);
+#endif
+}
+
+
+/* Wrapper function to set an unconditional branch. */
+void IRFactory::setSuccessor(BranchInst *BI, BasicBlock *BB)
+{
+ BI->setSuccessor(0, BB);
+}
+
+/* Determine whether we should inline a helper function or not. */
+int IRFactory::AnalyzeInlineCost(CallSite CS)
+{
+ Function *Callee = CS.getCalledFunction();
+ HelperInfo *Helper = Helpers[Callee->getName()];
+ int InlineCost = INLINE_THRESHOLD - Helper->Metrics.NumInsts;
+ unsigned ArgNo = 0;
+
+ if (Helper->Metrics.NumInsts <= INLINE_INSTCOUNT)
+ return 1;
+
+ InlineCost *= InlineConstants::InstrCost;
+ for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
+ I != E; ++I, ++ArgNo) {
+ InlineCost -= InlineConstants::InstrCost;
+ if (isa<AllocaInst>(I))
+ InlineCost += Helper->ArgumentWeights[ArgNo].AllocaWeight;
+ else if (isa<Constant>(I))
+ InlineCost += Helper->ArgumentWeights[ArgNo].ConstantWeight;
+ }
+
+ return InlineCost;
+}
+
+
+/* Perform helper function inlining. */
+void IRFactory::ProcessInline()
+{
+ while (!InlineCalls.empty()) {
+ CallInst *CI = static_cast<CallInst *>(InlineCalls.back());
+ InlineCalls.pop_back();
+ InlineFunc(CI);
+ }
+}
+
+void IRFactory::VerifyFunction(Function &F)
+{
+ if (DM.getDebugMode() & DEBUG_VERIFY)
+ verifyFunction(F, &DM.debug());
+}
+
+/* Format function to a legal format and inline calls. Be sure to make the
+ * function in a well form before doing any furthur optimization (i.e. inlining
+ * calls). Otherwise, the optimization may fail or the result may be wrong. */
+void IRFactory::PreProcess()
+{
+ dbg() << DEBUG_LLVM << __func__ << " entered.\n";
+
+ ProcessErase(toErase);
+
+ /* Insert terminator instruction to basic blocks that branch to ExitBB.
+ * This could happen when the last TCG opc is a call instruction. */
+ for (auto PI = pred_begin(ExitBB), PE = pred_end(ExitBB); PI != PE; PI++) {
+ Instruction *InsertPos = (*PI)->getTerminator();
+ new UnreachableInst(*Context, InsertPos);
+ toErase.push_back(InsertPos);
+ }
+ ProcessErase(toErase);
+ ExitBB->eraseFromParent();
+
+ /* Remove instructions after indirect branches. */
+ std::set<Instruction *> AfterIB;
+ for (unsigned i = 0, e = IndirectBrs.size(); i != e; ++i) {
+ BasicBlock *BB = IndirectBrs[i]->getParent();
+ for (auto I = ++BasicBlock::iterator(IndirectBrs[i]), E = BB->end();
+ I != E; ++I)
+ AfterIB.insert(&*I);
+ }
+ for (auto I = AfterIB.begin(), E = AfterIB.end(); I != E; ++I)
+ toErase.push_back(*I);
+ ProcessErase(toErase);
+
+ /* Sink blocks to the end. */
+ Function::iterator InsertPos = Func->end();
+ Function::BasicBlockListType &Blocks = Func->getBasicBlockList();
+ for (unsigned i = 0, e = toSink.size(); i != e; ++i) {
+ if (&*InsertPos == toSink[i])
+ continue;
+ Blocks.splice(InsertPos, Blocks, toSink[i]);
+ }
+
+ VerifyFunction(*Func);
+
+ /* Inline helper functions. */
+ ProcessInline();
+
+ SmallVector<std::pair<const BasicBlock*,const BasicBlock*>, 32> BackEdges;
+ FindFunctionBackedges(*Func, BackEdges);
+
+ TraceInfo *Trace = Builder->getTrace();
+ Trace->NumLoop = BackEdges.size();
+ dbg() << DEBUG_LLVM << __func__ << ": trace formation with pc "
+ << format("0x%" PRIx, Trace->getEntryPC())
+ << " length " << Trace->getNumBlock()
+ << " is_loop " << (Trace->NumLoop ? true : false) << "\n";
+
+#if 1 || defined(CONFIG_SOFTMMU)
+ if (Trace->NumLoop) {
+ intptr_t Offset = offsetof(CPUState, tcg_exit_req) - ENV_OFFSET;
+ Value *ExitRequestPtr = GetElementPtrInst::CreateInBounds(CPU,
+ CONSTPtr(Offset),
+ "", InitBB->getTerminator());
+ ExitRequestPtr = new BitCastInst(ExitRequestPtr, Int32PtrTy,
+ "tcg_exit_req",
+ InitBB->getTerminator());
+
+ /* Create the exit stub. */
+ for (unsigned i = 0, e = BackEdges.size(); i != e; ++i) {
+ BasicBlock *TCGExitBB = BasicBlock::Create(*Context, "exit", Func);
+ LastInst = BranchInst::Create(TCGExitBB, TCGExitBB);
+ StoreInst *SI = new StoreInst(CONST32(0), ExitRequestPtr, true, LastInst);
+ InsertExit(0);
+ LastInst->eraseFromParent();
+
+ MF->setExit(SI);
+
+ auto BackEdgeBB = const_cast<BasicBlock*>(BackEdges[i].first);
+ auto LoopHeader = const_cast<BasicBlock*>(BackEdges[i].second);
+ auto BI = const_cast<TerminatorInst *>(BackEdgeBB->getTerminator());
+
+ toErase.push_back(BI);
+
+ Value *ExitRequest = new LoadInst(ExitRequestPtr, "", true, BI);
+ Value *Cond = new ICmpInst(BI, ICmpInst::ICMP_EQ, ExitRequest,
+ CONST32(0), "");
+ BI = BranchInst::Create(LoopHeader, TCGExitBB, Cond, BI);
+ BI->getParent()->setName("loopback");
+ MF->setLoop(BI);
+ }
+ }
+#else
+ if (Trace->NumLoop) {
+ for (unsigned i = 0, e = BackEdges.size(); i != e; ++i) {
+ auto BackEdgeBB = const_cast<BasicBlock*>(BackEdges[i].first);
+ auto BI = const_cast<TerminatorInst *>(BackEdgeBB->getTerminator());
+ BI->getParent()->setName("loopback");
+ MF->setLoop(BI);
+
+ for (auto BI = BackEdgeBB->begin(), BE = BackEdgeBB->end(); BI != BE; ++BI) {
+ if (auto SI = dyn_cast<StoreInst>(BI)) {
+ intptr_t Off = 0;
+ Value *Base = getBaseWithConstantOffset(DL, getPointerOperand(SI), Off);
+ if (Base == CPU && isStateOfPC(Off))
+ toErase.push_back(SI);
+ }
+ }
+ }
+ }
+#endif
+
+ ProcessErase(toErase);
+
+ if (DM.getDebugMode() & DEBUG_IR) {
+ hqemu::MutexGuard locked(llvm_debug_lock);
+ Func->print(DM.debug());
+ }
+}
+
+void IRFactory::InitializeLLVMPasses(legacy::FunctionPassManager *FPM)
+{
+ auto TM = EE->getTargetMachine();
+#if defined(LLVM_V35)
+ TM->addAnalysisPasses(*FPM);
+ FPM->add(new DataLayoutPass(Mod));
+ FPM->add(createBasicTargetTransformInfoPass(TM));
+#else
+ PassRegistry &PassReg = *PassRegistry::getPassRegistry();
+ initializeTargetTransformInfoWrapperPassPass(PassReg);
+
+ FPM->add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
+#endif
+}
+
+void IRFactory::Optimize()
+{
+#define addPass(PM, P) do { PM->add(P); } while(0)
+#define addPassOptional(PM, P, Disable) \
+ do { \
+ if (!Disable) PM->add(P); \
+ } while(0)
+
+#if defined(ENABLE_PASSES)
+ if (runPasses) {
+ legacy::FunctionPassManager *FPM = new legacy::FunctionPassManager(Mod);
+
+ InitializeLLVMPasses(FPM);
+
+ addPass(FPM, createProfileExec(this));
+ addPass(FPM, createCombineGuestMemory(this));
+ addPass(FPM, createCombineZExtTrunc());
+ addPassOptional(FPM, createStateMappingPass(this), DisableStateMapping);
+ addPass(FPM, createPromoteMemoryToRegisterPass());
+ addPass(FPM, createCombineCasts(this));
+ addPassOptional(FPM, createSimplifyPointer(this), !EnableSimplifyPointer);
+ addPass(FPM, createAggressiveDCEPass());
+ addPass(FPM, createCFGSimplificationPass());
+ addPass(FPM, createInstructionCombiningPass());
+ addPass(FPM, createRedundantStateElimination(this));
+ addPass(FPM, createCombineCasts(this));
+
+ FPM->run(*Func);
+
+ delete FPM;
+ }
+#endif
+
+#undef addPass
+#undef addPassOptional
+}
+
+
+/* Legalize LLVM IR after running the pre-defined passes. */
+void IRFactory::PostProcess()
+{
+ dbg() << DEBUG_LLVM << __func__ << " entered.\n";
+
+#if defined(ENABLE_MCJIT)
+ for (auto I = ClonedFuncs.begin(), E = ClonedFuncs.end(); I != E; ++I) {
+ Function *F = *I;
+ if (!F->isDeclaration())
+ F->removeFromParent();
+ }
+ /* Bind addresses to external symbols. */
+ SymbolMap &Symbols = Translator.getSymbols();
+ for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) {
+ std::string Name = I->first;
+ if (!Mod->getNamedValue(Name))
+ continue;
+ EE->updateGlobalMapping(Mod->getNamedValue(Name), (void*)I->second);
+ }
+#endif
+
+ if (DM.getDebugMode() & DEBUG_IR_OPT) {
+ hqemu::MutexGuard locked(llvm_debug_lock);
+ Func->print(DM.debug());
+ }
+}
+
+/* Legalize LLVM IR after running the pre-defined passes. */
+void IRFactory::FinalizeObject()
+{
+ dbg() << DEBUG_LLVM << __func__ << " entered.\n";
+
+ uintptr_t Code = (uintptr_t)NI.Code;
+ uint32_t Size = NI.Size;
+
+#if defined(ENABLE_MCJIT)
+ for (unsigned i = 0, e = NI.Patches.size(); i != e; ++i) {
+ NotifyInfo::PatchInfo &Patch = NI.Patches[i];
+ uintptr_t Addr = Patch.Addr;
+ code_ostream OS(Addr);
+
+ /* If the address to patch is outside this code region, skip this
+ * invalid patch point. Actually this should not happen, but LLVM v35
+ * seems to report such invalid address. */
+ if (Addr >= Code + Size)
+ continue;
+ if (Patch.Type == PATCH_EXIT_TB) {
+#if defined(LLVM_V35) && defined(TCG_TARGET_I386)
+ EmitByte(OS, 0xE9);
+ EmitConstant(OS, (uintptr_t)tb_ret_addr - Addr - 5, 4);
+#endif
+ } else if (Patch.Type == PATCH_TRACE_BLOCK_CHAINING) {
+#if defined(TCG_TARGET_I386)
+ unsigned NumSkip = 3 - Addr % 4;
+ OS.Skip(NumSkip);
+ EmitByte(OS, 0xE9);
+ EmitConstant(OS, 0, 4);
+ NI.ChainSlot[Patch.Idx].Addr = Addr + NumSkip;
+#elif defined(TCG_TARGET_PPC64)
+ unsigned NumSkip = 0;
+ if (Addr & 7)
+ NumSkip = 4;
+ OS.Skip(NumSkip);
+ EmitConstant(OS, 0x48000000 | (16 & 0x3fffffc), 4); /* b .+16 */
+ EmitConstant(OS, 0x60000000, 4); /* nop */
+ EmitConstant(OS, 0x7C0903A6 | (12 << 21), 4); /* mtctr r12 */
+ EmitConstant(OS, 0x4E800420, 4); /* bctr */
+ NI.ChainSlot[Patch.Idx].Addr = Addr + NumSkip;
+#else
+ NI.ChainSlot[Patch.Idx].Addr = Addr;
+#endif
+ }
+ }
+#endif
+
+ /* Flush instruction cache */
+ flush_icache_range(Code, Code + Size);
+
+ if (DM.getDebugMode() & DEBUG_OUTASM) {
+ hqemu::MutexGuard locked(llvm_debug_lock);
+ if (HostDisAsm)
+ HostDisAsm->PrintOutAsm((uint64_t)Code, (uint64_t)Size);
+ else {
+ auto &OS = DM.debug();
+ OS << "\nOUT: [size=" << Size << "]\n";
+ disas(stderr, (void *)Code, Size);
+ OS << "\n";
+ }
+ }
+}
+
+/* Start the LLVM JIT compilation. */
+void IRFactory::Compile()
+{
+ dbg() << DEBUG_LLVM
+ << "Translator " << Translator.getID() << " starts compiling...\n";
+
+ /* Run optimization passes. */
+ PreProcess();
+ Optimize();
+ PostProcess();
+
+ VerifyFunction(*Func);
+
+ /* JIT. */
+ NI.Func = Func;
+ EE->getPointerToFunction(Func);
+ EE->finalizeObject();
+
+ FinalizeObject();
+
+ dbg() << DEBUG_LLVM << __func__ << ": done.\n";
+}
+
+PointerType *IRFactory::getPointerTy(int Size, unsigned AS)
+{
+ switch (Size) {
+ case 32: return Type::getInt32PtrTy(*Context, AS);
+ case 64: return Type::getInt64PtrTy(*Context, AS);
+ case 16: return Type::getInt16PtrTy(*Context, AS);
+ case 8: return Type::getInt8PtrTy(*Context, AS);
+ default:
+ IRError("%s: invalid bit type %d.\n", __func__, Size);
+ }
+ return nullptr;
+}
+
+Value *IRFactory::getExtendValue(Value *V, Type *Ty, int opc)
+{
+ int OldSize = DL->getTypeSizeInBits(V->getType());
+ int NewSize = DL->getTypeSizeInBits(Ty);
+
+ if (OldSize > NewSize)
+ IRError("%s: invalid size old=%d new=%d\n", __func__, OldSize, NewSize);
+ if (OldSize == NewSize)
+ return V;
+
+ if (opc & MO_SIGN)
+ return SEXT(V, Ty);
+ return ZEXT(V, Ty);
+}
+
+Value *IRFactory::getTruncValue(Value *V, int opc)
+{
+ int OldSize = DL->getTypeSizeInBits(V->getType());
+ int NewSize = getSizeInBits(opc);
+
+ if (OldSize < NewSize)
+ IRError("%s: invalid size old=%d new=%d\n", __func__, OldSize, NewSize);
+ if (OldSize == NewSize)
+ return V;
+
+ Type *Ty = Type::getIntNTy(*Context, NewSize);
+ return TRUNC(V, Ty);
+}
+
+Value *IRFactory::ConvertEndian(Value *V, int opc)
+{
+#ifdef NEED_BSWAP
+ switch (opc & MO_SIZE) {
+ case MO_8: return V;
+ case MO_16: return BSWAP16(V);
+ case MO_32: return BSWAP32(V);
+ case MO_64: return BSWAP64(V);
+ default:
+ IRError("%s: invalid size (opc=%d)\n", __func__, opc);
+ break;
+ }
+ return V;
+#else
+ return V;
+#endif
+}
+
+Value *IRFactory::CreateBSwap(Type *Ty, Value *V, Instruction *InsertPos)
+{
+ SmallVector<Value *, 4> Params;
+ Type *Tys[] = { Ty };
+
+ Function *Fn = Intrinsic::getDeclaration(Mod, Intrinsic::bswap, Tys);
+ Params.push_back(V);
+ return CallInst::Create(Fn, Params, "", InsertPos);
+}
+
+Value *IRFactory::ConvertCPUType(Function *F, int Idx, Instruction *InsertPos)
+{
+ Type *ParamTy = F->getFunctionType()->getParamType(Idx);
+ if (CPUStruct->getType() != ParamTy)
+ return new BitCastInst(CPU, ParamTy, "", InsertPos);
+ return CPUStruct;
+}
+
+Value *IRFactory::ConvertCPUType(Function *F, int Idx, BasicBlock *InsertPos)
+{
+ Type *ParamTy = F->getFunctionType()->getParamType(Idx);
+ if (CPUStruct->getType() != ParamTy)
+ return new BitCastInst(CPU, ParamTy, "", InsertPos);
+ return CPUStruct;
+}
+
+/* Return true if the offset is for the state of PC. */
+bool IRFactory::isStateOfPC(intptr_t Off)
+{
+ intptr_t IPOffset;
+#if defined(TARGET_ALPHA)
+ IPOffset = offsetof(CPUArchState, pc);
+#elif defined(TARGET_AARCH64)
+ IPOffset = offsetof(CPUArchState, pc);
+#elif defined(TARGET_ARM)
+ IPOffset = offsetof(CPUArchState, regs[15]);
+#elif defined(TARGET_CRIS)
+ IPOffset = offsetof(CPUArchState, pc);
+#elif defined(TARGET_I386)
+ IPOffset = offsetof(CPUArchState, eip);
+#elif defined(TARGET_M68K)
+ IPOffset = offsetof(CPUArchState, pc);
+#elif defined(TARGET_MICROBLAZE)
+ IPOffset = offsetof(CPUArchState, sregs[0]);
+#elif defined(TARGET_MIPS)
+ IPOffset = offsetof(CPUArchState, active_tc.PC);
+#elif defined(TARGET_PPC)
+ IPOffset = offsetof(CPUArchState, nip);
+#elif defined(TARGET_SH4)
+ IPOffset = offsetof(CPUArchState, pc);
+#elif defined(TARGET_SPARC)
+ intptr_t IPOffset2;
+ IPOffset = offsetof(CPUArchState, pc);
+ IPOffset2 = offsetof(CPUArchState, npc);
+#else
+#error "unsupported processor type"
+#endif
+
+#if defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_AARCH64) || \
+ defined(TARGET_CRIS) || defined(TARGET_I386) || defined(TARGET_M68K) || \
+ defined(TARGET_MICROBLAZE) || defined(TARGET_MIPS) || defined(TARGET_PPC) || \
+ defined(TARGET_SH4)
+ return (Off >= IPOffset && Off < IPOffset + TARGET_LONG_SIZE);
+#elif defined(TARGET_SPARC)
+ return ((Off >= IPOffset && Off < IPOffset + TARGET_LONG_SIZE) ||
+ (Off >= IPOffset2 && Off < IPOffset2 + TARGET_LONG_SIZE));
+#endif
+}
+
+/* Trace building requires store IP instruction to link basic blocks.
+ * But in some archirecture, IP is promoted to register and we need to
+ * regenerate the store IP instruction. */
+void IRFactory::CreateStorePC(Instruction *InsertPos)
+{
+ for (int i = 0, e = tcg_ctx.nb_globals; i != e; ++i) {
+ Register &reg = Reg[i];
+ if (reg.isReg() && reg.isDirty()) {
+ if (isStateOfPC(reg.Off)) {
+ StoreState(reg, InsertPos);
+ reg.Demote();
+ }
+ }
+ }
+}
+
+/* Store dirty states back to CPUArchState in memory. */
+void IRFactory::SaveGlobals(int level, Instruction *InsertPos)
+{
+ if (level == COHERENCE_NONE)
+ return;
+
+ int NumGlobals = tcg_ctx.nb_globals;
+ int NumTemps = tcg_ctx.nb_temps;
+ for (int i = 0; i < NumGlobals; ++i) {
+ Register &reg = Reg[i];
+ if (reg.isReg() && reg.isDirty())
+ StoreState(reg, InsertPos);
+ reg.Demote();
+ }
+
+ if (level == COHERENCE_GLOBAL)
+ return;
+
+ /* Store local registers to stack. */
+ for (int i = NumGlobals; i < NumTemps; ++i) {
+ Register &reg = Reg[i];
+ if (reg.isReg() && reg.isLocal() && reg.isDirty())
+ StoreState(reg, InsertPos);
+ reg.Demote();
+ }
+}
+
+/* Get or insert the pointer to the CPU register in the AddrCache. */
+Value *IRFactory::StatePointer(Register &reg)
+{
+ intptr_t Off = reg.Off;
+ PointerType *PTy = (reg.Size == 32) ? Int32PtrTy : Int64PtrTy;
+ std::pair<intptr_t, Type *> Key(Off, PTy);
+ if (StatePtr.find(Key) == StatePtr.end()) {
+ std::string Name = isStateOfPC(Off) ? "pc" : reg.Name;
+ auto GEP = GetElementPtrInst::CreateInBounds(BaseReg[reg.Base].Base,
+ CONSTPtr(Off), "", GEPInsertPos);
+ StatePtr[Key] = new BitCastInst(GEP, PTy, Name, InitBB->getTerminator());
+ }
+ return StatePtr[Key];
+}
+
+Value *IRFactory::StatePointer(Register &reg, intptr_t Off, Type *PTy)
+{
+ if (!reg.isRev())
+ IRError("%s: internal error.\n", __func__);
+
+ std::pair<intptr_t, Type *> Key(Off, PTy);
+ if (StatePtr.find(Key) == StatePtr.end()) {
+ std::string Name = isStateOfPC(Off) ? "pc" : "";
+ auto GEP = GetElementPtrInst::CreateInBounds(BaseReg[reg.Base].Base,
+ CONSTPtr(Off), "", GEPInsertPos);
+ StatePtr[Key] = new BitCastInst(GEP, PTy, Name, InitBB->getTerminator());
+ }
+ return StatePtr[Key];
+}
+
+/* Retrieve value from CPUArchState. */
+Value *IRFactory::LoadState(Register &reg)
+{
+ if (reg.isRev())
+ return BaseReg[reg.Base].Base;
+ if (reg.isAlias())
+ return LoadState(reg.getAlias());
+ if (reg.isReg())
+ return reg.getData();
+ if (reg.isLocal()) {
+ if (!reg.AI)
+ reg.AI = CreateAlloca(reg.Ty, 0, "loc", InitBB->getTerminator());
+ return new LoadInst(reg.AI, "", false, LastInst);
+ }
+
+ /* If we go here, the state is not loaded into a LLVM virtual register.
+ * Load it from CPUArchState. */
+ Value *V = new LoadInst(StatePointer(reg), "", false, LastInst);
+ reg.setData(V);
+
+ return V;
+}
+
+void IRFactory::StoreState(Register &reg, Instruction *InsertPos)
+{
+#ifdef ASSERT
+ int Size = DL->getTypeSizeInBits(reg.getData()->getType());
+ if (Size != reg.Size)
+ IRError("%s: internal error\n", __func__);
+#endif
+ if (reg.isRev())
+ IRError("%s: fatal error\n", __func__);
+ if (reg.isLocal()) {
+ if (!reg.AI)
+ reg.AI = CreateAlloca(reg.Ty, 0, "loc", InitBB->getTerminator());
+ new StoreInst(reg.getData(), reg.AI, false, InsertPos);
+ } else {
+ bool Volatile = isStateOfPC(reg.Off);
+ new StoreInst(reg.getData(), StatePointer(reg), Volatile, InsertPos);
+ }
+}
+
+
+/*
+ * TCG opcode to LLVM IR translation functions.
+ */
+void IRFactory::op_hotpatch(const TCGArg *args)
+{
+ IRDebug(INDEX_op_hotpatch);
+}
+
+void IRFactory::op_annotate(const TCGArg *args)
+{
+ IRDebug(INDEX_op_annotate);
+
+ uint32_t Annotation = *args;
+ if (Annotation == A_SetCC) {
+ if (LastInst && LastInst != &*LastInst->getParent()->begin())
+ MF->setCondition(&*--BasicBlock::iterator(LastInst));
+ } else if (Annotation == A_NoSIMDization) {
+ Builder->addAttribute(A_NoSIMDization);
+ }
+}
+
+void IRFactory::op_jmp(const TCGArg *args)
+{
+ IRDebug(INDEX_op_jmp);
+
+ Register &In = Reg[args[0]];
+ Value *InData = LoadState(In);
+
+ SaveGlobals(COHERENCE_ALL, LastInst);
+ if (!InData->getType()->isPointerTy())
+ InData = ITP8(InData);
+
+ IndirectBrInst *IB = IndirectBrInst::Create(InData, 1, LastInst);
+ MF->setExit(IB);
+}
+
+/*
+ * op_discard()
+ * args[0]: In
+ */
+void IRFactory::op_discard(const TCGArg *args)
+{
+ IRDebug(INDEX_op_discard);
+ Register &In = Reg[args[0]];
+ if (In.isReg())
+ In.Demote();
+}
+
+/*
+ * op_set_label()
+ * args[0]: Label number
+ */
+void IRFactory::op_set_label(const TCGArg *args)
+{
+ IRDebug(INDEX_op_set_label);
+
+ SaveGlobals(COHERENCE_ALL, LastInst);
+
+ TCGArg label = args[0];
+ if (Labels.find(label) == Labels.end())
+ Labels[label] = BasicBlock::Create(*Context, "true_dest", Func);
+
+ CurrBB = Labels[label];
+ if (LastInst) {
+ if (LastInst != &*LastInst->getParent()->begin() &&
+ isa<IndirectBrInst>(--BasicBlock::iterator(LastInst)))
+ LastInst->eraseFromParent();
+ else
+ setSuccessor(LastInst, CurrBB);
+ }
+
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+}
+
+/*
+ * op_call()
+ * args[0] : [nb_oargs:16][nb_iargs:16]
+ * args[1~#nb_oargs] : out args
+ * args[1+#nb_oargs~#nb_iargs-2] : function parameters
+ * args[1+#nb_oargs+#nb_iargs-1] : function address
+ * args[1+#nb_oargs+#nb_iargs] : flags
+ */
+void IRFactory::op_call(const TCGArg *args)
+{
+ IRDebug(INDEX_op_call);
+
+ TCGOp * const op = NI.Op;
+ int nb_oargs = op->callo;
+ int nb_iargs = op->calli;
+ int nb_params = nb_iargs;
+ tcg_insn_unit *func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs];
+ int flags = args[nb_oargs + nb_iargs + 1];
+ SmallVector<Value *, 4> Params;
+
+ /* If the called function is an illegal helper, skip this trace. */
+ if (isIllegalHelper((void *)func_addr)) {
+ Builder->Abort();
+ return;
+ }
+
+ /* Get function declaration from LLVM module. */
+ TCGHelperMap &TCGHelpers = Translator.getTCGHelpers();
+ if (TCGHelpers.find((uintptr_t)func_addr) == TCGHelpers.end())
+ IRError("%s: cannot resolve funtion.\n", __func__);
+
+ std::string FName = TCGHelpers[(uintptr_t)func_addr];
+ Function *F = ResolveFunction(FName);
+
+ std::set<std::string> &ConstHelpers = Translator.getConstHelpers();
+ if (ConstHelpers.find(FName) != ConstHelpers.end())
+ flags |= TCG_CALL_NO_READ_GLOBALS;
+
+ /* Package the function parameters.
+ NOTE: There are situations where the numbers of given arguments
+ are greater than the *real* function parameters. Ex:
+ declare void foo(int64, int64);
+ and
+ call foo(int32, int32, int32, int32);
+ */
+ int real_nb_params = F->getFunctionType()->getNumParams();
+ if (nb_params == real_nb_params) {
+ for (int i = 0; i < real_nb_params; ++i) {
+ Type *ParamTy = F->getFunctionType()->getParamType(i);
+ Register &In = Reg[args[nb_oargs + i]];
+ Value *InData = LoadState(In);
+
+ size_t real_size = DL->getTypeSizeInBits(ParamTy);
+ size_t size = DL->getTypeSizeInBits(InData->getType());
+
+ if (ParamTy->isPointerTy() && !InData->getType()->isPointerTy())
+ InData = ITP8(InData);
+ else if (real_size < size)
+ InData = TRUNC(InData, IntegerType::get(*Context, real_size));
+
+ if (InData->getType() != ParamTy)
+ InData = new BitCastInst(InData, ParamTy, "", LastInst);
+ Params.push_back(InData);
+ }
+ } else {
+ int idx = 0;
+ for (int i = 0; i < real_nb_params; ++i) {
+ Value *V = nullptr;
+ Type *ParamTy = F->getFunctionType()->getParamType(i);
+ size_t real_size = DL->getTypeSizeInBits(ParamTy);
+ size_t size, remain = real_size;
+
+next:
+ Register &In = Reg[args[nb_oargs + idx]];
+ Value *InData = LoadState(In);
+
+ size = DL->getTypeSizeInBits(InData->getType());
+ if (size == real_size) {
+ if (InData->getType() != ParamTy)
+ InData = new BitCastInst(InData, ParamTy, "", LastInst);
+ Params.push_back(InData);
+ idx++;
+ } else {
+ if (remain == real_size)
+ V = ZEXT(InData, IntegerType::get(*Context, real_size));
+ else {
+ InData = ZEXT(InData, ParamTy);
+ InData = SHL(InData, ConstantInt::get(ParamTy, real_size-remain));
+ V = OR(V, InData);
+ }
+
+ if (remain < size)
+ IRError("%s: fatal error.\n", __func__);
+
+ remain -= size;
+ idx++;
+
+ if (remain)
+ goto next;
+
+ Params.push_back(V);
+ }
+ }
+
+ if (idx != nb_params)
+ IRError("%s: num params not matched.\n", __func__);
+ }
+
+
+ /* Save global registers if this function is not TCG constant function.
+ Otherwise, mark this call instruction for state mapping use.
+ The rules can be found in tcg_reg_alloc_call() in tcg/tcg.c */
+ if (!(flags & TCG_CALL_NO_READ_GLOBALS))
+ SaveGlobals(COHERENCE_GLOBAL, LastInst);
+
+ /* handle COREMU's lightweight memory transaction helper */
+ if (isLMTFunction(FName)) {
+ uint32_t Idx = NI.setRestorePoint();
+ Value *ResVal = GetElementPtrInst::CreateInBounds(CPU,
+ CONSTPtr(offsetof(CPUArchState, restore_val)), "", LastInst);
+ ResVal = new BitCastInst(ResVal, Int32PtrTy, "", LastInst);
+ new StoreInst(CONST32(Idx), ResVal, true, LastInst);
+ }
+
+ CallInst *CI = CallInst::Create(F, Params, "", LastInst);
+
+ if (flags & TCG_CALL_NO_READ_GLOBALS)
+ MF->setConst(CI);
+
+ /* Determine if this function can be inlined. */
+ if (Helpers.find(FName) != Helpers.end()) {
+ bool MustInline = false;
+ HelperInfo *Helper = Helpers[FName];
+ if (AnalyzeInlineCost(CallSite(CI)) > 0) {
+ MustInline = true;
+ InlineCalls.push_back(CI);
+ }
+
+ if (!MustInline) {
+ Function *NoInlineF = ResolveFunction(Helper->FuncNoInline->getName());
+ CI->setCalledFunction(NoInlineF);
+ }
+ }
+
+ /* Format the return value.
+ NOTE: There are situations where the return value is split and
+ is used by different instructions. Ex:
+ int64 ret = call foo();
+ ... = opcode ret[0..31];
+ ... = opcode ret[32..64];
+ */
+ if (nb_oargs == 1) {
+ Register &Out = Reg[args[0]];
+ Out.setData(CI, true);
+ } else if (nb_oargs > 1) {
+ Value *V = CI;
+ size_t size = DL->getTypeSizeInBits(F->getReturnType());
+ size_t subsize = size / nb_oargs;
+ for (int i = 0; i < nb_oargs; ++i) {
+ Register &Out = Reg[args[i]];
+ Value *OutData = TRUNC(V, IntegerType::get(*Context, subsize));
+ Out.setData(OutData, true);
+ if (i != nb_oargs - 1)
+ V = LSHR(V, ConstantInt::get(IntegerType::get(*Context, size), subsize));
+ }
+ }
+}
+
+/*
+ * op_br()
+ * args[0]: Label number
+ */
+void IRFactory::op_br(const TCGArg *args)
+{
+ IRDebug(INDEX_op_br);
+
+ SaveGlobals(COHERENCE_ALL, LastInst);
+
+ TCGArg label = args[0];
+ if (Labels.find(label) == Labels.end())
+ Labels[label] = BasicBlock::Create(*Context, "direct_jump_tb", Func);
+
+ setSuccessor(LastInst, Labels[label]);
+ LastInst = nullptr;
+}
+
+/*
+ * op_mov_i32()
+ * args[0]: Out
+ * args[1]: In
+ */
+void IRFactory::op_mov_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_mov_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32);
+
+ Value *InData = LoadState(In);
+
+ size_t Size = DL->getTypeSizeInBits(InData->getType());
+ if (Size != 32)
+ InData = TRUNC32(InData);
+
+ Out.setData(InData, true);
+}
+
+/*
+ * op_movi_i32()
+ * args[0]: Out
+ * args[1]: In (const value)
+ */
+void IRFactory::op_movi_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_movi_i32);
+
+ Register &Out = Reg[args[0]];
+
+ AssertType(Out.Size == 32);
+
+ Out.setData(CONST32(args[1]), true);
+}
+
+static inline CmpInst::Predicate getPred(const TCGArg cond)
+{
+ CmpInst::Predicate pred = ICmpInst::BAD_ICMP_PREDICATE;
+ switch (cond) {
+ case TCG_COND_EQ: pred = ICmpInst::ICMP_EQ; break;
+ case TCG_COND_NE: pred = ICmpInst::ICMP_NE; break;
+ case TCG_COND_LT: pred = ICmpInst::ICMP_SLT; break;
+ case TCG_COND_GE: pred = ICmpInst::ICMP_SGE; break;
+ case TCG_COND_LE: pred = ICmpInst::ICMP_SLE; break;
+ case TCG_COND_GT: pred = ICmpInst::ICMP_SGT; break;
+ /* unsigned */
+ case TCG_COND_LTU: pred = ICmpInst::ICMP_ULT; break;
+ case TCG_COND_GEU: pred = ICmpInst::ICMP_UGE; break;
+ case TCG_COND_LEU: pred = ICmpInst::ICMP_ULE; break;
+ case TCG_COND_GTU: pred = ICmpInst::ICMP_UGT; break;
+ default:
+ IRError("%s - unsupported predicate\n", __func__);
+ }
+ return pred;
+}
+
+/*
+ * op_setcond_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ * args[3]: In3 (condition code)
+ */
+void IRFactory::op_setcond_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_setcond_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+ CmpInst::Predicate Pred = getPred(args[3]);
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = ICMP(InData1, InData2, Pred);
+ OutData = ZEXT32(OutData);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_movcond_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ * args[3]: In3
+ * args[4]: In4
+ * args[5]: In5 (condition code)
+ */
+void IRFactory::op_movcond_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_movcond_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+ Register &In3 = Reg[args[3]];
+ Register &In4 = Reg[args[4]];
+ CmpInst::Predicate Pred = getPred(args[5]);
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32 &&
+ In3.Size == 32 && In4.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = LoadState(In3);
+ Value *InData4 = LoadState(In4);
+ Value *Cond = ICMP(InData1, InData2, Pred);
+ Value *OutData = SelectInst::Create(Cond, InData3, InData4, "", LastInst);
+ Out.setData(OutData, true);
+}
+
+/* load/store */
+/*
+ * op_ld8u_i32()
+ * args[0]: Out (ret)
+ * args[1]: In1 (addr)
+ * args[2]: In2 (offset)
+ */
+void IRFactory::op_ld8u_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld8u_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 32);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = ZEXT32(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ld8s_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld8s_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 32);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = SEXT32(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ld16u_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld16u_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 32);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = CASTPTR16(InData);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = ZEXT32(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ld16s_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld16s_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 32);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = CASTPTR16(InData);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = SEXT32(InData);
+ Out.setData(InData, true);
+}
+
+/*
+ * op_ld_i32()
+ * args[0]: Out (ret)
+ * args[1]: In1 (addr)
+ * args[2]: In2 (offset)
+ */
+void IRFactory::op_ld_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 32);
+
+ Value *InData;
+ if (In.isRev()) {
+ InData = StatePointer(In, Off, Int32PtrTy);
+ InData = new LoadInst(InData, "", false, LastInst);
+ if (isStateOfPC(Off))
+ static_cast<LoadInst*>(InData)->setVolatile(true);
+ } else {
+ InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = CASTPTR32(InData);
+ InData = new LoadInst(InData, "", false, LastInst);
+ }
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_st8_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_st8_i32);
+
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(In1.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = TRUNC8(InData1);
+ if (InData2->getType() != Int8PtrTy)
+ InData2 = CASTPTR8(InData2);
+ InData2 = GetElementPtrInst::CreateInBounds(InData2, CONSTPtr(Off), "", LastInst);
+ new StoreInst(InData1, InData2, false, LastInst);
+}
+
+void IRFactory::op_st16_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_st16_i32);
+
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(In1.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = TRUNC16(InData1);
+ if (InData2->getType() != Int8PtrTy)
+ InData2 = CASTPTR8(InData2);
+ InData2 = GetElementPtrInst::CreateInBounds(InData2, CONSTPtr(Off), "", LastInst);
+ InData2 = CASTPTR16(InData2);
+ new StoreInst(InData1, InData2, false, LastInst);
+}
+
+/*
+ * op_st_i32()
+ * args[0]: In1
+ * args[1]: In2 (base)
+ * args[2]: In3 (offset)
+ */
+void IRFactory::op_st_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_st_i32);
+
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(In1.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+
+ if (In2.isRev()) {
+ Value *InData2 = StatePointer(In2, Off, Int32PtrTy);
+ StoreInst *SI = new StoreInst(InData1, InData2, false, LastInst);
+ if (isStateOfPC(Off))
+ SI->setVolatile(true);
+ } else {
+ Value *InData2 = LoadState(In2);
+ if (InData2->getType() != Int8PtrTy)
+ InData2 = CASTPTR8(InData2);
+ InData2 = GetElementPtrInst::CreateInBounds(InData2, CONSTPtr(Off), "", LastInst);
+ InData2 = CASTPTR32(InData2);
+ new StoreInst(InData1, InData2, false, LastInst);
+ }
+}
+
+/* arith */
+/*
+ * op_add_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_add_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_add_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData;
+ if (In1.isRev()) {
+ intptr_t Off = static_cast<ConstantInt*>(InData2)->getSExtValue();
+ OutData = StatePointer(In1, Off, Int32PtrTy);
+ } else
+ OutData = ADD(InData1, InData2);
+
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_sub_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_sub_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_sub_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = SUB(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_mul_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_mul_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = MUL(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_div_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_div_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = SDIV(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_divu_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_divu_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = UDIV(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_rem_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_rem_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = SREM(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_remu_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_remu_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = UREM(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_div2_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_div2_i32);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+#if 0
+ Register &In2 = Reg[args[3]];
+#endif
+ Register &In3 = Reg[args[4]];
+
+ AssertType(Out1.Size == 32 && Out2.Size == 32 &&
+ In1.Size == 32 && In3.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+#if 0
+ Value *InData2 = LoadState(In2);
+#endif
+ Value *InData3 = LoadState(In3);
+ Value *OutData1 = SDIV(InData1, InData3);
+ Value *OutData2 = SREM(InData1, InData3);
+ Out1.setData(OutData1, true);
+ Out2.setData(OutData2, true);
+}
+
+/*
+ * op_divu2_i32()
+ * args[0]: Out1
+ * args[1]: Out2
+ * args[2]: In1
+ * args[3]: In2
+ * args[4]: In3
+ */
+void IRFactory::op_divu2_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_divu2_i32);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+#if 0
+ Register &In2 = Reg[args[3]];
+#endif
+ Register &In3 = Reg[args[4]];
+
+ AssertType(Out1.Size == 32 && Out2.Size == 32 &&
+ In1.Size == 32 && In3.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+#if 0
+ Value *InData2 = LoadState(In2);
+#endif
+ Value *InData3 = LoadState(In3);
+ Value *OutData1 = UDIV(InData1, InData3);
+ Value *OutData2 = UREM(InData1, InData3);
+ Out1.setData(OutData1, true);
+ Out2.setData(OutData2, true);
+}
+
+/*
+ * op_and_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_and_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_and_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = AND(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_or_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_or_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_or_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = OR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_xor_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_xor_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_xor_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = XOR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/* shifts/rotates */
+/*
+ * op_shl_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_shl_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_shl_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = SHL(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_shr_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_shr_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_shr_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = LSHR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_sar_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_sar_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_sar_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = ASHR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_rotl_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_rotl_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_rotl_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ Value *C = LSHR(InData1, SUB(CONST32(32), InData2));
+ Value *OutData = SHL(InData1, InData2);
+ OutData = OR(OutData, C);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_rotr_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_rotr_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ Value *c = SHL(InData1, SUB(CONST32(32), InData2));
+ Value *OutData = LSHR(InData1, InData2);
+ OutData = OR(OutData, c);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_deposit_i32()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ * args[3]: In3 (offset from LSB)
+ * args[4]: In4 (length)
+ */
+void IRFactory::op_deposit_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_deposit_i32);
+
+ /* Deposit the lowest args[4] bits of register args[2] into register
+ * args[1] starting from bits args[3]. */
+ APInt mask = APInt::getBitsSet(32, args[3], args[3] + args[4]);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ if (args[3])
+ InData2 = SHL(InData2, CONST32(args[3]));
+ InData2 = AND(InData2, ConstantInt::get(*Context, mask));
+ InData1 = AND(InData1, ConstantInt::get(*Context, ~mask));
+ InData1 = OR(InData1, InData2);
+ Out.setData(InData1, true);
+}
+
+/*
+ * op_brcond_i32()
+ * args[0]: In1
+ * args[1]: In2
+ * args[2]: In3 (condition code)
+ * args[3]: In4 (label)
+ */
+void IRFactory::op_brcond_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_brcond_i32);
+
+ /* brcond_i32 format:
+ * brcond_i32 op1,op2,cond,<ifTrue>
+ * <ifFalse>:
+ * A
+ * <ifTrue>:
+ * B
+ */
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ CmpInst::Predicate Pred = getPred(args[2]);
+
+ AssertType(In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ SaveGlobals(COHERENCE_ALL, LastInst);
+
+ TCGArg label = args[3];
+ if (Labels.find(label) == Labels.end())
+ Labels[label] = BasicBlock::Create(*Context, "succ", Func);
+
+ BasicBlock *ifTrue = Labels[label];
+ BasicBlock *ifFalse = BasicBlock::Create(*Context, "succ", Func);
+
+ Value *Cond = ICMP(InData1, InData2, Pred);
+ BranchInst::Create(ifTrue, ifFalse, Cond, LastInst);
+ LastInst->eraseFromParent();
+
+ CurrBB = ifFalse;
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+}
+
+void IRFactory::op_add2_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_add2_i32);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+ Register &In2 = Reg[args[3]];
+ Register &In3 = Reg[args[4]];
+ Register &In4 = Reg[args[5]];
+
+ AssertType(Out1.Size == 32 && Out2.Size == 32 &&
+ In1.Size == 32 && In2.Size == 32 &&
+ In3.Size == 32 && In4.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = LoadState(In3);
+ Value *InData4 = LoadState(In4);
+
+ InData1 = ZEXT64(InData1);
+ InData2 = SHL(ZEXT64(InData2), CONST64(32));
+ InData2 = OR(InData2, InData1);
+
+ InData3 = ZEXT64(InData3);
+ InData4 = SHL(ZEXT64(InData4), CONST64(32));
+ InData4 = OR(InData4, InData3);
+
+ InData2 = ADD(InData2, InData4);
+
+ Value *OutData1 = TRUNC32(InData2);
+ Value *OutData2 = TRUNC32(LSHR(InData2, CONST64(32)));
+ Out1.setData(OutData1, true);
+ Out2.setData(OutData2, true);
+}
+
+void IRFactory::op_sub2_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_sub2_i32);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+ Register &In2 = Reg[args[3]];
+ Register &In3 = Reg[args[4]];
+ Register &In4 = Reg[args[5]];
+
+ AssertType(Out1.Size == 32 && Out2.Size == 32 &&
+ In1.Size == 32 && In2.Size == 32 &&
+ In3.Size == 32 && In4.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = LoadState(In3);
+ Value *InData4 = LoadState(In4);
+
+ InData1 = ZEXT64(InData1);
+ InData2 = SHL(ZEXT64(InData2), CONST64(32));
+ InData2 = OR(InData2, InData1);
+
+ InData3 = ZEXT64(InData3);
+ InData4 = SHL(ZEXT64(InData4), CONST64(32));
+ InData4 = OR(InData4, InData3);
+
+ InData2 = SUB(InData2, InData4);
+
+ Value *OutData1 = TRUNC32(InData2);
+ Value *OutData2 = TRUNC32(LSHR(InData2, CONST64(32)));
+ Out1.setData(OutData1, true);
+ Out2.setData(OutData2, true);
+}
+
+void IRFactory::op_mulu2_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_mulu2_i32);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+ Register &In2 = Reg[args[3]];
+
+ AssertType(Out1.Size == 32 && Out2.Size == 32 &&
+ In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = ZEXT64(InData1);
+ InData2 = ZEXT64(InData2);
+
+ Value *OutData = MUL(InData1, InData2);
+ Value *Low = TRUNC32(OutData);
+ Value *High = TRUNC32(LSHR(OutData, CONST64(32)));
+ Out1.setData(Low, true);
+ Out2.setData(High, true);
+}
+
+void IRFactory::op_muls2_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_muls2_i32);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+ Register &In2 = Reg[args[3]];
+
+ AssertType(Out1.Size == 32 && Out2.Size == 32 &&
+ In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = SEXT64(InData1);
+ InData2 = SEXT64(InData2);
+
+ Value *OutData = MUL(InData1, InData2);
+ Value *Low = TRUNC32(OutData);
+ Value *High = TRUNC32(LSHR(OutData, CONST64(32)));
+ Out1.setData(Low, true);
+ Out2.setData(High, true);
+}
+
+void IRFactory::op_muluh_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_muluh_i32);
+
+ Register &Out1 = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out1.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = ZEXT64(InData1);
+ InData2 = ZEXT64(InData2);
+
+ Value *OutData = MUL(InData1, InData2);
+ Value *High = TRUNC32(LSHR(OutData, CONST64(32)));
+ Out1.setData(High, true);
+}
+
+void IRFactory::op_mulsh_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_mulsh_i32);
+
+ Register &Out1 = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out1.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = SEXT64(InData1);
+ InData2 = SEXT64(InData2);
+
+ Value *OutData = MUL(InData1, InData2);
+ Value *High = TRUNC32(LSHR(OutData, CONST64(32)));
+ Out1.setData(High, true);
+}
+
+void IRFactory::op_brcond2_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_brcond2_i32);
+
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ Register &In3 = Reg[args[2]];
+ Register &In4 = Reg[args[3]];
+ CmpInst::Predicate Pred = getPred(args[4]);
+
+ AssertType(In1.Size == 32 && In2.Size == 32 &&
+ In3.Size == 32 && In4.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = LoadState(In3);
+ Value *InData4 = LoadState(In4);
+
+ SaveGlobals(COHERENCE_ALL, LastInst);
+
+ InData1 = ZEXT64(InData1);
+ InData2 = SHL(ZEXT64(InData2), CONST64(32));
+ InData3 = ZEXT64(InData3);
+ InData4 = SHL(ZEXT64(InData4), CONST64(32));
+
+ InData2 = OR(InData2, InData1);
+ InData4 = OR(InData4, InData3);
+
+ TCGArg label = args[5];
+ if (Labels.find(label) == Labels.end())
+ Labels[label] = BasicBlock::Create(*Context, "succ", Func);
+
+ BasicBlock *ifTrue = Labels[label];
+ BasicBlock *ifFalse = BasicBlock::Create(*Context, "succ", Func);
+
+ Value *Cond = ICMP(InData2, InData4, Pred);
+ BranchInst::Create(ifTrue, ifFalse, Cond, LastInst);
+ LastInst->eraseFromParent();
+
+ CurrBB = ifFalse;
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+}
+
+void IRFactory::op_setcond2_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_setcond2_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+ Register &In3 = Reg[args[3]];
+ Register &In4 = Reg[args[4]];
+ CmpInst::Predicate Pred = getPred(args[5]);
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32 &&
+ In3.Size == 32 && In4.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = LoadState(In3);
+ Value *InData4 = LoadState(In4);
+
+ InData1 = ZEXT64(InData1);
+ InData2 = SHL(ZEXT64(InData2), CONST64(32));
+ InData3 = ZEXT64(InData3);
+ InData4 = SHL(ZEXT64(InData4), CONST64(32));
+
+ InData2 = OR(InData2, InData1);
+ InData4 = OR(InData4, InData3);
+
+ Value *OutData = ICMP(InData2, InData4, Pred);
+ OutData = ZEXT32(OutData);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_ext8s_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext8s_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC8(InData);
+ InData = SEXT32(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ext16s_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext16s_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC16(InData);
+ InData = SEXT32(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ext8u_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext8u_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ InData = AND(InData, CONST32(0xFF));
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ext16u_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext16u_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ InData = AND(InData, CONST32(0xFFFF));
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_bswap16_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_bswap16_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC16(InData);
+ InData = BSWAP16(InData);
+ InData = ZEXT32(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_bswap32_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_bswap32_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ InData = BSWAP32(InData);
+ Out.setData(InData, true);
+}
+
+/*
+ * op_not_i32()
+ * args[0]: Out
+ * args[1]: In
+ */
+void IRFactory::op_not_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_not_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ Value *OutData = XOR(InData, CONST32((uint32_t)-1));
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_neg_i32()
+ * args[0]: Out
+ * args[1]: In
+ */
+void IRFactory::op_neg_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_neg_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ Value *OutData = SUB(CONST32(0), InData);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_andc_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_andc_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData2 = XOR(InData2, CONST32((uint32_t)-1));
+ Value *OutData = AND(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_orc_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_orc_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData2 = XOR(InData2, CONST32((uint32_t)-1));
+ Value *OutData = OR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_eqv_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_eqv_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData2 = XOR(InData2, CONST32((uint32_t)-1));
+ Value *OutData = XOR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_nand_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_nand_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ Value *OutData = AND(InData1, InData2);
+ OutData = XOR(OutData, CONST32((uint32_t)-1));
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_nor_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_nor_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 32 && In1.Size == 32 && In2.Size == 32);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ Value *OutData = OR(InData1, InData2);
+ OutData = XOR(OutData, CONST32((uint32_t)-1));
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_mov_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_mov_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64);
+
+ Value *InData = LoadState(In);
+
+ size_t Size = DL->getTypeSizeInBits(InData->getType());
+ if (Size != 64)
+ InData = ZEXT64(InData);
+
+ Out.setData(InData, true);
+}
+
+/*
+ * op_movi_i64()
+ * args[0]: Out
+ * args[1]: In (const value)
+ */
+void IRFactory::op_movi_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_movi_i64);
+
+ Register &Out = Reg[args[0]];
+
+ AssertType(Out.Size == 64);
+
+ Out.setData(CONST64(args[1]), true);
+}
+
+void IRFactory::op_setcond_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_setcond_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+ CmpInst::Predicate Pred = getPred(args[3]);
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = ICMP(InData1, InData2, Pred);
+ OutData = ZEXT64(OutData);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_movcond_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_movcond_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+ Register &In3 = Reg[args[3]];
+ Register &In4 = Reg[args[4]];
+ CmpInst::Predicate Pred = getPred(args[5]);
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64 &&
+ In3.Size == 64 && In4.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = LoadState(In3);
+ Value *InData4 = LoadState(In4);
+ Value *Cond = ICMP(InData1, InData2, Pred);
+ Value *OutData = SelectInst::Create(Cond, InData3, InData4, "", LastInst);
+ Out.setData(OutData, true);
+}
+
+
+/* load/store */
+void IRFactory::op_ld8u_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld8u_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 64);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = ZEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ld8s_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld8s_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 64);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = SEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ld16u_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld16u_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 64);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = CASTPTR16(InData);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = ZEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ld16s_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld16s_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 64);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = CASTPTR16(InData);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = SEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ld32u_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld32u_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 64);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = CASTPTR32(InData);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = ZEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ld32s_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld32s_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 64);
+
+ Value *InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = CASTPTR32(InData);
+ InData = new LoadInst(InData, "", false, LastInst);
+ InData = SEXT64(InData);
+ Out.setData(InData, true);
+}
+
+/*
+ * op_ld_i64()
+ * args[0]: Out
+ * args[1]: In (base)
+ * args[2]: In (offset)
+ */
+void IRFactory::op_ld_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ld_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(Out.Size == 64);
+
+ Value *InData;
+ if (In.isRev()) {
+ InData = StatePointer(In, Off, Int64PtrTy);
+ InData = new LoadInst(InData, "", false, LastInst);
+ if (isStateOfPC(Off))
+ static_cast<LoadInst*>(InData)->setVolatile(true);
+ } else {
+ InData = LoadState(In);
+ if (InData->getType() != Int8PtrTy)
+ InData = CASTPTR8(InData);
+ InData = GetElementPtrInst::CreateInBounds(InData, CONSTPtr(Off), "", LastInst);
+ InData = CASTPTR64(InData);
+ InData = new LoadInst(InData, "", false, LastInst);
+ }
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_st8_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_st8_i64);
+
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(In1.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = TRUNC8(InData1);
+ if (InData2->getType() != Int8PtrTy)
+ InData2 = CASTPTR8(InData2);
+ InData2 = GetElementPtrInst::CreateInBounds(InData2, CONSTPtr(Off), "", LastInst);
+ new StoreInst(InData1, InData2, false, LastInst);
+}
+
+void IRFactory::op_st16_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_st16_i64);
+
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(In1.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = TRUNC16(InData1);
+ if (InData2->getType() != Int8PtrTy)
+ InData2 = CASTPTR8(InData2);
+ InData2 = GetElementPtrInst::CreateInBounds(InData2, CONSTPtr(Off), "", LastInst);
+ InData2 = CASTPTR16(InData2);
+ new StoreInst(InData1, InData2, false, LastInst);
+}
+
+void IRFactory::op_st32_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_st32_i64);
+
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(In1.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = TRUNC32(InData1);
+ if (InData2->getType() != Int8PtrTy)
+ InData2 = CASTPTR8(InData2);
+ InData2 = GetElementPtrInst::CreateInBounds(InData2, CONSTPtr(Off), "", LastInst);
+ InData2 = CASTPTR32(InData2);
+ new StoreInst(InData1, InData2, false, LastInst);
+}
+
+/*
+ * op_st_i64()
+ * args[0]: In1
+ * args[1]: In2 (base)
+ * args[2]: In3 (offset)
+ */
+void IRFactory::op_st_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_st_i64);
+
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ TCGArg Off = args[2];
+
+ AssertType(In1.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+
+ if (In2.isRev()) {
+ Value *InData2 = StatePointer(In2, Off, Int64PtrTy);
+ StoreInst *SI = new StoreInst(InData1, InData2, false, LastInst);
+ if (isStateOfPC(Off))
+ SI->setVolatile(true);
+ } else {
+ Value *InData2 = LoadState(In2);
+ if (InData2->getType() != Int8PtrTy)
+ InData2 = CASTPTR8(InData2);
+ InData2 = GetElementPtrInst::CreateInBounds(InData2, CONSTPtr(Off), "", LastInst);
+ InData2 = CASTPTR64(InData2);
+ new StoreInst(InData1, InData2, false, LastInst);
+ }
+}
+
+/* arith */
+/*
+ * op_add_i64()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_add_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_add_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData;
+ if (In1.isRev()) {
+ intptr_t Off = static_cast<ConstantInt*>(InData2)->getSExtValue();
+ OutData = StatePointer(In1, Off, Int64PtrTy);
+ } else
+ OutData = ADD(InData1, InData2);
+
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_sub_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_sub_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = SUB(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_mul_i64()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_mul_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_mul_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = MUL(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_div_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_div_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = SDIV(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_divu_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_divu_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = UDIV(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_rem_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_rem_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = SREM(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_remu_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_remu_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = UREM(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_div2_i64(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_divu2_i64(const TCGArg *args)
+{
+ IRError("%s not implemented.\n", __func__);
+}
+
+void IRFactory::op_and_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_and_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ size_t Size = DL->getTypeSizeInBits(InData1->getType());
+ if (Size == 32)
+ InData1 = ZEXT64(InData1);
+ Size = DL->getTypeSizeInBits(InData2->getType());
+ if (Size == 32)
+ InData2 = ZEXT64(InData2);
+
+ Value *OutData = AND(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_or_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_or_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = OR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_xor_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_xor_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = XOR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/* shifts/rotates */
+void IRFactory::op_shl_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_shl_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = SHL(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+/*
+ * op_shr_i64()
+ * args[0]: Out
+ * args[1]: In1
+ * args[2]: In2
+ */
+void IRFactory::op_shr_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_shr_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = LSHR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_sar_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_sar_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *OutData = ASHR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_rotl_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_rotl_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ Value *C = LSHR(InData1, SUB(CONST64(64), InData2));
+ Value *OutData = SHL(InData1, InData2);
+ OutData = OR(OutData, C);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_rotr_i64(const TCGArg *args)
+{
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ Value *c = SHL(InData1, SUB(CONST64(64), InData2));
+ Value *OutData = LSHR(InData1, InData2);
+ OutData = OR(OutData, c);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_deposit_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_deposit_i64);
+
+ /* Deposit the lowest args[4] bits of register args[2] into register
+ * args[1] starting from bits args[3]. */
+ APInt mask = APInt::getBitsSet(64, args[3], args[3] + args[4]);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ if (args[3])
+ InData2 = SHL(InData2, CONST64(args[3]));
+ InData2 = AND(InData2, ConstantInt::get(*Context, mask));
+ InData1 = AND(InData1, ConstantInt::get(*Context, ~mask));
+ InData1 = OR(InData1, InData2);
+ Out.setData(InData1, true);
+}
+
+void IRFactory::op_ext_i32_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext_i32_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ InData = SEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_extu_i32_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_extu_i32_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 32);
+
+ Value *InData = LoadState(In);
+ InData = ZEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_extrl_i64_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_extrl_i64_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC32(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_extrh_i64_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_extrh_i64_i32);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 32 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC32(LSHR(InData, CONST64(32)));
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_brcond_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_brcond_i64);
+
+ /* brcond_i32 format:
+ * brcond_i32 op1,op2,cond,<ifTrue>
+ * <ifFalse>:
+ * A
+ * <ifTrue>:
+ * B
+ */
+ Register &In1 = Reg[args[0]];
+ Register &In2 = Reg[args[1]];
+ CmpInst::Predicate Pred = getPred(args[2]);
+
+ AssertType(In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ SaveGlobals(COHERENCE_ALL, LastInst);
+
+ TCGArg label = args[3];
+ if (Labels.find(label) == Labels.end())
+ Labels[label] = BasicBlock::Create(*Context, "succ", Func);
+
+ BasicBlock *ifTrue = Labels[label];
+ BasicBlock *ifFalse = BasicBlock::Create(*Context, "succ", Func);
+
+ Value *Cond = ICMP(InData1, InData2, Pred);
+ BranchInst::Create(ifTrue, ifFalse, Cond, LastInst);
+ LastInst->eraseFromParent();
+
+ CurrBB = ifFalse;
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+}
+
+void IRFactory::op_ext8s_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext8s_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC8(InData);
+ InData = SEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ext16s_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext16s_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC16(InData);
+ InData = SEXT64(InData);
+ Out.setData(InData, true);
+}
+
+/*
+ * op_ext32s_i64()
+ * args[0]: Out
+ * args[1]: In
+ */
+void IRFactory::op_ext32s_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext32s_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ if (DL->getTypeSizeInBits(InData->getType()) != 32)
+ InData = TRUNC32(InData);
+ InData = SEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ext8u_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext8u_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = AND(InData, CONST64(0xFF));
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_ext16u_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext16u_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = AND(InData, CONST64(0xFFFF));
+ Out.setData(InData, true);
+}
+
+/*
+ * op_ext32u_i64()
+ * args[0]: Out
+ * args[1]: In
+ */
+void IRFactory::op_ext32u_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_ext32u_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ if (DL->getTypeSizeInBits(InData->getType()) == 32)
+ InData = ZEXT64(InData);
+ else
+ InData = AND(InData, CONST64(0xFFFFFFFF));
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_bswap16_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_bswap16_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC16(InData);
+ InData = BSWAP16(InData);
+ InData = ZEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_bswap32_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_bswap32_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = TRUNC32(InData);
+ InData = BSWAP32(InData);
+ InData = ZEXT64(InData);
+ Out.setData(InData, true);
+}
+
+void IRFactory::op_bswap64_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_bswap64_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ InData = BSWAP64(InData);
+ Out.setData(InData, true);
+
+}
+
+void IRFactory::op_not_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_not_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ Value *OutData = XOR(InData, CONST64((uint64_t)-1));
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_neg_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_neg_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In = Reg[args[1]];
+
+ AssertType(Out.Size == 64 && In.Size == 64);
+
+ Value *InData = LoadState(In);
+ Value *OutData = SUB(CONST64(0), InData);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_andc_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_andc_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData2 = XOR(InData2, CONST64((uint64_t)-1));
+ Value *OutData = AND(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_orc_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_orc_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData2 = XOR(InData2, CONST64((uint64_t)-1));
+ Value *OutData = OR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_eqv_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_eqv_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData2 = XOR(InData2, CONST64((uint64_t)-1));
+ Value *OutData = XOR(InData1, InData2);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_nand_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_nand_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ Value *OutData = AND(InData1, InData2);
+ OutData = XOR(OutData, CONST64((uint64_t)-1));
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_nor_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_nor_i64);
+
+ Register &Out = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ Value *OutData = OR(InData1, InData2);
+ OutData = XOR(OutData, CONST64((uint64_t)-1));
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_add2_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_add2_i64);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+ Register &In2 = Reg[args[3]];
+ Register &In3 = Reg[args[4]];
+ Register &In4 = Reg[args[5]];
+
+ AssertType(Out1.Size == 64 && Out2.Size == 64 &&
+ In1.Size == 64 && In2.Size == 64 &&
+ In3.Size == 64 && In4.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = LoadState(In3);
+ Value *InData4 = LoadState(In4);
+
+ InData1 = ZEXT128(InData1);
+ InData2 = SHL(ZEXT128(InData2), CONST128(64));
+ InData2 = OR(InData2, InData1);
+
+ InData3 = ZEXT128(InData3);
+ InData4 = SHL(ZEXT128(InData4), CONST128(64));
+ InData4 = OR(InData4, InData3);
+
+ InData2 = ADD(InData2, InData4);
+
+ Value *OutData1 = TRUNC64(InData2);
+ Value *OutData2 = TRUNC64(LSHR(InData2, CONST128(64)));
+ Out1.setData(OutData1, true);
+ Out2.setData(OutData2, true);
+}
+
+void IRFactory::op_sub2_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_sub2_i64);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+ Register &In2 = Reg[args[3]];
+ Register &In3 = Reg[args[4]];
+ Register &In4 = Reg[args[5]];
+
+ AssertType(Out1.Size == 64 && Out2.Size == 64 &&
+ In1.Size == 64 && In2.Size == 64 &&
+ In3.Size == 64 && In4.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = LoadState(In3);
+ Value *InData4 = LoadState(In4);
+
+ InData1 = ZEXT128(InData1);
+ InData2 = SHL(ZEXT128(InData2), CONST128(64));
+ InData2 = OR(InData2, InData1);
+
+ InData3 = ZEXT128(InData3);
+ InData4 = SHL(ZEXT128(InData4), CONST128(64));
+ InData4 = OR(InData4, InData3);
+
+ InData2 = SUB(InData2, InData4);
+
+ Value *OutData1 = TRUNC64(InData2);
+ Value *OutData2 = TRUNC64(LSHR(InData2, CONST128(64)));
+ Out1.setData(OutData1, true);
+ Out2.setData(OutData2, true);
+}
+
+void IRFactory::op_mulu2_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_mulu2_i64);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+ Register &In2 = Reg[args[3]];
+
+ AssertType(Out1.Size == 64 && Out2.Size == 64 &&
+ In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = ZEXT128(InData1);
+ InData2 = ZEXT128(InData2);
+
+ Value *OutData = MUL(InData1, InData2);
+ Value *Low = TRUNC64(OutData);
+ Value *High = TRUNC64(LSHR(OutData, CONST128(64)));
+ Out1.setData(Low, true);
+ Out2.setData(High, true);
+}
+
+void IRFactory::op_muls2_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_muls2_i64);
+
+ Register &Out1 = Reg[args[0]];
+ Register &Out2 = Reg[args[1]];
+ Register &In1 = Reg[args[2]];
+ Register &In2 = Reg[args[3]];
+
+ AssertType(Out1.Size == 64 && Out2.Size == 64 &&
+ In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = SEXT128(InData1);
+ InData2 = SEXT128(InData2);
+
+ Value *OutData = MUL(InData1, InData2);
+ Value *Low = TRUNC64(OutData);
+ Value *High = TRUNC64(LSHR(OutData, CONST128(64)));
+ Out1.setData(Low, true);
+ Out2.setData(High, true);
+}
+
+void IRFactory::op_muluh_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_muluh_i64);
+
+ Register &Out1 = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out1.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = ZEXT128(InData1);
+ InData2 = ZEXT128(InData2);
+
+ Value *OutData = MUL(InData1, InData2);
+ Value *High = TRUNC64(LSHR(OutData, CONST128(64)));
+ Out1.setData(High, true);
+}
+
+void IRFactory::op_mulsh_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_mulsh_i64);
+
+ Register &Out1 = Reg[args[0]];
+ Register &In1 = Reg[args[1]];
+ Register &In2 = Reg[args[2]];
+
+ AssertType(Out1.Size == 64 && In1.Size == 64 && In2.Size == 64);
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+
+ InData1 = SEXT128(InData1);
+ InData2 = SEXT128(InData2);
+
+ Value *OutData = MUL(InData1, InData2);
+ Value *High = TRUNC64(LSHR(OutData, CONST128(64)));
+ Out1.setData(High, true);
+}
+
+/* QEMU specific */
+void IRFactory::op_insn_start(const TCGArg *args)
+{
+ IRDebug(INDEX_op_insn_start);
+ NI.NumInsts++;
+}
+
+void IRFactory::InsertLinkAndExit(Instruction *InsertPos)
+{
+ auto ChainSlot = LLEnv->getChainSlot();
+ size_t Key = ChainSlot.first;
+ uintptr_t RetVal = ChainSlot.second;
+ unsigned Idx = NI.setChainSlot(Key);
+ uintptr_t Addr = NI.getChainSlotAddr(Idx);
+
+ /* Here we use the llvm.trap intrinsic to notify LLVM backend to insert
+ * jump instruction for chaining. */
+ ConstantInt *Meta[] = { CONST32(PATCH_TRACE_BLOCK_CHAINING), CONSTPtr(Addr) };
+ Function *TrapFn = Intrinsic::getDeclaration(Mod, Intrinsic::trap);
+ CallInst *CI = CallInst::Create(TrapFn, "", InsertPos);
+ DebugLoc DL = MF->getDebugLoc(PATCH_TRACE_BLOCK_CHAINING, Idx, Func, Meta);
+ CI->setDebugLoc(DL);
+
+ MF->setExit(CI);
+
+ InsertExit(RetVal);
+}
+
+void IRFactory::InsertExit(uintptr_t RetVal, bool setExit)
+{
+ ConstantInt *Meta[] = { CONST32(PATCH_EXIT_TB), ExitAddr };
+ ReturnInst *RI = ReturnInst::Create(*Context, CONSTPtr(RetVal), LastInst);
+ DebugLoc DL = MF->getDebugLoc(PATCH_EXIT_TB, 0, Func, Meta);
+ RI->setDebugLoc(DL);
+
+ if (setExit)
+ MF->setExit(RI);
+}
+
+void IRFactory::InsertLookupIBTC(GraphNode *CurrNode)
+{
+ BasicBlock *BB = nullptr;
+
+ if (CommonBB.find("ibtc") == CommonBB.end()) {
+ BB = CommonBB["ibtc"] = BasicBlock::Create(*Context, "ibtc", Func);
+
+ SmallVector<Value *, 4> Params;
+ Function *F = ResolveFunction("helper_lookup_ibtc");
+ Value *Env = ConvertCPUType(F, 0, BB);
+
+ Params.push_back(Env);
+ CallInst *CI = CallInst::Create(F, Params, "", BB);
+ IndirectBrInst *IB = IndirectBrInst::Create(CI, 1, BB);
+ MF->setConst(CI);
+ MF->setExit(CI);
+
+ IndirectBrs.push_back(IB);
+ toSink.push_back(BB);
+ }
+
+ BB = CommonBB["ibtc"];
+ BranchInst::Create(BB, LastInst);
+}
+
+void IRFactory::InsertLookupCPBL(GraphNode *CurrNode)
+{
+ SmallVector<Value *, 4> Params;
+ Function *F = ResolveFunction("helper_lookup_cpbl");
+ Value *Env = ConvertCPUType(F, 0, LastInst);
+
+ Params.push_back(Env);
+ CallInst *CI = CallInst::Create(F, Params, "", LastInst);
+ IndirectBrInst *IB = IndirectBrInst::Create(CI, 1, LastInst);
+ MF->setConst(CI);
+ MF->setExit(CI);
+
+ IndirectBrs.push_back(IB);
+ toSink.push_back(CurrBB);
+}
+
+void IRFactory::TraceValidateCPBL(GraphNode *NextNode, StoreInst *StorePC)
+{
+ TranslationBlock *NextTB = NextNode->getTB();
+ Value *Cond;
+
+ SmallVector<Value *, 4> Params;
+ Function *F = ResolveFunction("helper_validate_cpbl");
+ Value *Env = ConvertCPUType(F, 0, LastInst);
+
+ Params.push_back(Env);
+ Params.push_back(ConstantInt::get(StorePC->getValueOperand()->getType(),
+ NextTB->pc));
+ Params.push_back(CONST32(NextTB->id));
+ CallInst *CI = CallInst::Create(F, Params, "", LastInst);
+ Cond = ICMP(CI, CONST32(1), ICmpInst::ICMP_EQ);
+
+ MF->setConst(CI);
+
+ BasicBlock *Valid = BasicBlock::Create(*Context, "cpbl.valid", Func);
+ BasicBlock *Invalid = BasicBlock::Create(*Context, "cpbl.invalid", Func);
+ toSink.push_back(Invalid);
+
+ BranchInst::Create(Valid, Invalid, Cond, LastInst);
+ LastInst->eraseFromParent();
+
+ LastInst = BranchInst::Create(ExitBB, Invalid);
+ Instruction *SI = StorePC->clone();
+ SI->insertBefore(LastInst);
+ InsertExit(0);
+ LastInst->eraseFromParent();
+
+ MF->setExit(SI);
+
+ CurrBB = Valid;
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+}
+
+/*
+ * TraceLinkIndirectJump()
+ * This routine implements IB inlining, i.e., linking two intra-trace blocks
+ * via indirect branch.
+ * Note that we don't need to validate CPBL because this routine is only
+ * used for user-mode emulation.
+ */
+void IRFactory::TraceLinkIndirectJump(GraphNode *NextNode, StoreInst *SI)
+{
+ dbg() << DEBUG_LLVM << " - Found an indirect branch. Guess pc "
+ << format("0x%" PRIx, NextNode->getGuestPC()) << "\n";
+
+ BasicBlock *ifTrue = BasicBlock::Create(*Context, "main_path", Func);
+ BasicBlock *ifFalse = BasicBlock::Create(*Context, "exit_stub", Func);
+
+ Value *NextPC = SI->getValueOperand();
+ Value *GuessPC = ConstantInt::get(NextPC->getType(),
+ Builder->getGuestPC(NextNode));
+
+ Value *Cond = ICMP(NextPC, GuessPC, ICmpInst::ICMP_EQ);
+ BranchInst::Create(ifTrue, ifFalse, Cond, LastInst);
+ LastInst->eraseFromParent();
+
+ CurrBB = ifTrue;
+
+ /* First set the branch to exit BB, and the link will be resolved
+ at the trace finalization procedure. */
+ BranchInst *BI = BranchInst::Create(ExitBB, CurrBB);
+ Builder->setBranch(BI, NextNode);
+
+ CurrBB = ifFalse;
+ LastInst = BranchInst::Create(ExitBB, CurrBB);
+}
+
+void IRFactory::TraceLinkDirectJump(GraphNode *NextNode, StoreInst *SI)
+{
+ ConstantInt *NextPC = static_cast<ConstantInt *>(SI->getValueOperand());
+ target_ulong next_pc = NextPC->getZExtValue() +
+ Builder->getCurrNode()->getTB()->cs_base;
+ NextPC = ConstantInt::get(NextPC->getType(), next_pc);
+
+ dbg() << DEBUG_LLVM << " - Found a direct branch to pc "
+ << format("0x%" PRIx, next_pc) << "\n";
+
+#if defined(CONFIG_SOFTMMU)
+ TranslationBlock *tb = Builder->getCurrNode()->getTB();
+ TranslationBlock *next_tb = NextNode->getTB();
+ /* If two blocks are not in the same page or the next block is across
+ * the page boundary, we have to handle it with CPBL. */
+ if ((tb->pc & TARGET_PAGE_MASK) != (next_tb->pc & TARGET_PAGE_MASK) ||
+ next_tb->page_addr[1] != (tb_page_addr_t)-1)
+ TraceValidateCPBL(NextNode, SI);
+#endif
+ /* First set the branch to exit BB, and the link will be resolved
+ at the trace finalization procedure. */
+ BranchInst *BI = BranchInst::Create(ExitBB, LastInst);
+ Builder->setBranch(BI, NextNode);
+}
+
+void IRFactory::TraceLinkDirectJump(StoreInst *SI)
+{
+ ConstantInt *NextPC = static_cast<ConstantInt *>(SI->getValueOperand());
+ target_ulong next_pc = NextPC->getZExtValue() +
+ Builder->getCurrNode()->getTB()->cs_base;
+ NextPC = ConstantInt::get(NextPC->getType(), next_pc);
+
+ dbg() << DEBUG_LLVM << " - Found a direct branch to pc "
+ << format("0x%" PRIx, next_pc) << " (exit)\n";
+
+#if defined(CONFIG_SOFTMMU)
+ TranslationBlock *tb = Builder->getCurrNode()->getTB();
+ if ((tb->pc & TARGET_PAGE_MASK) != (next_pc & TARGET_PAGE_MASK)) {
+ InsertLookupCPBL(Builder->getCurrNode());
+ return;
+ }
+#endif
+ InsertLinkAndExit(SI);
+}
+
+GraphNode *IRFactory::findNextNode(target_ulong pc)
+{
+#ifdef USE_TRACETREE_ONLY
+ for (auto Child : Builder->getCurrNode()->getChildren()) {
+ if (pc == Builder->getGuestPC(Child))
+ return Child;
+ }
+ return nullptr;
+#else
+ return Builder->getNode(pc);
+#endif
+}
+
+void IRFactory::TraceLink(StoreInst *SI)
+{
+ GraphNode *CurrNode = Builder->getCurrNode();
+ ConstantInt *CI = dyn_cast<ConstantInt>(SI->getValueOperand());
+ if (!CI) {
+ /* Indirect branch */
+ SaveGlobals(COHERENCE_ALL, LastInst);
+
+#if defined(CONFIG_USER_ONLY)
+ for (auto NextNode : CurrNode->getChildren())
+ TraceLinkIndirectJump(NextNode, SI);
+#endif
+ InsertLookupIBTC(CurrNode);
+ } else {
+ /* Direct branch. */
+ target_ulong pc = CI->getZExtValue();
+ GraphNode *NextNode = findNextNode(pc);
+ if (NextNode) {
+ TraceLinkDirectJump(NextNode, SI);
+ return;
+ }
+
+ TraceLinkDirectJump(SI);
+ std::string Name = CurrBB->getName().str() + ".exit";
+ CurrBB->setName(Name);
+ toSink.push_back(CurrBB);
+ }
+}
+
+StoreInst *IRFactory::getStorePC()
+{
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+ std::vector<std::pair<intptr_t, StoreInst *> > StorePC;
+
+ /* Search for store instructions that write value to PC in this block. */
+ bool hasAllConstantPC = true;
+ BasicBlock *BB = LastInst->getParent();
+ for (auto BI = BB->begin(), BE = BB->end(); BI != BE; ++BI) {
+ if (StoreInst *SI = dyn_cast<StoreInst>(BI)) {
+ intptr_t Off = 0;
+ Value *Base = getBaseWithConstantOffset(DL,
+ SI->getPointerOperand(), Off);
+ if (Base == BaseReg[TCG_AREG0].Base && isStateOfPC(Off)) {
+ StorePC.push_back(std::make_pair(Off, SI));
+ if (!isa<ConstantInt>(SI->getValueOperand()))
+ hasAllConstantPC = false;
+ }
+ }
+ }
+
+ if (StorePC.empty())
+ return nullptr;
+ if (StorePC.size() == 1)
+ return StorePC[0].second;
+
+ /* We only consider the last two stores. */
+ unsigned I1 = StorePC.size() - 2, I2 = StorePC.size() - 1;
+ if (StorePC[I1].first > StorePC[I2].first) {
+ unsigned tmp = I1;
+ I1 = I2;
+ I2 = tmp;
+ }
+
+ intptr_t OffsetA = StorePC[I1].first;
+ intptr_t OffsetB = StorePC[I2].first;
+ StoreInst *SA = StorePC[I1].second;
+ StoreInst *SB = StorePC[I2].second;
+ intptr_t SzA = DL->getTypeSizeInBits(SA->getValueOperand()->getType());
+ intptr_t SzB = DL->getTypeSizeInBits(SB->getValueOperand()->getType());
+ if (SzA != SzB || OffsetA + SzA != OffsetB || SzA + SzB != TARGET_LONG_BITS)
+ return nullptr;
+
+ Value *NewPC;
+ Type *Ty = (TARGET_LONG_BITS == 32) ? Int32Ty : Int64Ty;
+ Type *PTy = (TARGET_LONG_BITS == 32) ? Int32PtrTy : Int64PtrTy;
+ if (hasAllConstantPC) {
+ target_ulong PCA = static_cast<ConstantInt*>(SA->getValueOperand())->getZExtValue();
+ target_ulong PCB = static_cast<ConstantInt*>(SA->getValueOperand())->getZExtValue();
+ NewPC = ConstantInt::get(Ty, PCA | (PCB << SzA));
+ } else {
+ Value *PCA = ZEXT(SA->getValueOperand(), Ty);
+ Value *PCB = ZEXT(SB->getValueOperand(), Ty);
+ PCB = SHL(PCB, ConstantInt::get(Ty, SzA));
+ NewPC = OR(PCA, PCB);
+ }
+
+ toErase.push_back(SA);
+ toErase.push_back(SB);
+
+ Value *Addr = CAST(SA->getPointerOperand(), PTy);
+ return new StoreInst(NewPC, Addr, true, LastInst);
+
+#else
+ return dyn_cast<StoreInst>(--BasicBlock::iterator(LastInst));
+#endif
+}
+
+/*
+ * op_exit_tb()
+ * args[0]: return value
+ */
+void IRFactory::op_exit_tb(const TCGArg *args)
+{
+ IRDebug(INDEX_op_exit_tb);
+
+ if (!LastInst)
+ return;
+
+ /* Some guest architectures (e.g., ARM) do not explicitly generete a store
+ * instruction to sync the PC value to the memory before exit_tb. We
+ * generate the store PC instruction here so that the following routine can
+ * analyze the PC value it will branch to. Note that other dirty states will
+ * be synced later. */
+ CreateStorePC(LastInst);
+
+ if (LastInst == &*LastInst->getParent()->begin()) {
+ SaveGlobals(COHERENCE_ALL, LastInst);
+ InsertExit(0, true);
+ } else if (isa<CallInst>(--BasicBlock::iterator(LastInst))) {
+ /* Tail call. */
+ for (int i = 0, e = tcg_ctx.nb_globals; i != e; ++i) {
+ Register &reg = Reg[i];
+ if (reg.isReg() && reg.isDirty())
+ runPasses = false;
+ }
+
+ SaveGlobals(COHERENCE_ALL, LastInst);
+ InsertExit(0, true);
+ } else if (StoreInst *SI = getStorePC()) {
+ SaveGlobals(COHERENCE_ALL, SI);
+ TraceLink(SI);
+ } else {
+ runPasses = false;
+ SaveGlobals(COHERENCE_ALL, LastInst);
+ InsertExit(0, true);
+ }
+
+ LastInst->eraseFromParent();
+ LastInst = nullptr;
+}
+
+/*
+ * op_goto_tb()
+ * args[0]: jump index
+ */
+void IRFactory::op_goto_tb(const TCGArg *args)
+{
+ IRDebug(INDEX_op_goto_tb);
+}
+
+void IRFactory::op_qemu_ld_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_qemu_ld_i32);
+
+ TCGArg DataLo = *args++;
+ TCGArg AddrLo = *args++;
+ TCGArg AddrHi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) ? *args++ : 0;
+ TCGMemOpIdx oi = *args++;
+ TCGMemOp opc = get_memop(oi);
+
+ Register &Out = Reg[DataLo];
+ Register &In1 = Reg[AddrLo];
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = (AddrHi) ? LoadState(Reg[AddrHi]) : nullptr;
+
+ AssertType(In1.Size == 32 || In1.Size == 64);
+
+ SaveStates();
+
+ Value *OutData = QEMULoad(InData1, InData2, oi);
+ OutData = getExtendValue(OutData, Out.Ty, opc);
+ Out.setData(OutData, true);
+}
+
+void IRFactory::op_qemu_st_i32(const TCGArg *args)
+{
+ IRDebug(INDEX_op_qemu_st_i32);
+
+ TCGArg DataLo = *args++;
+ TCGArg AddrLo = *args++;
+ TCGArg AddrHi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) ? *args++ : 0;
+ TCGMemOpIdx oi = *args++;
+ TCGMemOp opc = get_memop(oi);
+
+ Register &In1 = Reg[DataLo];
+ Register &In2 = Reg[AddrLo];
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = (AddrHi) ? LoadState(Reg[AddrHi]) : nullptr;
+
+ AssertType(In1.Size == 32 || In1.Size == 64);
+
+ SaveStates();
+
+ InData1 = getTruncValue(InData1, opc);
+ QEMUStore(InData1, InData2, InData3, oi);
+}
+
+void IRFactory::op_qemu_ld_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_qemu_ld_i64);
+
+ TCGArg DataLo = *args++;
+ TCGArg DataHi = (TCG_TARGET_REG_BITS == 32) ? *args++ : 0;
+ TCGArg AddrLo = *args++;
+ TCGArg AddrHi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) ? *args++ : 0;
+ TCGMemOpIdx oi = *args++;
+ TCGMemOp opc = get_memop(oi);
+
+ Register &Out = Reg[DataLo];
+ Register &In1 = Reg[AddrLo];
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = (AddrHi) ? LoadState(Reg[AddrHi]) : nullptr;
+
+ AssertType(In1.Size == 32 || In1.Size == 64);
+
+ SaveStates();
+
+ Value *OutData = QEMULoad(InData1, InData2, oi);
+ OutData = getExtendValue(OutData, Out.Ty, opc);
+
+ if (DataHi == 0)
+ Out.setData(OutData, true);
+ else {
+ Register &Out2 = Reg[DataHi];
+ Value *OutData1 = TRUNC32(OutData);
+ Value *OutData2 = TRUNC32(LSHR(OutData, CONST64(32)));
+ Out.setData(OutData1, true);
+ Out2.setData(OutData2, true);
+ }
+}
+
+void IRFactory::op_qemu_st_i64(const TCGArg *args)
+{
+ IRDebug(INDEX_op_qemu_st_i64);
+
+ TCGArg DataLo = *args++;
+ TCGArg DataHi = (TCG_TARGET_REG_BITS == 32) ? *args++ : 0;
+ TCGArg AddrLo = *args++;
+ TCGArg AddrHi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) ? *args++ : 0;
+ TCGMemOpIdx oi = *args++;
+ TCGMemOp opc = get_memop(oi);
+
+ Register &In1 = Reg[DataLo];
+ Register &In2 = Reg[AddrLo];
+
+ Value *InData1 = LoadState(In1);
+ Value *InData2 = LoadState(In2);
+ Value *InData3 = (AddrHi) ? LoadState(Reg[AddrHi]) : nullptr;
+
+ AssertType(In2.Size == 32 || In2.Size == 64);
+
+ SaveStates();
+
+ Value *InData;
+ if (DataHi == 0)
+ InData = InData1;
+ else {
+ InData = LoadState(Reg[DataHi]);
+ InData = SHL(ZEXT64(InData), CONST64(32));
+ InData = OR(InData, ZEXT64(InData1));
+ }
+
+ InData = getTruncValue(InData, opc);
+ QEMUStore(InData, InData2, InData3, oi);
+}
+
+
+/*
+ * Metadata Factory
+ */
+MDFactory::MDFactory(Module *M) : UID(0), Context(M->getContext())
+{
+ Dummy = getMDNode(ArrayRef<ConstantInt*>(getUID()));
+}
+
+MDFactory::~MDFactory() {}
+
+#if defined(LLVM_V35)
+void MDFactory::setConstStatic(LLVMContext &Context, Instruction *I,
+ ArrayRef<ConstantInt*> V)
+{
+ SmallVector<Value *, 4> MDs;
+ for (unsigned i = 0, e = V.size(); i != e; ++i)
+ MDs.push_back(V[i]);
+ I->setMetadata(META_CONST, MDNode::get(Context, MDs));
+}
+
+MDNode *MDFactory::getMDNode(ArrayRef<ConstantInt*> V)
+{
+ SmallVector<Value *, 4> MDs;
+ MDs.push_back(getUID());
+ for (unsigned i = 0, e = V.size(); i != e; ++i)
+ MDs.push_back(V[i]);
+ return MDNode::get(Context, MDs);
+}
+#else
+void MDFactory::setConstStatic(LLVMContext &Context, Instruction *I,
+ ArrayRef<ConstantInt*> V)
+{
+ SmallVector<Metadata *, 4> MDs;
+ for (unsigned i = 0, e = V.size(); i != e; ++i)
+ MDs.push_back(ConstantAsMetadata::get(V[i]));
+ I->setMetadata(META_CONST, MDNode::get(Context, MDs));
+}
+
+MDNode *MDFactory::getMDNode(ArrayRef<ConstantInt*> V)
+{
+ SmallVector<Metadata *, 4> MDs;
+ MDs.push_back(ConstantAsMetadata::get(getUID()));
+ for (unsigned i = 0, e = V.size(); i != e; ++i)
+ MDs.push_back(ConstantAsMetadata::get(V[i]));
+ return MDNode::get(Context, MDs);
+}
+#endif
+
+#if defined(ENABLE_MCJIT)
+DebugLoc MDFactory::getDebugLoc(unsigned Line, unsigned Col, Function *F,
+ ArrayRef<ConstantInt*> Meta)
+{
+ Module *M = F->getParent();
+ DIBuilder DIB(*M);
+ auto File = DIB.createFile(F->getName(), "hqemu/");
+#if defined(LLVM_V35)
+ auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, F->getName(),
+ "hqemu/", "hqemu", true, "", 0);
+ auto Type = DIB.createSubroutineType(File,
+ DIB.getOrCreateArray(ArrayRef<Value *>()));
+ auto SP = DIB.createFunction(CU, F->getName(), "", File, 1, Type, false,
+ true, 1, 0, true);
+ auto Scope = DIB.createLexicalBlockFile(SP, File);
+ DebugLoc DL = DebugLoc::get(Line, Col, Scope);
+ DIB.finalize();
+ SP.replaceFunction(F);
+#elif defined(LLVM_V38) || defined(LLVM_V39)
+ auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, F->getName(),
+ "hqemu/", "hqemu", true, "", 0);
+ auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
+ auto SP = DIB.createFunction(CU, F->getName(), "", File, 1, Type, false,
+ true, 1, 0, true);
+ auto Scope = DIB.createLexicalBlockFile(SP, File, 0);
+ DebugLoc DL = DebugLoc::get(Line, Col, Scope);
+ DIB.finalize();
+ F->setSubprogram(SP);
+#else
+ auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, File,
+ "hqemu", true, "", 0);
+ auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
+ auto SP = DIB.createFunction(CU, F->getName(), "", File, 1, Type, false,
+ true, 1, DINode::FlagZero, true);
+ auto Scope = DIB.createLexicalBlockFile(SP, File, 0);
+ DebugLoc DL = DebugLoc::get(Line, Col, Scope);
+ DIB.finalize();
+ F->setSubprogram(SP);
+#endif
+
+ return DL;
+}
+#else
+DebugLoc MDFactory::getDebugLoc(unsigned Line, unsigned Col, Function *F,
+ ArrayRef<ConstantInt*> Meta)
+{
+ return DebugLoc::get(Line, Col, getMDNode(Meta));
+}
+#endif
+
+
+/*
+ * TraceBuilder()
+ */
+TraceBuilder::TraceBuilder(IRFactory *IRF, OptimizationInfo *Opt)
+ : IF(IRF), Opt(Opt), Aborted(false), Attribute(A_None), Trace(nullptr)
+{
+ GraphNode *EntryNode = Opt->getCFG();
+ if (!EntryNode)
+ hqemu_error("invalid optimization request.\n");
+
+ /* Find unique nodes. */
+ NodeVec VisitStack;
+ NodeSet Visited;
+ VisitStack.push_back(EntryNode);
+ do {
+ GraphNode *Node = VisitStack.back();
+ VisitStack.pop_back();
+ if (Visited.find(Node) == Visited.end()) {
+ Visited.insert(Node);
+
+ setUniqueNode(Node);
+
+ for (auto Child : Node->getChildren())
+ VisitStack.push_back(Child);
+ }
+ } while (!VisitStack.empty());
+
+ /* Add entry node into the building queue. */
+ NodeQueue.push_back(EntryNode);
+
+ IF->CreateSession(this);
+ IF->CreateFunction();
+}
+
+void TraceBuilder::ConvertToTCGIR(CPUArchState *env)
+{
+ TranslationBlock *tb = CurrNode->getTB();
+
+ if (LLEnv->isTraceMode()) {
+ env->image_base = (uintptr_t)tb->image - tb->pc;
+ tcg_copy_state(env, tb);
+ }
+
+ tcg_func_start(&tcg_ctx, tb);
+ gen_intermediate_code(env, tb);
+ tcg_liveness_analysis(&tcg_ctx);
+}
+
+static inline bool isVecOp(TCGOpcode opc)
+{
+ switch (opc) {
+ case INDEX_op_vector_start ... INDEX_op_vector_end:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void TraceBuilder::ConvertToLLVMIR()
+{
+ IF->CreateBlock();
+
+ auto OpcFunc = (IRFactory::FuncPtr *)IF->getOpcFunc();
+ TCGArg *VecArgs = tcg_ctx.vec_opparam_buf;
+
+ IF->NI.setTB(CurrNode->getTB());
+ for (int oi = tcg_ctx.gen_first_op_idx; oi >= 0; ) {
+ TCGOp * const op = &tcg_ctx.gen_op_buf[oi];
+ TCGArg *args = &tcg_ctx.gen_opparam_buf[op->args];
+ oi = op->next;
+
+ if (isVecOp(op->opc)) {
+ args = VecArgs;
+ VecArgs += 3;
+ }
+
+ IF->NI.setOp(op);
+ (IF->*OpcFunc[op->opc])(args);
+
+ if (isAborted()) {
+ IF->DeleteSession();
+ return;
+ }
+ }
+}
+
+void TraceBuilder::Abort()
+{
+ Aborted = true;
+}
+
+void TraceBuilder::Finalize()
+{
+ /* Reconnect links of basic blocks. The links are previously
+ set to ExitBB. */
+ for (unsigned i = 0, e = Branches.size(); i != e; ++i) {
+ BranchInst *BI = Branches[i].first;
+ GraphNode *Node = Branches[i].second;
+ IF->setSuccessor(BI, getBasicBlock(Node));
+ }
+
+ Trace = new TraceInfo(NodeUsed, Attribute);
+ IF->Compile();
+ IF->DeleteSession();
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/llvm-soft-perfmon.cpp b/src/llvm/llvm-soft-perfmon.cpp
new file mode 100644
index 0000000..a5f9a56
--- /dev/null
+++ b/src/llvm/llvm-soft-perfmon.cpp
@@ -0,0 +1,357 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include <iostream>
+#include <sstream>
+#include "tracer.h"
+#include "utils.h"
+#include "llvm.h"
+#include "llvm-target.h"
+#include "llvm-soft-perfmon.h"
+
+
+extern LLVMEnv *LLEnv;
+extern unsigned ProfileThreshold;
+extern unsigned PredictThreshold;
+
+/*
+ * Software Performance Monitor (SPM)
+ */
+void SoftwarePerfmon::ParseProfileMode(std::string &ProfileLevel)
+{
+ static std::string profile_str[SPM_NUM] = {
+ "none", "basic", "trace", "cache", "pass", "hpm", "exit", "hotspot", "all"
+ };
+ static uint64_t profile_enum[SPM_NUM] = {
+ SPM_NONE, SPM_BASIC, SPM_TRACE, SPM_CACHE, SPM_PASS, SPM_HPM,
+ SPM_EXIT, SPM_HOTSPOT, SPM_ALL,
+ };
+
+ if (ProfileLevel.empty())
+ return;
+
+ std::istringstream ss(ProfileLevel);
+ std::string token;
+ while(getline(ss, token, ',')) {
+ for (int i = 0; i != SPM_NUM; ++i) {
+ if (token == profile_str[i]) {
+ Mode |= profile_enum[i];
+ break;
+ }
+ }
+ }
+}
+
+void SoftwarePerfmon::printProfile()
+{
+ if (!isEnabled())
+ return;
+
+ if (LLVMEnv::TransMode == TRANS_MODE_NONE ||
+ LLVMEnv::TransMode == TRANS_MODE_INVALID)
+ return;
+
+ if (LLVMEnv::TransMode == TRANS_MODE_BLOCK)
+ printBlockProfile();
+ else
+ printTraceProfile();
+}
+
+void SoftwarePerfmon::printBlockProfile()
+{
+ LLVMEnv::TransCodeList &TransCode = LLEnv->getTransCode();
+ uint32_t GuestSize = 0, GuestICount = 0, HostSize = 0;
+ uint64_t TransTime = 0, MaxTime = 0;
+
+ for (auto TC : TransCode) {
+ TraceInfo *Trace = TC->Trace;
+ TranslationBlock *TB = TC->EntryTB;
+ GuestSize += TB->size;
+ GuestICount += TB->icount;
+ HostSize += TC->Size;
+ TransTime += Trace->TransTime;
+ if (Trace->TransTime > MaxTime)
+ MaxTime = Trace->TransTime;
+ }
+
+ auto &OS = DM.debug();
+ OS << "\nBlock statistic:\n"
+ << "Num of Blocks : " << TransCode.size() << "\n"
+ << "G/H Code Size : " << GuestSize << "/" << HostSize << "bytes\n"
+ << "Guest ICount : " << GuestICount << "\n"
+ << "Translation Time : " << format("%.6f", (double)TransTime * 1e-6)
+ << " seconds (max=" << MaxTime /1000 << " ms)\n";
+}
+
+static void printBasic(LLVMEnv::TransCodeList &TransCode)
+{
+ uint32_t GuestSize = 0, GuestICount = 0, HostSize = 0;
+ uint32_t NumBlock = 0, NumLoop = 0, NumExit = 0, NumIndirectBr = 0;
+ uint32_t MaxBlock = 0, MaxLoop = 0, MaxExit = 0, MaxIndirectBr = 0;
+ uint64_t TransTime = 0, MaxTime = 0;
+ unsigned NumTraces = TransCode.size();
+ std::map<unsigned, unsigned> LenDist;
+
+ for (auto TC : TransCode) {
+ TraceInfo *Trace = TC->Trace;
+ TBVec &TBs = Trace->TBs;
+ for (unsigned i = 0, e = TBs.size(); i != e; ++i) {
+ GuestSize += TBs[i]->size;
+ GuestICount += TBs[i]->icount;
+ }
+ HostSize += TC->Size;
+
+ NumBlock += TBs.size();
+ NumLoop += Trace->NumLoop;
+ NumExit += Trace->NumExit;
+ NumIndirectBr += Trace->NumIndirectBr;
+ TransTime += Trace->TransTime;
+
+ if (TBs.size() > MaxBlock)
+ MaxBlock = TBs.size();
+ if (Trace->NumLoop > MaxLoop)
+ MaxLoop = Trace->NumLoop;
+ if (Trace->NumExit > MaxExit)
+ MaxExit = Trace->NumExit;
+ if (Trace->NumIndirectBr > MaxIndirectBr)
+ MaxIndirectBr = Trace->NumIndirectBr;
+ if (Trace->TransTime > MaxTime)
+ MaxTime = Trace->TransTime;
+ LenDist[TBs.size()]++;
+ }
+
+ auto &OS = DM.debug();
+ OS << "Trace statistic:\n"
+ << "Num of Traces : " << NumTraces << "\n"
+ << "Profile Thres. : " << ProfileThreshold << "\n"
+ << "Predict Thres. : " << PredictThreshold << "\n"
+ << "G/H Code Size : " << GuestSize << "/" << HostSize << " bytes\n"
+ << "Translation Time : " << format("%.6f", (double)TransTime * 1e-6)
+ << " seconds (max=" << MaxTime /1000 << " ms)\n"
+ << "Average # Blocks : " << format("%.1f", (double)NumBlock / NumTraces)
+ << " (max=" << MaxBlock << ")\n"
+ << "Average # Loops : " << format("%.1f", (double)NumLoop / NumTraces)
+ << " (max=" << MaxLoop << ")\n"
+ << "Average # Exits : " << format("%.1f", (double)NumExit / NumTraces)
+ << " (max=" << MaxExit << ")\n"
+ << "Average # IBs : " << format("%.1f", (double)NumIndirectBr / NumTraces)
+ << " (max=" << MaxIndirectBr << ")\n"
+ << "Flush Count : " << LLEnv->getNumFlush() << "\n";
+
+ OS << "Trace length distribution: (1-" << MaxBlock << ")\n ";
+ for (unsigned i = 1; i <= MaxBlock; i++)
+ OS << LenDist[i] << " ";
+ OS << "\n";
+}
+
+static void printTraceExec(LLVMEnv::TransCodeList &TransCode)
+{
+ unsigned NumThread = 0;
+ for (auto next_cpu = first_cpu; next_cpu != nullptr;
+ next_cpu = CPU_NEXT(next_cpu))
+ NumThread++;
+
+ /* Detailed trace information and runtime counters. */
+ auto &OS = DM.debug();
+ OS << "----------------------------\n"
+ << "Trace execution information:\n";
+
+ unsigned NumTraces = TransCode.size();
+ for (unsigned i = 0; i != NumThread; ++i) {
+ unsigned TraceUsed = 0;
+
+ OS << ">\n"
+ << "Thread " << i << ":\n"
+ << " dynamic exec count\n"
+ << " id pc #loop:#exit loop ibtc exit\n";
+ for (unsigned j = 0; j != NumTraces; ++j) {
+ TraceInfo *Trace = TransCode[j]->Trace;
+ uint64_t *Counter = Trace->ExecCount[i];
+ if (Counter[0] + Counter[1] + Counter[2] == 0)
+ continue;
+ TraceUsed++;
+ OS << format("%4d", j) << ") "
+ << format("0x%08" PRIx, Trace->getEntryPC()) << " "
+ << format("%2d", Trace->NumLoop) << " "
+ << format("%2d", Trace->NumExit) << " "
+ << format("%8" PRId64, Counter[0]) << " "
+ << format("%8" PRId64, Counter[1]) << " "
+ << format("%8" PRId64, Counter[2]) << "\n";
+ }
+ OS << "Trace used: " << TraceUsed << "/" << NumTraces <<"\n";
+ }
+}
+
+static void printHPM()
+{
+ auto &OS = DM.debug();
+ OS << "Num of Insns : " << SP->NumInsns << "\n"
+ << "Num of Loads : " << SP->NumLoads << "\n"
+ << "Num of Stores : " << SP->NumStores << "\n"
+ << "Num of Branches : " << SP->NumBranches << "\n"
+ << "Sample Time : " << format("%.6f seconds", (double)SP->SampleTime * 1e-6)
+ << "\n";
+}
+
+static void printHotspot(unsigned &CoverSet,
+ std::vector<std::vector<uint64_t> *> &SampleListVec)
+{
+ auto &OS = DM.debug();
+ auto &TransCode = LLEnv->getTransCode();
+ auto &SortedCode = LLEnv->getSortedCode();
+ uint64_t BlockCacheStart = (uintptr_t)tcg_ctx_global.code_gen_buffer;
+ uint64_t BlockCacheEnd = BlockCacheStart + tcg_ctx_global.code_gen_buffer_size;
+ uint64_t TraceCacheStart = (uintptr_t)LLVMEnv::TraceCache;
+ uint64_t TraceCacheEnd = TraceCacheStart + LLVMEnv::TraceCacheSize;
+ uint64_t TotalSamples = 0;
+ uint64_t NumBlockCache = 0, NumTraceCache = 0, NumOther = 0;
+
+ for (auto *L : SampleListVec) {
+ for (uint64_t IP : *L) {
+ if (IP >= BlockCacheStart && IP < BlockCacheEnd)
+ NumBlockCache++;
+ else if (IP >= TraceCacheStart && IP < TraceCacheEnd)
+ NumTraceCache++;
+ else
+ NumOther++;
+
+ auto IT = SortedCode.upper_bound(IP);
+ if (IT == SortedCode.begin())
+ continue;
+ auto TC = (--IT)->second;
+ if (IP < (uint64_t)TC->Code + TC->Size)
+ TC->SampleCount++;;
+ }
+ delete L;
+ }
+
+ TotalSamples = NumBlockCache + NumTraceCache + NumOther;
+ if (TotalSamples == 0 || TransCode.empty()) {
+ OS << CoverSet << "% CoverSet : 0\n";
+ return;
+ }
+
+ /* Print the time breakdown of block cache, trace cache and other. */
+ char buf[128] = {'\0'};
+ double RatioBlockCache = (double)NumBlockCache * 100 / TotalSamples;
+ double RatioTraceCache = (double)NumTraceCache * 100 / TotalSamples;
+ sprintf(buf, "block (%.1f%%) trace (%.1f%%) other (%.1f%%)", RatioBlockCache,
+ RatioTraceCache, 100.0f - RatioBlockCache - RatioTraceCache);
+ OS << "Breakdown : " << buf << "\n";
+
+ /* Print the amount of traces in the cover set. */
+ std::map<TranslatedCode *, unsigned> IndexMap;
+ for (unsigned i = 0, e = TransCode.size(); i != e; ++i)
+ IndexMap[TransCode[i]] = i;
+
+ LLVMEnv::TransCodeList Covered(TransCode.begin(), TransCode.end());
+ std::sort(Covered.begin(), Covered.end(),
+ [](const TranslatedCode *a, const TranslatedCode *b) {
+ return a->SampleCount > b->SampleCount;
+ });
+
+ uint64_t CoverSamples = TotalSamples * CoverSet / 100;
+ uint64_t AccuSamples = 0;
+ unsigned NumTracesInCoverSet = 0;
+ for (TranslatedCode *TC : Covered) {
+ if (AccuSamples >= CoverSamples || TC->SampleCount == 0)
+ break;
+ NumTracesInCoverSet++;
+ AccuSamples += TC->SampleCount;
+ }
+
+ OS << CoverSet << "% CoverSet : " << NumTracesInCoverSet << "\n";
+
+ if (NumTracesInCoverSet == 0)
+ return;
+
+ /* Print the percentage of time of the traces in the cover set. */
+ if (DM.getDebugMode() & DEBUG_IR_OPT) {
+ OS << "Traces of CoverSet:\n";
+ for (unsigned i = 0; i < NumTracesInCoverSet; ++i) {
+ TranslatedCode *TC = Covered[i];
+ sprintf(buf, "%4d (%.1f%%): ", IndexMap[TC],
+ (double)TC->SampleCount * 100 / TotalSamples);
+ OS << buf;
+ int j = 0;
+ for (auto *TB: TC->Trace->TBs) {
+ std::stringstream ss;
+ ss << std::hex << TB->pc;
+ OS << (j++ == 0 ? "" : ",") << ss.str();
+ }
+ OS << "\n";
+ }
+ } else {
+ unsigned top = 10;
+
+ OS << "Percentage of CoverSet (top 10): ";
+ if (NumTracesInCoverSet < top)
+ top = NumTracesInCoverSet;
+ for (unsigned i = 0; i < top; ++i) {
+ TranslatedCode *TC = Covered[i];
+ sprintf(buf, "%.1f%%", (double)TC->SampleCount * 100 / TotalSamples);
+ OS << (i == 0 ? "" : " ") << buf;
+ }
+ OS << "\n";
+ }
+}
+
+void SoftwarePerfmon::printTraceProfile()
+{
+ auto &OS = DM.debug();
+ unsigned NumTraces = LLEnv->getTransCode().size();
+
+ OS << "\n";
+ if (NumTraces == 0) {
+ OS << "Trace statistic:\n"
+ << "Num of Traces : " << NumTraces << "\n\n";
+ return;
+ }
+
+ /* Static information */
+ if (Mode & SPM_BASIC)
+ printBasic(LLEnv->getTransCode());
+ if (Mode & SPM_EXIT)
+ OS << "Num of TraceExit : " << NumTraceExits << "\n";
+ if (Mode & SPM_HPM)
+ printHPM();
+ if (Mode & SPM_HOTSPOT)
+ printHotspot(CoverSet, SP->SampleListVec);
+
+ /* Code cache infomation - start address and size */
+ if (Mode & SPM_CACHE) {
+ size_t BlockSize = (uintptr_t)tcg_ctx_global.code_gen_ptr -
+ (uintptr_t)tcg_ctx_global.code_gen_buffer;
+ size_t TraceSize = LLEnv->getMemoryManager()->getCodeSize();
+
+ OS << "-------------------------\n"
+ << "Block/Trace Cache information:\n";
+ OS << "Block: start=" << tcg_ctx_global.code_gen_buffer
+ << " size=" << tcg_ctx_global.code_gen_buffer_size
+ << " code=" << format("%8d", BlockSize) << " (ratio="
+ << format("%.2f", (double)BlockSize * 100 / tcg_ctx_global.code_gen_buffer_size)
+ << "%)\n";
+ OS << "Trace: start=" << LLVMEnv::TraceCache
+ << " size=" << LLVMEnv::TraceCacheSize
+ << " code=" << format("%8d", TraceSize) << " (ratio="
+ << format("%.2f", (double)TraceSize * 100 / LLVMEnv::TraceCacheSize)
+ << "%)\n\n";
+ }
+
+ if (Mode & SPM_TRACE)
+ printTraceExec(LLEnv->getTransCode());
+
+ if ((Mode & SPM_PASS) && !ExitFunc.empty()) {
+ OS << "\n-------------------------\n"
+ << "Pass information:\n";
+ for (unsigned i = 0, e = ExitFunc.size(); i != e; ++i)
+ (*ExitFunc[i])();
+ }
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/llvm-target.cpp b/src/llvm/llvm-target.cpp
new file mode 100644
index 0000000..609a4ad
--- /dev/null
+++ b/src/llvm/llvm-target.cpp
@@ -0,0 +1,812 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/Support/Debug.h"
+#include "llvm-debug.h"
+#include "llvm-opc.h"
+#include "llvm-target.h"
+
+using namespace llvm::object;
+
+extern "C" {
+#if defined(TARGET_I386)
+extern const int comis_eflags[4];
+extern const int fcom_ccval[4];
+#endif
+}
+
+
+static std::vector<TCGHelperInfo> MMUHelper = {
+#if defined(CONFIG_SOFTMMU)
+ { (void *)llvm_ret_ldub_mmu, "llvm_ret_ldub_mmu", },
+ { (void *)llvm_le_lduw_mmu, "llvm_le_lduw_mmu", },
+ { (void *)llvm_le_ldul_mmu, "llvm_le_ldul_mmu", },
+ { (void *)llvm_le_ldq_mmu, "llvm_le_ldq_mmu", },
+ { (void *)llvm_be_lduw_mmu, "llvm_be_lduw_mmu", },
+ { (void *)llvm_be_ldul_mmu, "llvm_be_ldul_mmu", },
+ { (void *)llvm_be_ldq_mmu, "llvm_be_ldq_mmu", },
+ { (void *)llvm_ret_ldsb_mmu, "llvm_ret_ldsb_mmu", },
+ { (void *)llvm_le_ldsw_mmu, "llvm_le_ldsw_mmu", },
+ { (void *)llvm_le_ldsl_mmu, "llvm_le_ldsl_mmu", },
+ { (void *)llvm_be_ldsw_mmu, "llvm_be_ldsw_mmu", },
+ { (void *)llvm_be_ldsl_mmu, "llvm_be_ldsl_mmu", },
+
+ { (void *)llvm_ret_stb_mmu, "llvm_ret_stb_mmu", },
+ { (void *)llvm_le_stw_mmu, "llvm_le_stw_mmu", },
+ { (void *)llvm_le_stl_mmu, "llvm_le_stl_mmu", },
+ { (void *)llvm_le_stq_mmu, "llvm_le_stq_mmu", },
+ { (void *)llvm_be_stw_mmu, "llvm_be_stw_mmu", },
+ { (void *)llvm_be_stl_mmu, "llvm_be_stl_mmu", },
+ { (void *)llvm_be_stq_mmu, "llvm_be_stq_mmu", },
+#endif
+};
+
+
+/* Helper functions that cause side effect.
+ * For example, helpers modifying CPU states that cannot be identified,
+ * or helpers that call MMU helpers.
+ * During translating qemu_ld/st, we record MMU helper calls so that we
+ * know how to restore when page fault is handled. Unfortunately, we lose
+ * track of the MMU helper calls in a helper function and the restoration
+ * will fail. Currently, we mark such helper functions as illegal ones and
+ * we skip trace building when a call to one of them when translating
+ * op_call. */
+static std::vector<TCGHelperInfo> IllegalHelper = {
+#if defined(CONFIG_SOFTMMU)
+# if defined(TARGET_I386)
+ { (void *)helper_cmpxchg8b, "helper_cmpxchg8b", },
+ { (void *)helper_boundw, "helper_boundw", },
+ { (void *)helper_boundl, "helper_boundl", },
+# elif defined(TARGET_ARM)
+ { (void *)helper_dc_zva, "helper_dc_zva", },
+# endif
+#else
+# if defined(TARGET_AARCH64)
+ { (void *)helper_simd_tbl, "helper_simd_tbl", },
+# endif
+#endif
+};
+
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret) { (void *)helper_##name, "helper_"#name },
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) DEF_HELPER_FLAGS_0(name, flags, ret)
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) DEF_HELPER_FLAGS_0(name, flags, ret)
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) DEF_HELPER_FLAGS_0(name, flags, ret)
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) DEF_HELPER_FLAGS_0(name, flags, ret)
+
+static std::vector<TCGHelperInfo> LMTHelper = {
+#if defined(CONFIG_SOFTMMU)
+#include "atomic-helper.h"
+#endif
+};
+
+#undef DEF_HELPER_FLAGS_0
+#undef DEF_HELPER_FLAGS_1
+#undef DEF_HELPER_FLAGS_2
+#undef DEF_HELPER_FLAGS_3
+#undef DEF_HELPER_FLAGS_4
+
+
+const char *getMMUFName(const void *func)
+{
+ for (unsigned i = 0, e = MMUHelper.size(); i != e; ++i) {
+ if (func == MMUHelper[i].func)
+ return MMUHelper[i].name;
+ }
+ return "";
+}
+
+bool isMMUFunction(std::string &Name)
+{
+ for (unsigned i = 0, e = MMUHelper.size(); i != e; ++i) {
+ if (Name == MMUHelper[i].name)
+ return true;
+ }
+ return false;
+}
+
+bool isLMTFunction(std::string &Name)
+{
+ for (unsigned i = 0, e = LMTHelper.size(); i != e; ++i) {
+ if (Name == LMTHelper[i].name)
+ return true;
+ }
+ return false;
+}
+
+bool isIllegalHelper(const void *func)
+{
+ for (unsigned i = 0, e = IllegalHelper.size(); i != e; ++i) {
+ if (func == IllegalHelper[i].func)
+ return true;
+ }
+ return false;
+}
+
+/* Determine whether the function name is a system library or not. */
+bool isLibcall(std::string &Name)
+{
+ if (Name == "fmodf" || Name == "fmod" || Name == "fmodl" ||
+ Name == "abs" || Name == "labs" || Name == "llabs" ||
+ Name == "fabs" || Name == "fabsf" || Name == "fabsl" ||
+ Name == "sqrtf" || Name == "sqrt" || Name == "sqrtl" ||
+ Name == "logf" || Name == "log" || Name == "logl" ||
+ Name == "log2f" || Name == "log2" || Name == "log2l" ||
+ Name == "log10f" || Name == "log10" || Name == "log10l" ||
+ Name == "expf" || Name == "exp" || Name == "expl" ||
+ Name == "exp2f" || Name == "exp2" || Name == "exp2l" ||
+ Name == "ldexpf" || Name == "ldexp" || Name == "ldexpl" ||
+ Name == "sinf" || Name == "sin" || Name == "sinl" ||
+ Name == "cosf" || Name == "cos" || Name == "cosl" ||
+ Name == "tanf" || Name == "tan" || Name == "tanl" ||
+ Name == "atanf" || Name == "atan" || Name == "atanl" ||
+ Name == "atanf2" || Name == "atan2" || Name == "atanl2" ||
+ Name == "powf" || Name == "pow" || Name == "powl" ||
+ Name == "ceilf" || Name == "ceil" || Name == "ceill" ||
+ Name == "truncf" || Name == "trunc" || Name == "truncl" ||
+ Name == "rintf" || Name == "rint" || Name == "rintl" ||
+ Name == "lrintf" || Name == "lrint" || Name == "lrintl" ||
+ Name == "nearbyintf" || Name == "nearbyint" || Name == "nearbyintl" ||
+ Name == "floorf" || Name == "floor" || Name == "floorl" ||
+ Name == "copysignf" || Name == "copysign" || Name == "copysignl" ||
+ Name == "memcpy" || Name == "memmove" || Name == "memset" ||
+ Name == "fegetround" || Name == "fesetround" ||
+ Name == "__isinfl" || Name == "__isnanl")
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/* Determine whether the function name is a softfloat helper or not. */
+bool isSoftFPcall(std::string &Name)
+{
+ static char SoftFPName[][128] = {
+ "float16_to_float32",
+ "float32_add",
+ "float32_compare",
+ "float32_compare_quiet",
+ "float32_div",
+ "float32_mul",
+ "float32_scalbn",
+ "float32_sqrt",
+ "float32_sub",
+ "float32_to_float16",
+ "float32_to_float64",
+ "float32_to_int32",
+ "float32_to_int64",
+ "float32_to_uint32",
+ "float32_minnum",
+ "float32_maxnum",
+ "float64_add",
+ "float64_compare",
+ "float64_compare_quiet",
+ "float64_div",
+ "float64_mul",
+ "float64_scalbn",
+ "float64_sqrt",
+ "float64_sub",
+ "float64_to_float32",
+ "float64_to_int32",
+ "float64_to_int64",
+ "float64_to_uint32",
+ "float64_minnum",
+ "float64_maxnum",
+ "int32_to_float32",
+ "int32_to_float64",
+ "int64_to_float32",
+ "normalizeRoundAndPackFloat128",
+ "propagateFloat128NaN",
+ "propagateFloatx80NaN",
+ "roundAndPackFloat128",
+ "roundAndPackFloat32",
+ "roundAndPackFloat64",
+ "roundAndPackFloatx80",
+ "set_float_rounding_mode",
+ "subFloat128Sigs",
+ "subFloat32Sigs",
+ "subFloat64Sigs",
+ "subFloatx80Sigs",
+ "uint32_to_float32",
+ "uint32_to_float64",
+#if 0
+ /* FIXME: this function causes LLVM JIT error:
+ LLVM ERROR: Error reading function 'set_float_exception_flags' from bitcode file: Malformed block record */
+ "set_float_exception_flags",
+#endif
+ "addFloat32Sigs",
+ "addFloat64Sigs",
+
+ "float32_to_int32_round_to_zero",
+ "float64_to_int32_round_to_zero",
+
+ "int32_to_floatx80",
+ "int64_to_floatx80",
+ "float32_to_floatx80",
+ "float64_to_floatx80",
+ "floatx80_abs",
+ "floatx80_chs",
+ "floatx80_is_infinity",
+ "floatx80_is_neg",
+ "floatx80_is_zero",
+ "floatx80_is_zero_or_denormal",
+ "floatx80_is_any_nan",
+
+ "floatx80_to_int32",
+ "floatx80_to_int32_round_to_zero",
+ "floatx80_to_int64",
+ "floatx80_to_int64_round_to_zero",
+ "floatx80_to_float32",
+ "floatx80_to_float64",
+ "floatx80_to_float128",
+ "floatx80_round_to_int",
+ "floatx80_add",
+ "floatx80_sub",
+ "floatx80_mul",
+ "floatx80_div",
+ "floatx80_rem",
+ "floatx80_sqrt",
+ "floatx80_eq",
+ "floatx80_le",
+ "floatx80_lt",
+ "floatx80_unordered",
+ "floatx80_eq_quiet",
+ "floatx80_le_quiet",
+ "floatx80_lt_quiet",
+ "floatx80_unordered_quiet",
+ "floatx80_compare",
+ "floatx80_compare_quiet",
+ "floatx80_is_quiet_nan",
+ "floatx80_is_signaling_nan",
+ "floatx80_maybe_silence_nan",
+ "floatx80_scalbn",
+ };
+
+ for (int i = 0, e = ARRAY_SIZE(SoftFPName); i < e; i++) {
+ if (Name == SoftFPName[i])
+ return true;
+ }
+ return false;
+}
+
+/* Bind function names/addresses that are used in the softfloat helpers. */
+void AddFPUSymbols(LLVMTranslator *Translator)
+{
+#define AddSymbol(a) Translator->AddSymbol(#a, (void*)a)
+ AddSymbol(float32_add);
+ AddSymbol(float32_sub);
+ AddSymbol(float32_mul);
+ AddSymbol(float32_div);
+ AddSymbol(float32_sqrt);
+ AddSymbol(float32_scalbn);
+ AddSymbol(float32_compare);
+ AddSymbol(float32_compare_quiet);
+ AddSymbol(float32_minnum);
+ AddSymbol(float32_maxnum);
+ AddSymbol(float64_add);
+ AddSymbol(float64_sub);
+ AddSymbol(float64_mul);
+ AddSymbol(float64_div);
+ AddSymbol(float64_sqrt);
+ AddSymbol(float64_scalbn);
+ AddSymbol(float64_compare);
+ AddSymbol(float64_compare_quiet);
+ AddSymbol(float64_minnum);
+ AddSymbol(float64_maxnum);
+ AddSymbol(float16_to_float32);
+ AddSymbol(float32_to_float16);
+ AddSymbol(float32_to_float64);
+ AddSymbol(float32_to_int32);
+ AddSymbol(float32_to_int64);
+ AddSymbol(float32_to_uint32);
+ AddSymbol(float64_to_float32);
+ AddSymbol(float64_to_int32);
+ AddSymbol(float64_to_int64);
+ AddSymbol(float64_to_uint32);
+ AddSymbol(int32_to_float32);
+ AddSymbol(int32_to_float64);
+ AddSymbol(int64_to_float32);
+ AddSymbol(uint32_to_float32);
+ AddSymbol(uint32_to_float64);
+ AddSymbol(float32_to_int32_round_to_zero);
+ AddSymbol(float64_to_int32_round_to_zero);
+
+ AddSymbol(int32_to_floatx80);
+ AddSymbol(int64_to_floatx80);
+ AddSymbol(float32_to_floatx80);
+ AddSymbol(float64_to_floatx80);
+ AddSymbol(floatx80_abs);
+ AddSymbol(floatx80_chs);
+ AddSymbol(floatx80_is_infinity);
+ AddSymbol(floatx80_is_neg);
+ AddSymbol(floatx80_is_zero);
+ AddSymbol(floatx80_is_zero_or_denormal);
+ AddSymbol(floatx80_is_any_nan);
+
+ AddSymbol(floatx80_to_int32);
+ AddSymbol(floatx80_to_int32_round_to_zero);
+ AddSymbol(floatx80_to_int64);
+ AddSymbol(floatx80_to_int64_round_to_zero);
+ AddSymbol(floatx80_to_float32);
+ AddSymbol(floatx80_to_float64);
+ AddSymbol(floatx80_to_float128);
+ AddSymbol(floatx80_round_to_int);
+ AddSymbol(floatx80_add);
+ AddSymbol(floatx80_sub);
+ AddSymbol(floatx80_mul);
+ AddSymbol(floatx80_div);
+ AddSymbol(floatx80_rem);
+ AddSymbol(floatx80_sqrt);
+ AddSymbol(floatx80_eq);
+ AddSymbol(floatx80_le);
+ AddSymbol(floatx80_lt);
+ AddSymbol(floatx80_unordered);
+ AddSymbol(floatx80_eq_quiet);
+ AddSymbol(floatx80_le_quiet);
+ AddSymbol(floatx80_lt_quiet);
+ AddSymbol(floatx80_unordered_quiet);
+ AddSymbol(floatx80_compare);
+ AddSymbol(floatx80_compare_quiet);
+ AddSymbol(floatx80_is_quiet_nan);
+ AddSymbol(floatx80_is_signaling_nan);
+ AddSymbol(floatx80_maybe_silence_nan);
+ AddSymbol(floatx80_scalbn);
+
+ AddSymbol(rint);
+ AddSymbol(rintf);
+ AddSymbol(lrint);
+ AddSymbol(lrintf);
+ AddSymbol(llrint);
+ AddSymbol(llrintf);
+ AddSymbol(remainder);
+ AddSymbol(remainderf);
+ AddSymbol(fabs);
+ AddSymbol(fabsf);
+ AddSymbol(sqrt);
+ AddSymbol(sqrtf);
+ AddSymbol(trunc);
+ AddSymbol(exp2);
+ AddSymbol(log);
+ AddSymbol(ldexp);
+ AddSymbol(floor);
+ AddSymbol(ceil);
+ AddSymbol(sin);
+ AddSymbol(cos);
+ AddSymbol(tan);
+ AddSymbol(atan2);
+ AddSymbol(__isinf);
+ AddSymbol(__isnan);
+#undef AddSymbol
+}
+
+void AddLMTSymbols(LLVMTranslator *Translator)
+{
+ for (unsigned i = 0, e = LMTHelper.size(); i != e; ++i) {
+ TCGHelperInfo &H = LMTHelper[i];
+ Translator->AddSymbol(H.name, H.func);
+ }
+}
+
+void AddMMUSymbols(LLVMTranslator *Translator)
+{
+ for (unsigned i = 0, e = MMUHelper.size(); i != e; ++i) {
+ TCGHelperInfo &H = MMUHelper[i];
+ Translator->AddSymbol(H.name, H.func);
+ }
+}
+
+/* Bind function names/addresses that are used by the helpers. */
+#if defined(CONFIG_USER_ONLY)
+void AddDependentSymbols(LLVMTranslator *Translator)
+{
+ Translator->AddSymbol("helper_verify_tb", (void*)helper_verify_tb);
+ Translator->AddSymbol("helper_lookup_ibtc", (void*)helper_lookup_ibtc);
+ Translator->AddSymbol("guest_base", (void*)&guest_base);
+ Translator->AddSymbol("cpu_loop_exit", (void*)cpu_loop_exit);
+ Translator->AddSymbol("qemu_logfile", (void*)&qemu_logfile);
+ Translator->AddSymbol("qemu_loglevel", (void*)&qemu_loglevel);
+
+ Translator->AddSymbol("alignment_count", (void*)alignment_count);
+ Translator->AddSymbol("aligned_boundary", (void*)&aligned_boundary);
+
+#if defined(TARGET_I386)
+ Translator->AddSymbol("parity_table", (void*)parity_table);
+ Translator->AddSymbol("comis_eflags", (void*)comis_eflags);
+ Translator->AddSymbol("fcom_ccval", (void*)fcom_ccval);
+ Translator->AddSymbol("raise_exception", (void*)raise_exception);
+ Translator->AddSymbol("raise_exception_err", (void*)raise_exception_err);
+#endif
+
+ AddFPUSymbols(Translator);
+}
+#else
+void AddDependentSymbols(LLVMTranslator *Translator)
+{
+ Translator->AddSymbol("helper_verify_tb", (void*)helper_verify_tb);
+ Translator->AddSymbol("helper_lookup_ibtc", (void*)helper_lookup_ibtc);
+ Translator->AddSymbol("helper_lookup_cpbl", (void*)helper_lookup_cpbl);
+ Translator->AddSymbol("helper_validate_cpbl", (void*)helper_validate_cpbl);
+ Translator->AddSymbol("cpu_loop_exit", (void*)cpu_loop_exit);
+ Translator->AddSymbol("qemu_logfile", (void*)&qemu_logfile);
+ Translator->AddSymbol("qemu_loglevel", (void*)&qemu_loglevel);
+ Translator->AddSymbol("exp2", (void*)exp2);
+
+#if defined(TARGET_I386)
+ Translator->AddSymbol("parity_table", (void*)parity_table);
+ Translator->AddSymbol("comis_eflags", (void*)comis_eflags);
+ Translator->AddSymbol("fcom_ccval", (void*)fcom_ccval);
+#endif
+
+ AddFPUSymbols(Translator);
+ AddLMTSymbols(Translator);
+ AddMMUSymbols(Translator);
+}
+#endif
+
+/* Return base address and offset of a memory access pointer. */
+Value *getBaseWithConstantOffset(const DataLayout *DL, Value *Ptr,
+ intptr_t &Offset)
+{
+ Operator *PtrOp = dyn_cast<Operator>(Ptr);
+ if (!PtrOp)
+ return Ptr;
+
+ if (PtrOp->getOpcode() == Instruction::BitCast ||
+ PtrOp->getOpcode() == Instruction::IntToPtr)
+ return getBaseWithConstantOffset(DL, PtrOp->getOperand(0), Offset);
+
+ /* If this is a GEP with constant indices, we can look through it. */
+ GEPOperator *GEP = dyn_cast<GEPOperator>(PtrOp);
+ if (!GEP || !GEP->hasAllConstantIndices())
+ return Ptr;
+
+ gep_type_iterator GTI = gep_type_begin(GEP);
+ for (auto I = GEP->idx_begin(), E = GEP->idx_end(); I != E; ++I, ++GTI) {
+ ConstantInt *OpC = cast<ConstantInt>(*I);
+ if (OpC->isZero())
+ continue;
+
+ /* Handle a struct and array indices which add their offset to the
+ * pointer. */
+#if defined(LLVM_V35) || defined(LLVM_V38) || defined(LLVM_V39)
+ if (StructType *STy = dyn_cast<StructType>(*GTI))
+#else
+ if (StructType *STy = GTI.getStructTypeOrNull())
+#endif
+ Offset += DL->getStructLayout(STy)->getElementOffset(OpC->getZExtValue());
+ else {
+ intptr_t Size = DL->getTypeAllocSize(GTI.getIndexedType());
+ Offset += OpC->getSExtValue() * Size;
+ }
+ }
+
+ return getBaseWithConstantOffset(DL, GEP->getPointerOperand(), Offset);
+}
+
+static bool accumulateConstantOffset(const DataLayout *DL, GEPOperator *GEP,
+ APInt &Offset, Value *GuestBase)
+{
+ for (auto GTI = gep_type_begin(GEP), GTE = gep_type_end(GEP); GTI != GTE; ++GTI) {
+ /* Skip the operand if it is from the guest base. */
+ if (GTI.getOperand() == GuestBase)
+ continue;
+ ConstantInt *OpC = dyn_cast<ConstantInt>(GTI.getOperand());
+ if (!OpC)
+ return false;
+ if (OpC->isZero())
+ continue;
+
+ /* Handle a struct index, which adds its field offset to the pointer. */
+#if defined(LLVM_V35) || defined(LLVM_V38) || defined(LLVM_V39)
+ if (StructType *STy = dyn_cast<StructType>(*GTI)) {
+#else
+ if (StructType *STy = GTI.getStructTypeOrNull()) {
+#endif
+ unsigned ElementIdx = OpC->getZExtValue();
+ const StructLayout *SL = DL->getStructLayout(STy);
+ Offset += APInt(Offset.getBitWidth(),
+ SL->getElementOffset(ElementIdx));
+ continue;
+ }
+
+ /* For array or vector indices, scale the index by the size of the type. */
+ APInt Index = OpC->getValue().sextOrTrunc(Offset.getBitWidth());
+ Offset += Index * APInt(Offset.getBitWidth(),
+ DL->getTypeAllocSize(GTI.getIndexedType()));
+ }
+ return true;
+}
+
+Value *StripPointer(Value *Ptr)
+{
+ if (!Ptr->getType()->isPointerTy())
+ return Ptr;
+
+ SmallPtrSet<Value *, 8> Visited;
+ Visited.insert(Ptr);
+ do {
+ Operator *PtrOp = cast<Operator>(Ptr);
+ unsigned Opcode = PtrOp->getOpcode();
+ if (Opcode == Instruction::BitCast ||
+ Opcode == Instruction::IntToPtr ||
+ Opcode == Instruction::GetElementPtr)
+ Ptr = cast<Operator>(Ptr)->getOperand(0);
+ else
+ return Ptr;
+
+ if (Visited.count(Ptr))
+ break;
+ Visited.insert(Ptr);
+ } while (true);
+
+ return Ptr;
+}
+
+Value *StripPointerWithConstantOffset(const DataLayout *DL, Value *Ptr,
+ APInt &Offset, Value *GuestBase)
+{
+ if (!Ptr->getType()->isPointerTy())
+ return Ptr;
+
+ std::set<Value *> Visited;
+ Visited.insert(Ptr);
+ Value *V = Ptr;
+ do {
+ if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
+ APInt GEPOffset(Offset);
+ if (!accumulateConstantOffset(DL, GEP, GEPOffset, GuestBase))
+ return V;
+ Offset = GEPOffset;
+ V = GEP->getPointerOperand();
+ continue;
+ }
+
+ Operator *PtrOp = cast<Operator>(V);
+ unsigned Opcode = PtrOp->getOpcode();
+ if (Opcode == Instruction::BitCast || Opcode == Instruction::IntToPtr) {
+ V = cast<Operator>(V)->getOperand(0);
+ } else if (Opcode == Instruction::Add ||
+ Opcode == Instruction::Sub) {
+ if (!isa<ConstantInt>(PtrOp->getOperand(1)))
+ return V;
+
+ int64_t C = cast<ConstantInt>(PtrOp->getOperand(1))->getSExtValue();
+ if (Opcode == Instruction::Add)
+ Offset += APInt(Offset.getBitWidth(), C, true);
+ else
+ Offset -= APInt(Offset.getBitWidth(), C, true);
+ V = PtrOp->getOperand(0);
+ } else
+ return V;
+
+ if (Visited.find(V) != Visited.end())
+ break;
+ Visited.insert(V);
+ } while (true);
+
+ return V;
+}
+
+/* Remove an instruction from a basic block. Also delete any instrution used by
+ * this instruction if it is no longer being used. */
+static void DeleteDeadInstructions(Instruction *Inst)
+{
+ SmallVector<Instruction*, 16> DeadInsts;
+ DeadInsts.push_back(Inst);
+ do {
+ Instruction *I = DeadInsts.pop_back_val();
+ for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
+ Value *OpV = I->getOperand(i);
+ I->setOperand(i, nullptr);
+
+ if (!OpV->use_empty()) continue;
+
+ Instruction *OpI = dyn_cast<Instruction>(OpV);
+ if (OpI && OpI->getParent())
+ DeadInsts.push_back(OpI);
+ }
+ I->eraseFromParent();
+ } while (!DeadInsts.empty());
+}
+
+/* Perform instruction removal from the parent container. */
+void ProcessErase(IVec &toErase)
+{
+ for (auto I = toErase.begin(), E = toErase.end(); I != E; ++I)
+ DeleteDeadInstructions(*I);
+ toErase.clear();
+}
+
+
+/*
+ * JIT Event Listener
+ */
+void EventListener::NotifyFunctionEmitted(const Function &F,
+ void *Code, size_t Size,
+ const EmittedFunctionDetails &Details)
+{
+ if (!NI.Func)
+ return;
+
+ NI.Code = (uint8_t *)Code;
+ NI.Size = Size;
+}
+
+#if defined(LLVM_V35)
+void EventListener::NotifyObjectEmitted(const ObjectImage &Obj)
+{
+ StringRef Name;
+ uint64_t Code;
+ uint64_t Size;
+ unsigned NumFunc = 0;
+ DIContext* Context = DIContext::getDWARFContext(Obj.getObjectFile());
+
+ for (auto I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E; ++I) {
+ object::SymbolRef::Type SymType;
+ if (I->getType(SymType)) continue;
+ if (SymType == object::SymbolRef::ST_Function) {
+ if (I->getName(Name)) continue;
+ if (I->getAddress(Code)) continue;
+ if (I->getSize(Size)) continue;
+
+ NumFunc++;
+ if (!Context)
+ continue;
+
+ DILineInfoTable Lines = Context->getLineInfoForAddressRange(Code, Size);
+ DILineInfoTable::iterator Begin = Lines.begin();
+ DILineInfoTable::iterator End = Lines.end();
+ for (DILineInfoTable::iterator It = Begin; It != End; ++It)
+ NI.addPatch(It->second.Line, It->second.Column, It->first);
+ }
+ }
+ if (NumFunc != 1)
+ hqemu_error("internal error.\n");
+
+ NI.Code = (uint8_t *)Code;
+ NI.Size = Size;
+}
+#elif defined(LLVM_V38)
+void EventListener::NotifyObjectEmitted(const ObjectFile &Obj,
+ const RuntimeDyld::LoadedObjectInfo &L)
+{
+ OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
+ const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
+ DIContext* Context = new DWARFContextInMemory(DebugObj);
+ uint64_t Code;
+ uint64_t Size;
+ unsigned NumFunc = 0;
+
+ for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
+ SymbolRef Sym = P.first;
+ if (Sym.getType() != SymbolRef::ST_Function)
+ continue;
+
+ ErrorOr<StringRef> Name = Sym.getName();
+ if (!Name)
+ continue;
+
+ ErrorOr<uint64_t> AddrOrErr = Sym.getAddress();
+ if (AddrOrErr.getError())
+ continue;
+
+ Code = *AddrOrErr;
+ Size = P.second;
+ NumFunc++;
+
+ DILineInfoTable Lines = Context->getLineInfoForAddressRange(Code, Size);
+ DILineInfoTable::iterator Begin = Lines.begin();
+ DILineInfoTable::iterator End = Lines.end();
+ for (DILineInfoTable::iterator It = Begin; It != End; ++It)
+ NI.addPatch(It->second.Line, It->second.Column, It->first);
+ }
+
+ if (NumFunc != 1)
+ hqemu_error("internal error.\n");
+
+ NI.Code = (uint8_t *)Code;
+ NI.Size = Size;
+}
+#elif defined(LLVM_V39) || defined(LLVM_V50)
+void EventListener::NotifyObjectEmitted(const ObjectFile &Obj,
+ const RuntimeDyld::LoadedObjectInfo &L)
+{
+ OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
+ const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
+ DIContext* Context = new DWARFContextInMemory(DebugObj);
+ uint64_t Code;
+ uint64_t Size;
+ unsigned NumFunc = 0;
+
+ for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
+ SymbolRef Sym = P.first;
+ Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
+ if (!SymTypeOrErr)
+ continue;
+
+ SymbolRef::Type SymType = *SymTypeOrErr;
+ if (SymType != SymbolRef::ST_Function)
+ continue;
+
+ Expected<StringRef> Name = Sym.getName();
+ if (!Name)
+ continue;
+
+ Expected<uint64_t> AddrOrErr = Sym.getAddress();
+ if (!AddrOrErr)
+ continue;
+
+ Code = *AddrOrErr;
+ Size = P.second;
+ NumFunc++;
+
+ DILineInfoTable Lines = Context->getLineInfoForAddressRange(Code, Size);
+ DILineInfoTable::iterator Begin = Lines.begin();
+ DILineInfoTable::iterator End = Lines.end();
+ for (DILineInfoTable::iterator It = Begin; It != End; ++It)
+ NI.addPatch(It->second.Line, It->second.Column, It->first);
+ }
+
+ if (NumFunc != 1)
+ hqemu_error("internal error.\n");
+
+ NI.Code = (uint8_t *)Code;
+ NI.Size = Size;
+}
+#else
+void EventListener::NotifyObjectEmitted(const ObjectFile &Obj,
+ const RuntimeDyld::LoadedObjectInfo &L)
+{
+ OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
+ const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
+ std::unique_ptr<DIContext> Context = DWARFContext::create(DebugObj);
+ uint64_t Code;
+ uint64_t Size;
+ unsigned NumFunc = 0;
+
+ for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
+ SymbolRef Sym = P.first;
+ Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
+ if (!SymTypeOrErr)
+ continue;
+
+ SymbolRef::Type SymType = *SymTypeOrErr;
+ if (SymType != SymbolRef::ST_Function)
+ continue;
+
+ Expected<StringRef> Name = Sym.getName();
+ if (!Name)
+ continue;
+
+ Expected<uint64_t> AddrOrErr = Sym.getAddress();
+ if (!AddrOrErr)
+ continue;
+
+ Code = *AddrOrErr;
+ Size = P.second;
+ NumFunc++;
+
+ DILineInfoTable Lines = Context->getLineInfoForAddressRange(Code, Size);
+ DILineInfoTable::iterator Begin = Lines.begin();
+ DILineInfoTable::iterator End = Lines.end();
+ for (DILineInfoTable::iterator It = Begin; It != End; ++It)
+ NI.addPatch(It->second.Line, It->second.Column, It->first);
+ }
+
+ if (NumFunc != 1)
+ hqemu_error("internal error.\n");
+
+ NI.Code = (uint8_t *)Code;
+ NI.Size = Size;
+}
+#endif
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/llvm-translator.cpp b/src/llvm/llvm-translator.cpp
new file mode 100644
index 0000000..e435b1f
--- /dev/null
+++ b/src/llvm/llvm-translator.cpp
@@ -0,0 +1,924 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Analysis/InlineCost.h"
+#include "fpu/softfloat-native-def.h"
+#include "utils.h"
+#include "tracer.h"
+#include "llvm.h"
+#include "llvm-debug.h"
+#include "llvm-soft-perfmon.h"
+#include "llvm-hard-perfmon.h"
+#include "llvm-target.h"
+#include "llvm-pass.h"
+#include "llvm-opc.h"
+#include "llvm-state.h"
+#include "llvm-translator.h"
+
+
+static cl::opt<bool> DisableFastMath("disable-fast-math", cl::init(false),
+ cl::cat(CategoryHQEMU), cl::desc("Disable fast-math optimizations"));
+
+
+static char include_helper[][64] = {
+#include "llvm-helper.h"
+};
+
+extern LLVMEnv *LLEnv;
+extern hqemu::Mutex llvm_global_lock;
+extern hqemu::Mutex llvm_debug_lock;
+
+extern bool TraceCacheFull;
+
+
+#if defined(TCG_TARGET_I386)
+# if defined(__i386__)
+# define AREG0 "ebp"
+# elif defined(__x86_64__)
+# define AREG0 "r14"
+# endif
+#elif defined(TCG_TARGET_PPC64)
+# define AREG0 "r27"
+#elif defined(TCG_TARGET_ARM)
+# define AREG0 "r7"
+#elif defined(TCG_TARGET_AARCH64)
+# define AREG0 "x19"
+# define AREG1 "x28"
+#else
+# error "unsupported processor type"
+#endif
+const char *BaseRegStr = AREG0; /* The base register name */
+
+
+
+/*
+ * LLVM Translator
+ */
+LLVMTranslator::LLVMTranslator(unsigned id, CPUArchState *env)
+ : MyID(id), Env(env)
+{
+ dbg() << DEBUG_LLVM << "Starting LLVM Translator " << MyID << ".\n";
+
+ if (!Env)
+ hqemu_error("internal error. LLVMEnv is not initialized.\n");
+
+ /* Create LLVM module and basic types. */
+ InitializeModule();
+ InitializeType();
+ InitializeTarget();
+ InitializeHelpers();
+ InitializeDisasm();
+
+ /* Create the TCG IR to LLVM IR conversion module. */
+ IF = new IRFactory(this);
+
+#if defined(ENABLE_MCJIT)
+ if (MyID == 0)
+ LLEnv->getMemoryManager()->AddSymbols(Symbols);
+#endif
+
+ dbg() << DEBUG_LLVM << "LLVM Translator " << MyID << " initialized.\n";
+}
+
+LLVMTranslator::~LLVMTranslator()
+{
+ if (GuestDisAsm) delete GuestDisAsm;
+ if (HostDisAsm) delete HostDisAsm;
+ delete IF;
+ delete Mod;
+}
+
+/* Perform the initialization of the LLVM module. */
+void LLVMTranslator::InitializeModule()
+{
+ const char *p = strrchr(CONFIG_LLVM_BITCODE, '/');
+ if (!p || ++p == 0)
+ hqemu_error("unknown bitcode file.\n");
+
+ std::string Bitcode(p);
+ std::vector<std::string> Path;
+
+ Path.push_back(std::string("/etc/hqemu/").append(Bitcode));
+ p = getenv("HOME");
+ if (p)
+ Path.push_back(std::string(p).append("/.hqemu/").append(Bitcode));
+ Path.push_back(CONFIG_LLVM_BITCODE);
+
+ unsigned i = 0, e = Path.size();
+ for (; i != e; ++i) {
+ struct stat buf;
+ if (stat(Path[i].c_str(), &buf) != 0)
+ continue;
+
+ SMDiagnostic Err;
+#if defined(LLVM_V35)
+ Mod = ParseIRFile(Path[i], Err, Context);
+#else
+ std::unique_ptr<Module> Owner = parseIRFile(Path[i], Err, Context);
+ Mod = Owner.release();
+#endif
+ if (Mod)
+ break;
+ }
+
+ if (i == e)
+ hqemu_error("cannot find bitcode file %s.\n", Bitcode.c_str());
+
+ DL = getDataLayout(Mod);
+
+ dbg() << DEBUG_LLVM << "Use bitcode file " << Path[i] << ".\n";
+ dbg() << DEBUG_LLVM << "LLVM module initialized (" << Mod->getTargetTriple() << ").\n";
+}
+
+void LLVMTranslator::InitializeType()
+{
+ VoidTy = Type::getVoidTy(Context);
+ Int8Ty = IntegerType::get(Context, 8);
+ Int16Ty = IntegerType::get(Context, 16);
+ Int32Ty = IntegerType::get(Context, 32);
+ Int64Ty = IntegerType::get(Context, 64);
+ Int128Ty = IntegerType::get(Context, 128);
+
+ IntPtrTy = DL->getIntPtrType(Context);
+ Int8PtrTy = Type::getInt8PtrTy(Context, 0);
+ Int16PtrTy = Type::getInt16PtrTy(Context, 0);
+ Int32PtrTy = Type::getInt32PtrTy(Context, 0);
+ Int64PtrTy = Type::getInt64PtrTy(Context, 0);
+
+ FloatTy = Type::getFloatTy(Context);
+ DoubleTy = Type::getDoubleTy(Context);
+
+ FloatPtrTy = Type::getFloatPtrTy(Context, 0);
+ DoublePtrTy = Type::getDoublePtrTy(Context, 0);
+}
+
+/* Setup guest-dependent data structures. */
+void LLVMTranslator::InitializeTarget()
+{
+ /* TODO: any smart way to hack into CPUArchState type? */
+ Value *Base = Mod->getNamedValue("basereg");
+ if (!Base)
+ hqemu_error("cannot resolve cpu_proto.\n");
+
+ BaseReg.resize(TCG_TARGET_NB_REGS);
+ BaseReg[TCG_AREG0].RegNo = TCG_AREG0;
+ BaseReg[TCG_AREG0].Name = BaseRegStr;
+ BaseReg[TCG_AREG0].Ty = Base->getType();
+ BaseReg[TCG_AREG0].Base = nullptr;
+
+#if defined(CONFIG_USER_ONLY) && defined(AREG1)
+ if (guest_base != 0 || TARGET_LONG_BITS == 32) {
+ GuestBaseReg.Name = AREG1;
+ GuestBaseReg.Base = nullptr;
+ }
+#endif
+
+ /* Define the new types of special registers. */
+ std::map<Type *, Type *> SpecialReg;
+ DefineSpecialReg(SpecialReg);
+
+ /* Convert the CPUArchState of aggregate type to the list of single element
+ * of primitive type. */
+ intptr_t Off = 0;
+ FlattenCPUState(Base->getType()->getContainedType(0), Off, SpecialReg);
+}
+
+/* This function defines the special registers and the new types to be reset. */
+void LLVMTranslator::DefineSpecialReg(std::map<Type *, Type *> &SpecialReg)
+{
+#if defined(TARGET_I386)
+ Value *SIMDReg = Mod->getNamedValue("xmm_reg");
+ if (SIMDReg) {
+ /* remap XMMReg --> <64 x i8> */
+ Type *Int8Ty = IntegerType::get(Context, 8);
+ Type *OldTy = SIMDReg->getType()->getContainedType(0);
+ Type *NewTy = VectorType::get(Int8Ty, 16);
+ SpecialReg[OldTy] = NewTy;
+ }
+#endif
+}
+
+/* Convert the CPUArchState of the aggregate type to a list of single element of
+ * primitive type. Each element contains a pair of offset to CPUArchState and its
+ * type. This list of flattened type will be used for the state mapping pass. */
+void LLVMTranslator::FlattenCPUState(Type *Ty, intptr_t &Off,
+ std::map<Type *, Type *> &SpecialReg)
+{
+ switch (Ty->getTypeID()) {
+ default:
+ {
+ StateType[Off] = Ty;
+ Off += DL->getTypeSizeInBits(Ty) / 8;
+ break;
+ }
+ case Type::StructTyID:
+ {
+ /* Map a special register to another type with the same size as the
+ * original type. E.g., mapping a <16 * i8> type to <2 * i64>. */
+ if (SpecialReg.find(Ty) != SpecialReg.end()) {
+ Type *NewTy = SpecialReg[Ty];
+ StateType[Off] = NewTy;
+ Off += DL->getTypeSizeInBits(Ty) / 8;
+ break;
+ }
+
+ StructType *STy = cast<StructType>(Ty);
+ intptr_t Size = DL->getTypeSizeInBits(STy) / 8;
+ intptr_t SubOff;
+
+ const StructLayout *SL = DL->getStructLayout(STy);
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ SubOff = Off + SL->getElementOffset(i);
+ FlattenCPUState(STy->getElementType(i), SubOff, SpecialReg);
+ }
+
+ Off += Size;
+
+ /* Structure could have padding at the end of the struct. Expand
+ * the size of the last struct member by adding the padding size. */
+ if (Off != SubOff) {
+ intptr_t LastOff = StateType.rbegin()->first;
+ intptr_t NewSize = (Off - LastOff) * 8;
+ Type *NewTy = IntegerType::get(Context, NewSize);
+ StateType[LastOff] = NewTy;
+ }
+ break;
+ }
+ case Type::ArrayTyID:
+ {
+#if defined(CONFIG_SOFTMMU)
+ /* Do not flatten the SoftTLB because it could create a huge amount
+ * of flattened states. */
+ if (Off == offsetof(CPUArchState, tlb_table[0][0])) {
+ StateType[Off] = Ty;
+ Off += DL->getTypeSizeInBits(Ty) / 8;
+ break;
+ }
+#endif
+ ArrayType *ATy = cast<ArrayType>(Ty);
+ intptr_t ElemSize = DL->getTypeSizeInBits(ATy->getElementType()) / 8;
+ for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
+ intptr_t SubOff = Off + i * ElemSize;
+ FlattenCPUState(ATy->getElementType(), SubOff, SpecialReg);
+ }
+ Off += DL->getTypeSizeInBits(ATy) / 8;
+ break;
+ }
+ }
+}
+
+static inline void Materialize(Function &F)
+{
+#if defined(LLVM_V35)
+ std::string ErrInfo;
+ F.Materialize(&ErrInfo);
+#else
+ F.materialize();
+#endif
+}
+
+/* Materialize helper functions and compute inline costs. */
+void LLVMTranslator::InitializeHelpers()
+{
+ /* Set target-specific symbols. */
+ AddDependentSymbols(this);
+
+ /* Set const helpers. (i.e., helpers that have no side effect) */
+ InitializeConstHelpers();
+
+ /* Materialize fpu helper functions. */
+ TCGHelperInfo *FPUHelper = (TCGHelperInfo *)get_native_fpu_helpers();
+ for (int i = 0, e = num_native_fpu_helpers(); i != e; ++i) {
+ std::string ErrInfo;
+ Function *Func = Mod->getFunction(FPUHelper[i].name);
+ if (Func && Func->isMaterializable())
+ Materialize(*Func);
+ }
+
+ /* Materialize defined helper functions that are allowed for inlining. */
+ for (int i = 0, e = ARRAY_SIZE(include_helper); i < e; ++i) {
+ std::string ErrInfo;
+ Helpers[include_helper[i]] = new HelperInfo;
+ Function *Func = Mod->getFunction(include_helper[i]);
+ if (Func && Func->isMaterializable())
+ Materialize(*Func);
+ }
+
+ /* Initialize all TCG helper functions. */
+ const TCGHelperInfo *all_helpers = get_tcg_helpers();
+ for (int i = 0, e = tcg_num_helpers(); i != e; ++i) {
+ uintptr_t func = (uintptr_t)all_helpers[i].func;
+ const char *name = all_helpers[i].name;
+ if (!name)
+ hqemu_error("invalid helper name.\n");
+
+ TCGHelpers[func] = std::string("helper_") + std::string(name);
+ }
+
+ for (int i = 0, e = tcg_num_helpers(); i != e; ++i) {
+ std::string FName = std::string("helper_") +
+ std::string(all_helpers[i].name);
+ std::string FNameNoInline = FName + std::string("_noinline");
+ if (Helpers.find(FName) != Helpers.end()) {
+ HelperInfo *Helper = Helpers[FName];
+ Function *F = Mod->getFunction(FName);
+ if (!F)
+ hqemu_error("fatal error - %s\n", FName.c_str());
+ Helper->Func = F;
+ Mod->getOrInsertFunction(FNameNoInline, F->getFunctionType());
+ Helper->FuncNoInline = Mod->getFunction(FNameNoInline);
+ Helpers[FNameNoInline] = Helper;
+
+ AddSymbol(FNameNoInline, all_helpers[i].func);
+ }
+ }
+
+ /* Analyze the inline cost for each helper function and make a non-inlined
+ * counterpart object in LLVM Module. For the non-inlined function, just
+ * remap the function address in LLVM module which causes the JIT to emit a
+ * call instruction to the function address. */
+ for (int i = 0, e = tcg_num_helpers(); i != e; ++i) {
+ const TCGHelperInfo *th = &all_helpers[i];
+ std::string FName = std::string("helper_") + std::string(th->name);
+ if (Helpers.find(FName) != Helpers.end()) {
+ HelperInfo *Helper = Helpers[FName];
+ bool ret = OptimizeHelper(*Helper);
+ if (!ret) {
+ /* If the helper function consists of loops, it is not suitable
+ * to be inlined because it conflicts to the state mapping
+ * pass. */
+ Helpers.erase(FName);
+ goto skip;
+ }
+
+ Helper->CalculateMetrics(Helper->Func);
+ continue;
+ }
+skip:
+ AddSymbol(FName, th->func);
+ }
+
+ /* Add all states of the nested helpers to the calling helper.
+ * Then, calculate state boundary and determine if we can know all states
+ * (included in the nested functions) by this helper function.
+ *
+ * Note that we only allow one-level helper inlining. */
+ for (auto &I : Helpers) {
+ HelperInfo *Helper = I.second;
+ bool hasNestNestedCall = false;
+ for (CallInst *CI : Helper->NestedCalls) {
+ std::string FName = CI->getCalledFunction()->getName();
+ HelperInfo *NestedHelper = Helpers[FName];
+ Helper->States.insert(Helper->States.begin(),
+ NestedHelper->States.begin(),
+ NestedHelper->States.end());
+
+ CI->setCalledFunction(NestedHelper->FuncNoInline);
+ if (I.first != FName && NestedHelper->hasNestedCall)
+ hasNestNestedCall = true;
+ }
+ /* Clear hasNestedCall if onle one level nested functions. If the
+ * helper has only one level nested helpers, then all states are found. */
+ Helper->hasNestedCall = hasNestNestedCall;
+
+ /* Compute state boundaries. */
+ StateAnalyzer Analyzer(DL);
+ for (auto J : Helper->States)
+ Analyzer.addStateRef(J.first, J.second);
+
+ StateRange Reads, Writes;
+ Analyzer.computeStateRange(Reads, Writes);
+
+ Helper->insertState(Reads, false);
+ Helper->insertState(Writes, true);
+ }
+
+ for (auto &I : Helpers) {
+ HelperInfo *Helper = I.second;
+ Helper->States.clear();
+ Helper->NestedCalls.clear();
+ }
+}
+
+void LLVMTranslator::InitializeDisasm()
+{
+ std::string TargetTriple = "UnknownArch";
+
+#if defined(TARGET_I386)
+ #if defined(TARGET_X86_64)
+ TargetTriple = "x86_64";
+ #else
+ TargetTriple = "i386";
+ #endif
+#elif defined(TARGET_ARM)
+ #if defined(TARGET_AARCH64)
+ TargetTriple = "aarch64";
+ #else
+ TargetTriple = "arm";
+ #endif
+#elif defined(TARGET_PPC)
+ TargetTriple = "ppc";
+#endif
+
+ GuestDisAsm = MCDisasm::CreateMCDisasm(TargetTriple, false);
+ HostDisAsm = MCDisasm::CreateMCDisasm(Mod->getTargetTriple(), true);
+
+ if (GuestDisAsm)
+ dbg() << DEBUG_INASM << __func__
+ << ": use LLVM disassembler for guest (" << TargetTriple << ").\n";
+ else
+ dbg() << DEBUG_INASM << __func__
+ << ": can't find LLVM disassembler for guest ("
+ << TargetTriple << "). Use QEMU disas.\n";
+
+ if (HostDisAsm)
+ dbg() << DEBUG_OUTASM << __func__
+ << ": use LLVM disassembler for host ("
+ << Mod->getTargetTriple() << ").\n";
+ else
+ dbg() << DEBUG_OUTASM << __func__
+ << ": can't find LLVM disassembler for host ("
+ << Mod->getTargetTriple() << "). Use QEMU disas.\n";
+}
+
+static bool isLegalIntrinsic(IntrinsicInst *II)
+{
+ switch (II->getIntrinsicID()) {
+ case Intrinsic::memset:
+ case Intrinsic::memcpy:
+ case Intrinsic::memmove:
+ case Intrinsic::dbg_declare:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+/* Determine if the function argument and Ptr are alias. */
+static Value *isFromFuncArgument(Function &F, Value *Ptr)
+{
+ Ptr = StripPointer(Ptr);
+ for (auto I = F.arg_begin(), E = F.arg_end(); I != E; ++I) {
+ if (Ptr == &*I)
+ return Ptr;
+ }
+ return nullptr;
+}
+
+/* Create function pass manager to optimize the helper function. */
+static void Optimize(Function &F)
+{
+ auto FPM = new legacy::FunctionPassManager(F.getParent());
+
+ FPM->add(createReplaceIntrinsic());
+ if (!DisableFastMath)
+ FPM->add(createFastMathPass());
+ FPM->run(F);
+
+ delete FPM;
+}
+
+/* Analyze and optimize a helper function. */
+bool LLVMTranslator::OptimizeHelper(HelperInfo &Helper)
+{
+ Function &F = *Helper.Func;
+
+ /* We don't want to inline helper functions that contain loop. */
+ SmallVector<std::pair<const BasicBlock*,const BasicBlock*>, 32> BackEdges;
+ FindFunctionBackedges(F, BackEdges);
+ if (BackEdges.size())
+ return false;
+
+ Optimize(F);
+
+ /* Collect and analyze memory and call instructions. */
+ SmallVector<CallInst *, 16> Calls;
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; ++II) {
+ Instruction *I = &*II;
+
+ if (isa<LoadInst>(I) || isa<StoreInst>(I)) {
+ intptr_t Off = 0;
+ Value *Base = getBaseWithConstantOffset(DL, getPointerOperand(I), Off);
+
+ if (auto GV = dyn_cast<GlobalValue>(StripPointer(Base))) {
+ if (!GV->hasPrivateLinkage())
+ continue;
+ }
+
+ /* XXX: We assume the pointer is derived from the function argument.
+ * Skip it if not from the the function argument. */
+ Value *Arg = isFromFuncArgument(F, Base);
+ if (!Arg)
+ return false;
+
+ if (Base->getType() == BaseReg[TCG_AREG0].Ty) {
+ /* This is a load/store of CPU state plus a constant offset.
+ * Track the state. */
+ Helper.States.push_back(std::make_pair(I, Off));
+ } else {
+ /* This is a load/store of unknown pointer.
+ * Track the maximum access size. */
+ Type *Ty = cast<PointerType>(Arg->getType())->getElementType();
+ intptr_t Size = DL->getTypeSizeInBits(Ty) / 8;
+ Helper.mayConflictArg = true;
+ Helper.ConflictSize = std::max(Helper.ConflictSize, Size);
+ }
+ } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
+ Calls.push_back(CI);
+ }
+ }
+
+ /* Analyze calls. */
+ for (CallInst *CI : Calls) {
+ if (CI->isInlineAsm())
+ continue;
+
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI)) {
+ if (!isLegalIntrinsic(II))
+ return false;
+ continue;
+ }
+
+ if (!CI->getCalledFunction())
+ return false;
+
+ std::string FName = CI->getCalledFunction()->getName();
+ if (isLibcall(FName) || isSoftFPcall(FName)) {
+ /* Libcalls/SoftFPCalls are always const function. Mark it. */
+ ConstantInt *Meta[] = { CONST32(0) };
+ MDFactory::setConstStatic(Context, CI, Meta);
+ continue;
+ }
+
+ if (Helpers.find(FName) == Helpers.end())
+ return false;
+
+ Helper.hasNestedCall = true;
+ Helper.NestedCalls.push_back(CI);
+ }
+
+ return true;
+}
+
+/* Figure out an approximation for how many instructions will be constant
+ * folded if the specified value is constant. */
+static unsigned CountCodeReductionForConstant(Value *V, CodeMetrics &Metrics)
+{
+ unsigned IndirectCallBonus;
+ IndirectCallBonus = -InlineConstants::IndirectCallThreshold;
+
+ unsigned Reduction = 0;
+ for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI) {
+ User *U = UI->getUser();
+ if (isa<BranchInst>(U) || isa<SwitchInst>(U)) {
+ /* We will be able to eliminate all but one of the successors. */
+ const TerminatorInst &TI = cast<TerminatorInst>(*U);
+ const unsigned NumSucc = TI.getNumSuccessors();
+ unsigned Instrs = 0;
+ for (unsigned I = 0; I != NumSucc; ++I)
+ Instrs += Metrics.NumBBInsts[TI.getSuccessor(I)];
+ /* We don't know which blocks will be eliminated, so use the average size. */
+ Reduction += InlineConstants::InstrCost*Instrs*(NumSucc-1)/NumSucc*2;
+ } else if (CallInst *CI = dyn_cast<CallInst>(U)) {
+ /* Turning an indirect call into a direct call is a BIG win */
+ if (CI->getCalledValue() == V)
+ Reduction += IndirectCallBonus;
+ } else if (InvokeInst *II = dyn_cast<InvokeInst>(U)) {
+ /* Turning an indirect call into a direct call is a BIG win */
+ if (II->getCalledValue() == V)
+ Reduction += IndirectCallBonus;
+ } else {
+ Instruction &Inst = cast<Instruction>(*U);
+
+ if (Inst.mayReadFromMemory() || Inst.mayHaveSideEffects() ||
+ isa<AllocaInst>(Inst))
+ continue;
+
+ bool AllOperandsConstant = true;
+ for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i)
+ if (!isa<Constant>(Inst.getOperand(i)) && Inst.getOperand(i) != V) {
+ AllOperandsConstant = false;
+ break;
+ }
+
+ if (AllOperandsConstant) {
+ /* We will get to remove this instruction... */
+ Reduction += InlineConstants::InstrCost;
+ Reduction += CountCodeReductionForConstant(&Inst, Metrics);
+ }
+ }
+ }
+ return Reduction;
+}
+
+/* Figure out an approximation of how much smaller the function will be if
+ * it is inlined into a context where an argument becomes an alloca. */
+static unsigned CountCodeReductionForAlloca(Value *V)
+{
+ if (!V->getType()->isPointerTy()) return 0;
+
+ unsigned Reduction = 0;
+ for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI) {
+ Instruction *I = cast<Instruction>(UI->getUser());
+
+ if (isa<LoadInst>(I) || isa<StoreInst>(I))
+ Reduction += InlineConstants::InstrCost;
+ else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(I)) {
+ /* If the GEP has variable indices, we won't be able to do much with it. */
+ if (GEP->hasAllConstantIndices())
+ Reduction += CountCodeReductionForAlloca(GEP);
+ } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(I)) {
+ /* Track pointer through bitcasts. */
+ Reduction += CountCodeReductionForAlloca(BCI);
+ } else
+ return 0;
+ }
+
+ return Reduction;
+}
+
+void HelperInfo::CalculateMetrics(Function *F)
+{
+ Metrics.NumInsts = 0;
+
+ for (auto FI = F->begin(); FI != F->end(); FI++) {
+ unsigned NumInsts = 0;
+ BasicBlock *BB = &*FI;
+ for (auto BI = FI->begin(); BI != FI->end(); BI++) {
+ if (isa<PHINode>(BI)) /* PHI nodes don't count. */
+ continue;
+ NumInsts++;
+ }
+ Metrics.NumBlocks++;
+ Metrics.NumInsts += NumInsts;
+ Metrics.NumBBInsts[BB] = NumInsts;
+ }
+
+ ArgumentWeights.reserve(F->arg_size());
+ for (auto I = F->arg_begin(), E = F->arg_end(); I != E; ++I) {
+ Value *V = &*I;
+ ArgumentWeights.push_back(ArgInfo(
+ CountCodeReductionForConstant(V, Metrics),
+ CountCodeReductionForAlloca(V)));
+ }
+}
+
+void LLVMTranslator::InitializeConstHelpers()
+{
+#if defined(TARGET_I386)
+ ConstHelpers.insert("helper_outb");
+ ConstHelpers.insert("helper_inb");
+ ConstHelpers.insert("helper_outw");
+ ConstHelpers.insert("helper_inw");
+ ConstHelpers.insert("helper_outl");
+ ConstHelpers.insert("helper_inl");
+#elif defined(TARGET_ARM)
+ ConstHelpers.insert("helper_vfp_tosis");
+ ConstHelpers.insert("helper_vfp_tosid");
+ ConstHelpers.insert("helper_vfp_tosizs");
+ ConstHelpers.insert("helper_vfp_tosizd");
+ ConstHelpers.insert("helper_vfp_touis");
+ ConstHelpers.insert("helper_vfp_touid");
+ ConstHelpers.insert("helper_vfp_touizs");
+ ConstHelpers.insert("helper_vfp_touizd");
+
+ ConstHelpers.insert("helper_vfp_sitos");
+ ConstHelpers.insert("helper_vfp_sitod");
+ ConstHelpers.insert("helper_vfp_uitos");
+ ConstHelpers.insert("helper_vfp_uitod");
+
+ ConstHelpers.insert("helper_vfp_fcvtds");
+ ConstHelpers.insert("helper_vfp_fcvtsd");
+
+ ConstHelpers.insert("helper_vfp_cmps");
+ ConstHelpers.insert("helper_vfp_cmpd");
+ ConstHelpers.insert("helper_vfp_cmpes");
+ ConstHelpers.insert("helper_vfp_cmped");
+
+#if defined(TARGET_AARCH64)
+ ConstHelpers.insert("helper_vfp_tosls");
+ ConstHelpers.insert("helper_vfp_tosld");
+ ConstHelpers.insert("helper_vfp_sqtos");
+ ConstHelpers.insert("helper_vfp_sqtod");
+ ConstHelpers.insert("helper_vfp_uqtos");
+ ConstHelpers.insert("helper_vfp_uqtod");
+
+ ConstHelpers.insert("helper_vfp_cmps_a64");
+ ConstHelpers.insert("helper_vfp_cmpd_a64");
+ ConstHelpers.insert("helper_vfp_cmpes_a64");
+ ConstHelpers.insert("helper_vfp_cmped_a64");
+ ConstHelpers.insert("helper_vfp_minnums");
+ ConstHelpers.insert("helper_vfp_maxnums");
+ ConstHelpers.insert("helper_vfp_minnumd");
+ ConstHelpers.insert("helper_vfp_maxnumd");
+
+ ConstHelpers.insert("helper_get_cp_reg64");
+ ConstHelpers.insert("helper_dc_zva");
+#endif
+#endif
+}
+
+void LLVMTranslator::Abort(TraceBuilder &Builder)
+{
+ target_ulong pc = Builder.getEntryNode()->getGuestPC();
+ dbg() << DEBUG_LLVM << __func__
+ << ": abort trace pc " << format("0x%" PRIx "", pc) << "\n";
+}
+
+/* Make a jump from the head block in the block code cache to the translated
+ * host code of this region in the optimized code cache. Also patch previous
+ * built regions that have direct branch to this region. */
+void LLVMTranslator::Commit(TraceBuilder &Builder)
+{
+ bool Invalid = false;
+ OptimizationInfo *Opt = Builder.getOpt();
+ TraceInfo *Trace = Builder.getTrace();
+ TBVec &TBs = Trace->TBs;
+
+ for (unsigned i = 0, e = TBs.size(); i != e; ++i) {
+ if (TBs[i]->mode == BLOCK_INVALID) {
+ Invalid = true;
+ break;
+ }
+ }
+
+ if (Invalid || llvm_check_cache() == 1) {
+ delete Trace;
+ delete Opt;
+ return;
+ }
+
+ TranslatedCode *TC = new TranslatedCode;
+ TC->Active = true;
+ TC->Size = NI.Size;
+ TC->Code = NI.Code;
+ TC->EntryTB = Trace->getEntryTB();
+ TC->Restore = NI.Restore;
+ TC->Trace = Trace;
+
+ /* If we go here, this is a legal trace. */
+ LLVMEnv::ChainSlot &ChainPoint = LLEnv->getChainPoint();
+ TranslationBlock *EntryTB = TC->EntryTB;
+
+ hqemu::MutexGuard locked(llvm_global_lock);
+
+ for (unsigned i = 0; i != NI.NumChainSlot; ++i)
+ ChainPoint[NI.ChainSlot[i].Key] = NI.ChainSlot[i].Addr;
+
+ TraceID tid = LLEnv->insertTransCode(TC);
+ EntryTB->tid = tid;
+ EntryTB->mode = BLOCK_OPTIMIZED;
+ EntryTB->opt_ptr = TC->Code;
+
+ /* Set the jump from the block to the trace */
+ patch_jmp(tb_get_jmp_entry(EntryTB), TC->Code);
+
+ if (!SP->isEnabled()) {
+ delete Trace;
+ TC->Trace = nullptr;
+ }
+
+ delete Opt;
+}
+
+void LLVMTranslator::dump(CPUArchState *env, TranslationBlock *tb)
+{
+ auto &DebugMode = DM.getDebugMode();
+ if (DebugMode & (DEBUG_INASM | DEBUG_OP)) {
+ hqemu::MutexGuard locked(llvm_debug_lock);
+ dbg() << DEBUG_LLVM << "Translator " << MyID << " dumps asm...\n";
+ if (DebugMode & DEBUG_INASM)
+ printAsm(Env, tb);
+ if (DebugMode & DEBUG_OP)
+ printOp(Env, tb);
+ }
+}
+
+void LLVMTranslator::GenBlock(CPUArchState *env, OptimizationInfo *Opt)
+{
+ struct timeval start, end;
+ if (SP->isEnabled())
+ gettimeofday(&start, nullptr);
+
+ TraceBuilder Builder(IF, Opt);
+ GraphNode *Node = Builder.getNextNode();
+ if (!Node)
+ hqemu_error("fatal error.\n");
+
+ Builder.ConvertToTCGIR(env);
+
+ if (DM.getDebugMode() & (DEBUG_INASM | DEBUG_OP))
+ dump(env, Opt->getCFG()->getTB());
+
+ Builder.ConvertToLLVMIR();
+ Builder.Finalize();
+
+ if (SP->isEnabled()) {
+ gettimeofday(&end, nullptr);
+ Builder.getTrace()->setTransTime(&start, &end);
+ }
+
+ Commit(Builder);
+}
+
+void LLVMTranslator::GenTrace(CPUArchState *env, OptimizationInfo *Opt)
+{
+ struct timeval start, end;
+ if (SP->isEnabled())
+ gettimeofday(&start, nullptr);
+
+ TraceBuilder Builder(IF, Opt);
+ for (;;) {
+ GraphNode *Node = Builder.getNextNode();
+ if (!Node)
+ break;
+
+ Builder.ConvertToTCGIR(Env);
+
+ if (DM.getDebugMode() & (DEBUG_INASM | DEBUG_OP))
+ dump(Env, Node->getTB());
+
+ Builder.ConvertToLLVMIR();
+
+ if (Node->getTB()->mode == BLOCK_INVALID || Builder.isAborted()) {
+ Abort(Builder);
+ return;
+ }
+ }
+ Builder.Finalize();
+
+ if (SP->isEnabled()) {
+ gettimeofday(&end, nullptr);
+ Builder.getTrace()->setTransTime(&start, &end);
+ }
+
+ Commit(Builder);
+}
+
+/* Display the guest assembly code of the given basic block. */
+void LLVMTranslator::printAsm(CPUArchState *env, TranslationBlock *tb)
+{
+ auto &OS = DM.debug();
+ if (GuestDisAsm) {
+ OS << "----------------\n"
+ << "IN: [size=" << tb->size << "]\n";
+#if defined(CONFIG_USER_ONLY)
+ GuestDisAsm->PrintInAsm((uint64_t)g2h(tb->pc), tb->size, tb->pc);
+#else
+ GuestDisAsm->PrintInAsm((uint64_t)tb->image, tb->size, tb->pc);
+#endif
+ OS << "\n";
+ return;
+ }
+
+#if defined(CONFIG_USER_ONLY)
+ /* The guest is not supported by the LLVM MCDisassembler. Use QEMU disas. */
+ int disas_flags = 0;
+
+#if defined(TARGET_I386)
+ #if defined(TARGET_X86_64)
+ if ((tb->flags >> HF_CS64_SHIFT) & 1)
+ disas_flags = 2;
+ else
+ #endif
+ disas_flags = !((tb->flags >> HF_CS32_SHIFT) & 1);
+#elif defined(TARGET_ARM)
+ #if defined(TARGET_AARCH64)
+ disas_flags = 4 | (0 << 1);
+ #else
+ disas_flags = env->thumb;
+ #endif
+#elif defined(TARGET_PPC)
+ int le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
+ disas_flags = env->bfd_mach;
+ disas_flags |= le_mode << 16;
+#endif
+
+ OS << "----------------\n";
+ OS << "IN: [size=" << tb->size << "%d]\n";
+ target_disas(stderr, ENV_GET_CPU(env), tb->pc, tb->size, disas_flags);
+ OS << "\n";
+#endif
+}
+
+extern "C" void printops(const char *outbuf) {
+ DM.debug() << outbuf;
+}
+
+/* Display TCG IR of the given basic block. */
+void LLVMTranslator::printOp(CPUArchState *env, TranslationBlock *tb)
+{
+ auto &OS = DM.debug();
+ OS << "OP:\n";
+ tcg_dump_ops_fn(&tcg_ctx, printops);
+ OS << "\n";
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/llvm.cpp b/src/llvm/llvm.cpp
new file mode 100644
index 0000000..80c8473
--- /dev/null
+++ b/src/llvm/llvm.cpp
@@ -0,0 +1,1251 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include <fstream>
+#include <dlfcn.h>
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm-types.h"
+#include "llvm-annotate.h"
+#include "llvm-soft-perfmon.h"
+#include "llvm-hard-perfmon.h"
+#include "llvm-translator.h"
+#include "llvm-state.h"
+#include "llvm-opc.h"
+#include "llvm.h"
+#include "tracer.h"
+#include "optimization.h"
+
+
+#define MAX_TRANSLATORS 8
+#define MAX_SEARCH_DEPTH 8
+#define ACTIVE_QUEUE_SIZE (1 << 16)
+#define ACTIVE_QUEUE_MASK (ACTIVE_QUEUE_SIZE - 1)
+
+
+cl::OptionCategory CategoryHQEMU("HQEMU Options");
+
+static cl::opt<std::string> DebugLevel("debuglv", cl::init(""),
+ cl::cat(CategoryHQEMU), cl::desc("Set debug level"));
+
+static cl::opt<std::string> DebugFile("debugfile", cl::init(""),
+ cl::cat(CategoryHQEMU), cl::desc("Set debug file (default=stderr)"));
+
+static cl::opt<std::string> ProfileLevel("profile", cl::init(""),
+ cl::cat(CategoryHQEMU), cl::desc("Set profile level"));
+
+static cl::opt<unsigned> NumThreads("threads", cl::init(1),
+ cl::cat(CategoryHQEMU), cl::desc("Number of threads used in the hybridm mode"));
+
+static cl::opt<unsigned> NumTranslations("count", cl::init(-1U),
+ cl::cat(CategoryHQEMU),
+ cl::desc("Maximum number of traces to translate (default=2^32)"));
+
+static cl::opt<unsigned> NETProfileThreshold("net-profile",
+ cl::init(NET_PROFILE_THRESHOLD),
+ cl::cat(CategoryHQEMU),
+ cl::desc("Hot threshold value for NET trace creation (default=50)"));
+
+static cl::opt<unsigned> NETPredictThreshold("net-predict",
+ cl::init(NET_PREDICT_THRESHOLD),
+ cl::cat(CategoryHQEMU),
+ cl::desc("Maximum number of basic blocks in a NET trace (default=64)"));
+
+static cl::opt<bool> DisableNETPlus("disable-netplus", cl::init(false),
+ cl::cat(CategoryHQEMU),
+ cl::desc("Disable NETPlus algorithm (use NET trace formation only)"));
+
+
+/* static members */
+bool LLVMEnv::InitOnce = false;
+int LLVMEnv::TransMode = TRANS_MODE_NONE;
+uint8_t *LLVMEnv::TraceCache = nullptr;
+size_t LLVMEnv::TraceCacheSize = 0;
+bool LLVMEnv::RunWithVTune = false;
+
+LLVMDebug DM;
+LLVMEnv *LLEnv;
+QueueManager *QM;
+AnnotationFactory *AF;
+SoftwarePerfmon *SP;
+HardwarePerfmon *HP;
+ControlFlowGraph GlobalCFG;
+
+hqemu::Mutex llvm_global_lock;
+hqemu::Mutex llvm_debug_lock;
+
+bool ThreadStop = false;
+bool ThreadExit = false;
+bool TraceCacheFull = false;
+unsigned NumPendingThread = 0;
+int MonThreadID;
+
+extern unsigned ProfileThreshold;
+extern unsigned PredictThreshold;
+
+/*
+ * LLVMEnv()
+ * Intialize LLVM translator(s) and globally shared resources. The LLVMEnv
+ * instance must be initialized before using the underlying transaltion
+ * service and should be initialized only ONCE.
+ */
+LLVMEnv::LLVMEnv() : NumTranslator(1), UseThreading(false), NumFlush(0)
+{
+ /* Set LLVMEnv pointer first so other classes can access it. */
+ LLEnv = this;
+
+ ParseCommandLineOptions();
+
+ /* Check if HQEMU is running in Intel VTune. */
+ ProbeIntelVTune();
+
+ /* Initialize debugger and software profiler. */
+ DM.setDebugMode(DebugLevel, DebugFile);
+
+ dbg() << DEBUG_LLVM << "Initializing LLVM Environment.\n";
+
+ /* Initialize LLVM targets. */
+ InitializeAllTargetInfos();
+ InitializeAllTargets();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+ InitializeAllTargetMCs();
+ InitializeAllDisassemblers();
+
+ MonThreadID = gettid();
+ qemu_mutex_init(&mutex);
+
+ Translator.resize(NumTranslator);
+ HelperThread.resize(NumTranslator);
+ ThreadEnv.resize(NumTranslator);
+ for (unsigned i = 0; i < NumTranslator; ++i) {
+ CPUState *cpu = ThreadEnv[i] = cpu_create();
+ CPUArchState *env = (CPUArchState *)cpu->env_ptr;
+ cpu->cpu_index = -i -1;
+ env->build_mode = BUILD_LLVM;
+ Translator[i] = nullptr;
+ }
+
+ QM = new QueueManager;
+ AF = new AnnotationFactory;
+ SP = new SoftwarePerfmon(ProfileLevel);
+ HP = new HardwarePerfmon;
+
+ if (SP->Mode & (SPM_HPM | SPM_HOTSPOT)) {
+ if (RunWithVTune)
+ DM.debug() << "Warning: cannot profile hpm,hotspot inside VTune. Disable it.\n";
+ }
+
+ /* Create the memory manager and intialize the optimized code cache. There
+ * is only copy of the optimized code cache and is shared by all underlying
+ * translators. */
+ MM = std::shared_ptr<MemoryManager>(
+ MemoryManager::Create(TraceCache, TraceCacheSize));
+
+ CreateTranslator();
+
+ /* Initialize HPM after the LLVM thread is initialized. */
+ HP->Init(MonThreadID);
+
+ dbg() << DEBUG_LLVM << "LLVM Environment initialized. "
+ << format("guest_base=0x%lx.\n", GUEST_BASE)
+ << format("\tBlock code cache: addr=%p size=%zd bytes.\n",
+ tcg_ctx_global.code_gen_buffer,
+ tcg_ctx_global.code_gen_buffer_size)
+ << format("\tTrace code cache: addr=%p size=%zd bytes.\n",
+ TraceCache, TraceCacheSize);
+}
+
+LLVMEnv::~LLVMEnv()
+{
+ if (TransMode == TRANS_MODE_BLOCK) {
+ size_t BlockCodeSize = MM->getCodeSize();
+ dbg() << DEBUG_LLVM << "Finalizing LLVM environment."
+ << "\n\tBlock code size: " << BlockCodeSize << " bytes.\n";
+ } else {
+ size_t BlockCodeSize = (uintptr_t)tcg_ctx_global.code_gen_ptr -
+ (uintptr_t)tcg_ctx_global.code_gen_buffer;
+ size_t TraceCodeSize = MM->getCodeSize();
+ dbg() << DEBUG_LLVM << "Finalizing LLVM environment."
+ << "\n\tBlock code size : " << format("%8d", BlockCodeSize) << " bytes"
+ << "\n\tTrace code size : " << format("%8d", TraceCodeSize) << " bytes"
+ << "\n\tTrace/Block ratio: "
+ << format("%.2f%%\n\n", (double)TraceCodeSize * 100 / BlockCodeSize);
+ }
+
+ /* Stop the HPM early so that the handling thread will no longer receive
+ * the overflow signal. */
+ delete HP;
+
+ if (UseThreading && !ThreadExit)
+ StopThread();
+
+ DeleteTranslator();
+
+ for (int i = 0, e = tcg_ctx_global.tb_ctx->nb_tbs; i != e; ++i) {
+ if (tbs[i].image) delete_image(&tbs[i]);
+ if (tbs[i].state) delete_state(&tbs[i]);
+ if (tbs[i].chain) ChainInfo::free(&tbs[i]);
+ }
+
+ SP->printProfile();
+
+ delete SP;
+ delete QM;
+ delete AF;
+
+ /* Delete all translated code. */
+ for (unsigned i = 0, e = TransCode.size(); i != e; ++i)
+ delete TransCode[i];
+
+ dbg() << DEBUG_LLVM << "LLVM environment finalized.\n";
+
+ DM.Flush();
+}
+
+void LLVMEnv::ProbeIntelVTune()
+{
+#if defined(__i386__)
+#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32"
+#elif defined(__x86_64__)
+#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64"
+#else
+#define NEW_DLL_ENVIRONMENT_VAR ""
+#endif
+#define DLL_ENVIRONMENT_VAR "VS_PROFILER"
+#define DEFAULT_DLLNAME "libJitPI.so"
+
+ if (!strcmp(NEW_DLL_ENVIRONMENT_VAR, ""))
+ return;
+
+ void *DLLHandle = nullptr;
+ char *DLLName = getenv(NEW_DLL_ENVIRONMENT_VAR);
+ if (!DLLName)
+ DLLName = getenv(DLL_ENVIRONMENT_VAR);
+
+ if (DLLName) {
+ DLLHandle = dlopen(DLLName, RTLD_LAZY);
+ if (DLLHandle)
+ goto has_vtune;
+ }
+ if (!DLLHandle) {
+ DLLHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);
+ if (DLLHandle)
+ goto has_vtune;
+ }
+ return;
+
+has_vtune:
+ dlclose(DLLHandle);
+ RunWithVTune = true;
+}
+
+#if defined(LLVM_V35) || defined(LLVM_V38) || defined(LLVM_V39) || defined(LLVM_V50)
+static void PrintVersion()
+{
+ Triple HostTriple(sys::getDefaultTargetTriple());
+ raw_ostream &OS = outs();
+
+ OS << "HQEMU (http://itanium.iis.sinica.edu.tw/hqemu/):\n"
+ << " HQEMU version: " << PACKAGE_VERSION_MAJOR << "."
+ << PACKAGE_VERSION_MINOR << "\n"
+ << " QEMU version: " << QEMU_VERSION << "\n"
+ << " Guest ISA: " << TARGET_NAME << "\n"
+ << " Host ISA: " << HostTriple.getArchName() << "\n";
+ OS << "\n";
+ cl::PrintVersionMessage();
+}
+#else
+static void PrintVersion(raw_ostream &OS)
+{
+ Triple HostTriple(sys::getDefaultTargetTriple());
+ OS << "HQEMU (http://itanium.iis.sinica.edu.tw/hqemu/):\n"
+ << " HQEMU version: " << PACKAGE_VERSION_MAJOR << "."
+ << PACKAGE_VERSION_MINOR << "\n"
+ << " QEMU version: " << QEMU_VERSION << "\n"
+ << " Guest ISA: " << TARGET_NAME << "\n"
+ << " Host ISA: " << HostTriple.getArchName() << "\n";
+ OS << "\n";
+ cl::PrintVersionMessage();
+}
+#endif
+
+void LLVMEnv::ParseCommandLineOptions()
+{
+ /* Disable passes that would change the DebugLoc metadata which
+ * may fail our block/trace chaining. */
+ static const char *argv[] = {
+ "-disable-tail-duplicate",
+ "-disable-early-taildup",
+ "-disable-block-placement",
+#if defined(TCG_TARGET_ARM) || defined(TCG_TARGET_AARCH64)
+ "-disable-branch-fold",
+#elif defined(TCG_TARGET_PPC64)
+ "-disable-branch-fold",
+ "-ppc-asm-full-reg-names",
+#endif
+ };
+
+ cl::SetVersionPrinter(PrintVersion);
+
+ /* Hide LLVM builtin options. */
+#if defined(LLVM_V35)
+ StringMap<cl::Option*> opts;
+ cl::getRegisteredOptions(opts);
+#else
+ StringMap<cl::Option*> &opts = cl::getRegisteredOptions();
+#endif
+ for (auto &I : opts) {
+ auto opt = I.second;
+ if (opt->Category == &cl::GeneralCategory)
+ opt->setHiddenFlag(cl::Hidden);
+ }
+
+ dbg() << DEBUG_LLVM << "Parsing command line options.\n";
+
+ /* Get translation mode from LLVM_MODE. */
+ TransMode = getTransMode();
+ if (TransMode == TRANS_MODE_INVALID)
+ hqemu_error("invalid LLVM_MODE.\n");
+
+ /* Get command-line options from LLVM_CMD and update them in LLVM. */
+ std::vector<const char *> PassArgs;
+ char *p = getenv("LLVM_CMD");
+ if (p) {
+ const char *token = strtok(p, " ");
+ while (token) {
+ PassArgs.push_back(token);
+ token = strtok(nullptr, " ");
+ }
+ }
+
+ SmallVector<const char *, 16> Args;
+ Args.push_back("qemu-" TARGET_NAME);
+ for (unsigned i = 0, e = ARRAY_SIZE(argv); i < e; ++i)
+ Args.push_back(argv[i]);
+ for (const char *s : PassArgs)
+ Args.push_back(s);
+ Args.push_back(nullptr);
+ cl::ParseCommandLineOptions(Args.size() - 1,
+ const_cast<char **>(&Args[0]));
+
+ /* Overwrite NET trace formation parameters. */
+ ProfileThreshold = NETProfileThreshold;
+ PredictThreshold = NETPredictThreshold;
+
+ /*
+ * After this point, command-line options are all set.
+ * We need to update functions that are controlled by the options.
+ */
+
+ /* Update threading number if hybridm is enabled. */
+ UseThreading = (TransMode == TRANS_MODE_HYBRIDM);
+ if (!UseThreading)
+ return;
+
+ if (NumThreads != 1)
+ NumTranslator = (NumThreads < 1) ? 1 : MIN(MAX_TRANSLATORS, NumThreads);
+}
+
+#if defined(CONFIG_USER_ONLY)
+#define TIMEOUT_INTERVAL 1
+#else
+#define TIMEOUT_INTERVAL 1000
+#endif
+
+/*
+ * WorkerFunc()
+ * The thread routine of the LLVM translation threads.
+ */
+void *WorkerFunc(void *argv)
+{
+ unsigned MyID = (unsigned long)argv;
+ LLVMTranslator *Translator = LLEnv->getTranslator(MyID);
+ MemoryManager *MM = LLEnv->getMemoryManager().get();
+ CPUState *cpu = LLEnv->getThreadEnv(MyID);
+ CPUArchState *env = (CPUArchState *)cpu->env_ptr;
+
+ /* Block all signals. */
+ sigset_t set;
+ sigfillset(&set);
+ pthread_sigmask(SIG_SETMASK, &set, nullptr);
+
+ copy_tcg_context();
+ optimization_init(env);
+
+ Atomic<unsigned>::inc_return(&NumPendingThread);
+
+ for (;;) {
+ /* Exit the loop if a request is received. */
+ if (unlikely(ThreadExit))
+ break;
+
+ if (unlikely(ThreadStop)) {
+ Atomic<unsigned>::inc_return(&NumPendingThread);
+ while (ThreadStop)
+ usleep(100);
+
+ Translator = LLEnv->getTranslator(MyID);
+ }
+
+ /* Exit the loop if the trace cache is full. */
+ if (unlikely(!MM->isSizeAvailable())) {
+ TraceCacheFull = true;
+ ThreadStop = true;
+ continue;
+ }
+
+ /* Everything is fine. Process an optimization request. */
+ OptimizationInfo *Opt = (OptimizationInfo *)QM->Dequeue();
+ if (Opt)
+ Translator->GenTrace(env, Opt);
+
+ usleep(TIMEOUT_INTERVAL);
+ }
+
+ pthread_exit(nullptr);
+ return nullptr;
+}
+
+/*
+ * CreateTranslator()
+ * Create LLVM translators and worker threads. We create the instances of
+ * translators and helper threads during the initialization of LLVMEnv and
+ * each helper thread will pick its own translator instance later.
+ */
+void LLVMEnv::CreateTranslator()
+{
+ dbg() << DEBUG_LLVM << "Creating " << NumTranslator << " translator(s).\n";
+
+ for (unsigned i = 0; i < NumTranslator; ++i) {
+ CPUArchState *env = (CPUArchState *)ThreadEnv[i]->env_ptr;
+ Translator[i] = LLVMTranslator::CreateLLVMTranslator(i, env);
+ }
+
+ ThreadStop = false;
+ ThreadExit = false;
+ TraceCacheFull = false;
+
+ if (UseThreading)
+ StartThread();
+}
+
+/*
+ * DeleteTranslator()
+ * Destroy LLVMTranslator.
+ */
+void LLVMEnv::DeleteTranslator()
+{
+ dbg() << DEBUG_LLVM << "Destroying " << NumTranslator << " translator(s).\n";
+
+ /* Wait for worker threads finishing their jobs, clear all optimization
+ * requests and flush trace code cache. */
+ if (UseThreading && !ThreadExit) {
+ ThreadStop = true;
+ while (NumPendingThread != NumTranslator)
+ usleep(100);
+
+ QM->Flush();
+ MM->Flush();
+ }
+
+ for (unsigned i = 0; i < NumTranslator; ++i) {
+ delete Translator[i];
+ Translator[i] = nullptr;
+ }
+}
+
+void LLVMEnv::RestartTranslator()
+{
+ dbg() << DEBUG_LLVM << "Restarting " << NumTranslator << " translator(s).\n";
+
+ for (unsigned i = 0; i < NumTranslator; ++i) {
+ CPUArchState *env = (CPUArchState *)ThreadEnv[i]->env_ptr;
+ Translator[i] = LLVMTranslator::CreateLLVMTranslator(i, env);
+ }
+
+ TraceCacheFull = false;
+ NumPendingThread = 0;
+ ThreadStop = false;;
+}
+
+void LLVMEnv::StartThread()
+{
+ ThreadExit = false;
+ for (unsigned i = 0; i < NumTranslator; ++i) {
+ int ret = pthread_create(&HelperThread[i], nullptr, WorkerFunc,
+ (void*)(long)i);
+ if (ret != 0)
+ hqemu_error("failed to create worker thread.\n");
+ }
+
+ /* Wait until all threads are ready. */
+ while (NumPendingThread != NumTranslator)
+ usleep(200);
+ NumPendingThread = 0;
+}
+
+void LLVMEnv::StopThread()
+{
+ ThreadExit = true;
+ for (unsigned i = 0; i < NumTranslator; ++i)
+ pthread_join(HelperThread[i], nullptr);
+}
+
+LLVMTranslator *LLVMEnv::AcquireSingleTranslator()
+{
+ if (Translator.empty())
+ hqemu_error("internal error.\n");
+
+ qemu_mutex_lock(&mutex);
+ return Translator[0];
+}
+
+void LLVMEnv::ReleaseSingleTranslator()
+{
+ qemu_mutex_unlock(&mutex);
+}
+
+
+/*
+ * CreateLLVMEnv()
+ * The interface to create the LLVMEnv instance.
+ */
+void LLVMEnv::CreateLLVMEnv()
+{
+ if (InitOnce == true)
+ hqemu_error("LLVM environment already initialized.\n");
+
+ if (TraceCache == nullptr)
+ hqemu_error("llvm_alloc_cache() must be called before this function.\n");
+
+ new LLVMEnv;
+ InitOnce = true;
+}
+
+void LLVMEnv::DeleteLLVMEnv()
+{
+ if (InitOnce == false)
+ hqemu_error("LLVM environment already destroyed.\n");
+
+ /* Stop the LLVM translation threads before the program is terminated. */
+ delete LLEnv;
+ InitOnce = false;
+}
+
+TraceID LLVMEnv::insertTransCode(TranslatedCode *TC)
+{
+ TraceID tid = TransCode.size();
+ TransCode.push_back(TC);
+ SortedCode[(uintptr_t)TC->Code] = TC;
+
+ for (auto TB : TC->Trace->TBs) {
+ ChainInfo &Chain = *ChainInfo::get(TB);
+ Chain.insertDepTrace(TC->EntryTB->id);
+ }
+ return tid;
+}
+
+LLVMEnv::SlotInfo LLVMEnv::getChainSlot()
+{
+ hqemu::MutexGuard locked(llvm_global_lock);
+
+ size_t Key = ChainPoint.size();
+ uintptr_t RetVal = (Key << 2) | TB_EXIT_LLVM;
+ ChainPoint.push_back(0);
+ return SlotInfo(Key, RetVal);
+}
+
+static bool OptimizeOrSkip()
+{
+ static unsigned curr = 0;
+
+ dbg() << DEBUG_LLVM << "Received an optimization request ID=" << curr << "."
+ << (curr >= NumTranslations ? " (skip)\n" : "\n");
+
+ return curr++ >= NumTranslations;
+}
+
+int LLVMEnv::OptimizeBlock(CPUArchState *env, OptRequest Request)
+{
+ if (InitOnce == false)
+ hqemu_error("internal error.\n");
+
+ if (OptimizeOrSkip() == true)
+ return 0;
+
+ env->build_mode = BUILD_LLVM | BUILD_TCG;
+ LLVMTranslator *Translator = LLEnv->AcquireSingleTranslator();
+ Translator->GenBlock(env, Request.release());
+ LLEnv->ReleaseSingleTranslator();
+ env->build_mode = BUILD_NONE;
+ return 1;
+}
+
+int LLVMEnv::OptimizeTrace(CPUArchState *env, OptRequest Request)
+{
+ if (InitOnce == false)
+ return 0;
+
+ if (TransMode == TRANS_MODE_NONE)
+ return 0;
+ if (OptimizeOrSkip() == true)
+ return 0;
+
+ OptimizationInfo *Opt = Request.release();
+ Opt->ComposeCFG();
+
+ if (TransMode == TRANS_MODE_HYBRIDS) {
+ if (!TraceCacheFull) {
+ if (!LLEnv->getMemoryManager()->isSizeAvailable())
+ TraceCacheFull = true;
+ else {
+ LLVMTranslator *Translator = LLEnv->AcquireSingleTranslator();
+ Translator->GenTrace(env, Opt);
+ LLEnv->ReleaseSingleTranslator();
+ }
+ }
+
+ if (TraceCacheFull)
+ return 0;
+ } else if (TransMode == TRANS_MODE_HYBRIDM) {
+ /* Put the optimization request into the request queue and continue. */
+ QM->Enqueue(Opt);
+ }
+
+ return 1;
+}
+
+#if defined(CONFIG_USER_ONLY)
+QueueManager::QueueManager()
+{
+ CurrentQueue = new Queue;
+}
+
+QueueManager::~QueueManager()
+{
+ delete CurrentQueue;
+}
+
+void QueueManager::Enqueue(OptimizationInfo *Opt)
+{
+ CurrentQueue->enqueue(Opt);
+}
+
+void *QueueManager::Dequeue()
+{
+ return CurrentQueue->dequeue();
+}
+
+void QueueManager::Flush()
+{
+ while (1) {
+ OptimizationInfo *Opt = (OptimizationInfo *)CurrentQueue->dequeue();
+ if (Opt == nullptr)
+ break;
+ delete Opt;
+ }
+}
+
+#else
+QueueManager::QueueManager()
+{
+ ActiveQueue.resize(ACTIVE_QUEUE_SIZE);
+ for (unsigned i = 0, e = ActiveQueue.size(); i != e; ++i)
+ ActiveQueue[i] = nullptr;
+}
+
+QueueManager::~QueueManager()
+{
+ for (unsigned i = 0, e = ActiveQueue.size(); i != e; ++i) {
+ if (ActiveQueue[i])
+ delete ActiveQueue[i];
+ }
+}
+
+void QueueManager::Enqueue(OptimizationInfo *Opt)
+{
+ Queue *CurrentQueue = ActiveQueue[pcid & ACTIVE_QUEUE_MASK];
+ if (unlikely(!CurrentQueue))
+ CurrentQueue = ActiveQueue[pcid & ACTIVE_QUEUE_MASK] = new Queue;
+ CurrentQueue->enqueue(Opt);
+}
+
+void *QueueManager::Dequeue()
+{
+ Queue *CurrentQueue = ActiveQueue[pcid & ACTIVE_QUEUE_MASK];
+ if (unlikely(!CurrentQueue))
+ return nullptr;
+ return CurrentQueue->dequeue();
+}
+
+void QueueManager::Flush()
+{
+ for (unsigned i = 0, e = ActiveQueue.size(); i != e; ++i) {
+ if (!ActiveQueue[i])
+ continue;
+
+ while (1) {
+ OptimizationInfo *Opt = (OptimizationInfo *)ActiveQueue[i]->dequeue();
+ if (!Opt)
+ break;
+ delete Opt;
+ }
+ }
+}
+#endif
+
+
+/*
+ * OptimizationInfo
+ */
+
+OptimizationInfo::OptimizationInfo(TranslationBlock *HeadTB, TraceEdge &Edges)
+ : isUserTrace(true), isBlock(false), CFG(nullptr)
+{
+ for (auto &E : Edges)
+ Trace.push_back(E.first);
+
+#if defined(CONFIG_USER_ONLY)
+ if (!llvm_has_annotation(HeadTB->pc, ANNOTATION_LOOP))
+ ExpandTrace(HeadTB, Edges);
+#endif
+
+ /* Build CFG from the edges. */
+ std::map<TranslationBlock *, GraphNode *> NodeMap;
+
+ NodeMap[HeadTB] = new GraphNode(HeadTB);
+ for (auto &E : Edges) {
+ TranslationBlock *Parent = E.first;
+ if (NodeMap.find(Parent) == NodeMap.end())
+ NodeMap[Parent] = new GraphNode(Parent);
+
+ GraphNode *ParentNode = NodeMap[Parent];
+ for (auto Child : E.second) {
+ if (NodeMap.find(Child) == NodeMap.end())
+ NodeMap[Child] = new GraphNode(Child);
+
+ ParentNode->insertChild(NodeMap[Child]);
+ }
+ }
+
+ CFG = NodeMap[HeadTB];
+}
+
+void OptimizationInfo::SearchCycle(TraceNode &SearchNodes, TraceNode &Nodes,
+ TraceEdge &Edges, TBVec &Visited, int Depth)
+{
+ TranslationBlock *Curr = Visited.back();
+
+ if (llvm_has_annotation(Curr->pc, ANNOTATION_LOOP))
+ return;
+ if (Nodes.size() >= PredictThreshold)
+ return;
+
+ /* If the current node is one of the main NET trace node, we found a cyclic path.
+ * The links of such cyclic path are added to the trace edges. */
+ if (SearchNodes.find(Curr) != SearchNodes.end()) {
+ for (unsigned i = 1, e = Visited.size(); i != e; ++i) {
+ TranslationBlock *Pred = Visited[i - 1];
+ TranslationBlock *Succ = Visited[i];
+ Nodes.insert(Succ);
+ Edges[Pred].insert(Succ);
+ }
+ return;
+ }
+ /* Stop if we reach the maximum search depth. */
+ if (Depth == MAX_SEARCH_DEPTH)
+ return;
+
+ /* Still cannot find a cyclic path? Keep looking for the successors. */
+ for (auto Succ : GlobalCFG.getSuccessor(Curr)) {
+ Visited.push_back(Succ);
+ SearchCycle(SearchNodes, Nodes, Edges, Visited, Depth + 1);
+ Visited.pop_back();
+ }
+}
+
+/*
+ * ExpandTrace()
+ * Expand a NET trace to a bigger region with the NETPlus algorithm.
+ * NETPlus: trace formation algorithm based on the paper published in
+ * RESoLVE'11. D. Davis and K. Hazelwood, "Improving Region Selection Through
+ * Loop Completion," in ASPLOS Workshop on Runtime Environments/Systems,
+ * Layering, and Virtualized Environments, 2011.
+ */
+void OptimizationInfo::ExpandTrace(TranslationBlock *HeadTB, TraceEdge &Edges)
+{
+ if (DisableNETPlus)
+ return;
+
+ TraceNode Nodes;
+ TraceNode MainTraceNodes;
+ std::map<target_ulong, TranslationBlock*> NodeMap;
+#ifdef USE_TRACETREE_ONLY
+ MainTraceNodes.insert(HeadTB);
+ NodeMap[HeadTB->pc] = HeadTB;
+#else
+ for (auto &E : Edges) {
+ TranslationBlock *TB = E.first;
+ MainTraceNodes.insert(TB);
+ NodeMap[TB->pc] = TB;
+ }
+#endif
+
+ for (auto &E : Edges)
+ Nodes.insert(E.first);
+
+ /* Put critical section when traversing GlobalCFG. */
+ hqemu::MutexGuard locked(GlobalCFG.getLock());
+
+ for (auto TB : Trace) {
+ TBVec Visited;
+ Visited.push_back(TB);
+ if (NodeMap.find(TB->jmp_pc[0]) != NodeMap.end())
+ Edges[TB].insert(NodeMap[TB->jmp_pc[0]]);
+ if (TB->jmp_pc[1] != (target_ulong)-1 &&
+ NodeMap.find(TB->jmp_pc[1]) != NodeMap.end())
+ Edges[TB].insert(NodeMap[TB->jmp_pc[1]]);
+
+ for (auto Succ : GlobalCFG.getSuccessor(TB)) {
+ Visited.push_back(Succ);
+ SearchCycle(MainTraceNodes, Nodes, Edges, Visited, 0);
+ Visited.pop_back();
+ }
+ }
+}
+
+/*
+ * ComposeCFG()
+ * Compose a trace of CFG from a list of TBs.
+ */
+void OptimizationInfo::ComposeCFG()
+{
+ bool isUser = true;
+ TranslationBlock *HeadTB = Trace[0];
+
+#if defined(CONFIG_SOFTMMU)
+ isUser = isUserTB(HeadTB) ? true : false;
+ for (auto TB : Trace) {
+ if (unlikely(TB->mode == BLOCK_INVALID)) {
+ /* A NET trace may contain invalidated block because the block
+ * is invalidated during trace formation. */
+ dbg() << DEBUG_LLVM << __func__ << ": skip due to invalidated block\n";
+ return;
+ }
+
+ if (isUser && isUserTB(TB) == false) {
+ dbg() << DEBUG_LLVM << __func__ << ": skip due to mixed mode\n";
+ return;
+ }
+
+ /* Our translator assumes that component blocks have the same cs_base. */
+ if (TB->cs_base != HeadTB->cs_base) {
+ dbg() << DEBUG_LLVM << __func__ << ": skip due to inconsistent cs\n";
+ return;
+ }
+ }
+#endif
+
+ /* Check if the consecutive blocks are really connected. */
+ TraceEdge Edges;
+
+ TranslationBlock *Curr = Trace[0];
+ for (unsigned i = 1, e = Trace.size(); i != e; ++i) {
+ TranslationBlock *Pred = Trace[i - 1];
+ Curr = Trace[i];
+ if (Pred->jmp_pc[0] != (target_ulong)-1 &&
+ Pred->jmp_pc[0] != Curr->pc &&
+ Pred->jmp_pc[1] != Curr->pc) {
+ /* Disconnected. Discard the tailing blocks. */
+ Trace.resize(i);
+ LoopHeadIdx = -1;
+ break;
+ }
+
+ /* Connected. */
+ Edges[Pred].insert(Curr);
+ }
+ if (LoopHeadIdx != -1)
+ Edges[Curr].insert(Trace[LoopHeadIdx]);
+
+#if defined(CONFIG_USER_ONLY)
+ if (!llvm_has_annotation(Trace[0]->pc, ANNOTATION_LOOP))
+ ExpandTrace(HeadTB, Edges);
+#endif
+
+ /* Build CFG from the edges. */
+ std::map<TranslationBlock *, GraphNode *> NodeMap;
+
+ NodeMap[HeadTB] = new GraphNode(HeadTB);
+ for (auto &E : Edges) {
+ TranslationBlock *Parent = E.first;
+ if (NodeMap.find(Parent) == NodeMap.end())
+ NodeMap[Parent] = new GraphNode(Parent);
+
+ GraphNode *ParentNode = NodeMap[Parent];
+ for (auto Child : E.second) {
+ if (NodeMap.find(Child) == NodeMap.end())
+ NodeMap[Child] = new GraphNode(Child);
+
+ ParentNode->insertChild(NodeMap[Child]);
+ }
+ }
+
+ CFG = NodeMap[HeadTB];
+ isUserTrace = isUser;
+}
+
+
+/* The following implements routines of the C interfaces for QEMU. */
+extern "C" {
+
+void hqemu_help(void)
+{
+ /* Hide LLVM builtin options. */
+#if defined(LLVM_V35)
+ StringMap<cl::Option*> opts;
+ cl::getRegisteredOptions(opts);
+#else
+ StringMap<cl::Option*> &opts = cl::getRegisteredOptions();
+#endif
+ for (auto &I : opts) {
+ auto opt = I.second;
+ if (opt->Category == &cl::GeneralCategory)
+ opt->setHiddenFlag(cl::Hidden);
+ }
+
+ SmallVector<const char *, 16> Args;
+ Args.push_back("\n export LLVM_CMD='[OPTION1] [OPTION2]'\n qemu-" TARGET_NAME);
+ Args.push_back(nullptr);
+ cl::ParseCommandLineOptions(Args.size() - 1,
+ const_cast<char **>(&Args[0]));
+ cl::PrintHelpMessage(false, false);
+}
+
+int llvm_init()
+{
+ LLVMEnv::CreateLLVMEnv();
+ return 0;
+}
+
+int llvm_finalize()
+{
+ LLVMEnv::DeleteLLVMEnv();
+#if 0
+ llvm_shutdown();
+#endif
+ return 0;
+}
+
+int llvm_alloc_cache()
+{
+ size_t BlockCacheSize = (tcg_ctx.code_gen_buffer_size / 2)
+ & qemu_real_host_page_mask;
+ LLVMEnv::TraceCacheSize = tcg_ctx.code_gen_buffer_size - BlockCacheSize;
+ LLVMEnv::TraceCache = (uint8_t *)tcg_ctx.code_gen_buffer + BlockCacheSize;
+
+ tcg_ctx.code_gen_buffer_size = BlockCacheSize;
+ return 0;
+}
+
+int llvm_check_cache(void)
+{
+ if (LLVMEnv::InitOnce == false)
+ return 1;
+ return TraceCacheFull ? 1 : 0;
+}
+
+/*
+ * llvm_tb_flush()
+ * Wrapper fucntion to flush the optmizated code cache.
+ */
+int llvm_tb_flush(void)
+{
+ if (LLVMEnv::InitOnce == false)
+ return 1;
+ if (LLVMEnv::TransMode == TRANS_MODE_NONE)
+ return 1;
+
+ dbg() << DEBUG_LLVM << __func__ << " entered.\n";
+
+ LLEnv->DeleteTranslator();
+
+ for (int i = 0, e = tcg_ctx_global.tb_ctx->nb_tbs; i != e; ++i) {
+ if (tbs[i].image) delete_image(&tbs[i]);
+ if (tbs[i].state) delete_state(&tbs[i]);
+ if (tbs[i].chain) ChainInfo::free(&tbs[i]);
+
+ tbs[i].image = tbs[i].state = tbs[i].chain = nullptr;
+ }
+
+ /* Remove all translated code. */
+ LLVMEnv::TransCodeList &TransCode = LLEnv->getTransCode();
+ for (unsigned i = 0, e = TransCode.size(); i != e; ++i)
+ delete TransCode[i];
+
+ TransCode.clear();
+ LLEnv->getSortedCode().clear();
+ LLEnv->getChainPoint().clear();
+
+ /* Clear global cfg. */
+ GlobalCFG.reset();
+
+ LLEnv->RestartTranslator();
+ LLEnv->incNumFlush();
+
+ dbg() << DEBUG_LLVM << __func__ << ": trace cache flushed.\n";
+
+ return 0;
+}
+
+static void llvm_suppress_chaining(TranslationBlock *tb)
+{
+ /* TODO: add unlinking rule for non-x86 hosts. */
+ std::vector<uintptr_t> &Chains = ChainInfo::get(tb)->Chains;
+ if (Chains.empty())
+ return;
+
+ for (unsigned i = 0, e = Chains.size(); i != e; ++i) {
+#if defined(TCG_TARGET_I386)
+ patch_jmp(Chains[i], Chains[i] + 5);
+#elif defined(TCG_TARGET_ARM) || defined(TCG_TARGET_AARCH64)
+ patch_jmp(Chains[i], Chains[i] + 4);
+#elif defined(TCG_TARGET_PPC64)
+ patch_jmp(Chains[i], Chains[i] + 16);
+#endif
+ }
+ Chains.clear();
+}
+
+/*
+ * llvm_tb_remove()
+ * Remove the traces containing the `tb' that is invalidated by QEMU.
+ */
+int llvm_tb_remove(TranslationBlock *tb)
+{
+ if (LLVMEnv::TransMode == TRANS_MODE_NONE)
+ return 1;
+ if (!tb->chain)
+ return 1;
+
+ /* Unlink traces that jump to this tb. */
+ llvm_suppress_chaining(tb);
+
+ if (LLVMEnv::TransMode == TRANS_MODE_BLOCK) {
+ patch_jmp(tb_get_jmp_entry(tb), tb_get_jmp_next(tb));
+ ChainInfo::free(tb);
+ return 1;
+ }
+
+ LLVMEnv::TransCodeList &TransCode = LLEnv->getTransCode();
+ LLVMEnv::TransCodeMap &SortedCode = LLEnv->getSortedCode();
+ std::vector<BlockID> &DepTraces = ChainInfo::get(tb)->DepTraces;
+
+ hqemu::MutexGuard locked(llvm_global_lock);
+
+ /* Remove traces that contain this tb. */
+ if (DepTraces.empty())
+ return 0;
+
+ for (unsigned i = 0, e = DepTraces.size(); i != e; ++i) {
+ TranslationBlock *EntryTB = &tbs[DepTraces[i]];
+ if (EntryTB->tid == -1) {
+ /* This can happen when a trace block (not head) was removed
+ * before and at that time the tid of the trace head block is
+ * set to -1. Now, the trace head block is going to be removed
+ * and we just skip it. */
+ continue;
+ }
+
+ TranslatedCode *TC = TransCode[EntryTB->tid];
+ if (!TC->Active)
+ hqemu_error("fatal error.\n");
+
+ TC->Active = false;
+ SortedCode.erase((uintptr_t)TC->Code);
+ patch_jmp(tb_get_jmp_entry(EntryTB), tb_get_jmp_next(EntryTB));
+
+ /* For system-mode emulation, since the source traces do not directly
+ * jump to the trace code, we do not need to suppress the traces
+ * chaining to the trace head block. Unlinking the jump from the
+ * trace head block to the trace code is sufficient to make execution
+ * from going to the trace code. */
+#if defined(CONFIG_USER_ONLY)
+ llvm_suppress_chaining(EntryTB);
+#endif
+
+ EntryTB->mode = BLOCK_ACTIVE;
+ EntryTB->exec_count = 0;
+ EntryTB->opt_ptr = EntryTB->tc_ptr;
+ EntryTB->tid = -1;
+ }
+
+ DepTraces.clear();
+ ChainInfo::free(tb);
+
+ return 1;
+}
+
+/*
+ * llvm_resolve_address()
+ * Given the value returned when leaving the code cache, return the patch
+ * address for the region chaining.
+ */
+static uintptr_t llvm_resolve_address(uintptr_t addr)
+{
+ if (LLVMEnv::InitOnce == false)
+ return 0;
+
+ hqemu::MutexGuard locked(llvm_global_lock);
+
+ LLVMEnv::ChainSlot &ChainPoint = LLEnv->getChainPoint();
+ size_t Key = addr >> 2;
+ return ChainPoint[Key];
+}
+
+#if defined(CONFIG_USER_ONLY)
+#define cross_page(__tb) (0)
+#define trace_add_jump(src, dst) patch_jmp(next_tb, tb->opt_ptr)
+#else
+#define cross_page(__tb) (__tb->page_addr[1] != (unsigned long)-1)
+#define trace_add_jump(src, dst) patch_jmp(next_tb, tb->tc_ptr)
+#endif
+
+void llvm_handle_chaining(uintptr_t next_tb, TranslationBlock *tb)
+{
+ if ((next_tb & TB_EXIT_MASK) == TB_EXIT_LLVM) {
+ next_tb = llvm_resolve_address(next_tb);
+ if (next_tb && !cross_page(tb)) {
+ /* Keep track of traces (i.e., next_tb) that jump to this tb. */
+ ChainInfo &Chain = *ChainInfo::get(tb);
+ Chain.insertChain(next_tb);
+
+ /* For system-mode emulation, we only let the source traces
+ * jump to the trace head 'block' in the block code cache. */
+ trace_add_jump(next_tb, tb);
+ }
+ } else if (next_tb != 0 && !cross_page(tb)) {
+ TranslationBlock *pred = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
+ int n = next_tb & TB_EXIT_MASK;
+ tb_add_jump(pred, n, tb);
+
+ GlobalCFG.insertLink(pred, tb);
+ }
+}
+
+int llvm_locate_trace(uintptr_t searched_pc)
+{
+ uintptr_t Start = (uintptr_t)LLVMEnv::TraceCache;
+ uintptr_t End = Start + LLVMEnv::TraceCacheSize;
+ return (searched_pc >= Start && searched_pc < End);
+}
+
+TranslationBlock *llvm_find_pc(CPUState *cpu, uintptr_t searched_pc)
+{
+ LLVMEnv::TransCodeMap &SortedCode = LLEnv->getSortedCode();
+ CPUArchState *env = (CPUArchState *)cpu->env_ptr;
+
+ if (LLVMEnv::InitOnce == false)
+ return nullptr;
+ if (!llvm_locate_trace(searched_pc))
+ return nullptr;
+
+ hqemu::MutexGuard locked(llvm_global_lock);
+
+ LLVMEnv::TransCodeMap::iterator I = SortedCode.upper_bound(searched_pc);
+ TranslatedCode *TC = (--I)->second;
+
+ if (env->restore_val >= TC->Restore.size()) {
+ auto HostDisAsm = LLEnv->getTranslator(0)->getHostDisAsm();
+ if (HostDisAsm)
+ HostDisAsm->PrintOutAsm((uint64_t)TC->Code, TC->Size);
+ hqemu_error("got exception at 0x%zx\n", searched_pc);
+ }
+
+ /* Since restore_val is no longer used, we set it to the
+ * the opc index so the later restore can quickly get it. */
+ std::pair<BlockID, uint16_t> RestoreInfo = TC->Restore[env->restore_val];
+ env->restore_val = RestoreInfo.second - 1;
+ return &tbs[RestoreInfo.first];
+}
+
+/*
+ * llvm_restore_state()
+ * The cpu state corresponding to 'searched_pc' is restored.
+ */
+int llvm_restore_state(CPUState *cpu, TranslationBlock *tb,
+ uintptr_t searched_pc)
+{
+ target_ulong data[TARGET_INSN_START_WORDS] = { tb->pc };
+ CPUArchState *env = (CPUArchState *)cpu->env_ptr;
+ uintptr_t host_pc = (uintptr_t)tb->tc_ptr;
+ uint8_t *p = tb->tc_search;
+
+ /* Reconstruct the stored insn data while looking for the point at
+ which the end of the insn exceeds the searched_pc. */
+ for (unsigned i = 0, e = tb->icount; i != e; ++i) {
+ for (unsigned j = 0; j < TARGET_INSN_START_WORDS; ++j) {
+ data[j] += decode_sleb128(&p);
+ }
+ host_pc += decode_sleb128(&p);
+ if (env->restore_val == i)
+ goto found;
+ }
+ return -1;
+
+found:
+ restore_state_to_opc(env, tb, data);
+
+ return 0;
+}
+
+/*
+ * llvm_fork_start()
+ * Wrapper function to stop the optimization service before performing fork.
+ */
+void llvm_fork_start(void)
+{
+ if (!LLEnv->isThreading())
+ return;
+
+ dbg() << DEBUG_LLVM << __func__ << " entered.\n";
+
+ LLEnv->StopThread();
+}
+
+/*
+ * llvm_fork_end()
+ * Wrapper function to restart the optimization service after performing fork.
+ */
+void llvm_fork_end(int child)
+{
+ if (!LLEnv->isThreading())
+ return;
+
+ dbg() << DEBUG_LLVM << __func__ << " entered.\n";
+
+ /* Now, restart the LLVM thread. */
+ if (child == 0) {
+ LLEnv->StartThread();
+ } else {
+ ThreadExit = true;
+ LLVMEnv::setTransMode(TRANS_MODE_NONE);
+
+ qemu_mutex_init(&LLEnv->mutex);
+ }
+}
+
+int llvm_has_annotation(target_ulong addr, int annotation)
+{
+ if (annotation == ANNOTATION_LOOP)
+ return AF->hasLoopAnnotation(addr) == true;
+ return 0;
+}
+
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/optimization.cpp b/src/llvm/optimization.cpp
new file mode 100644
index 0000000..15597bf
--- /dev/null
+++ b/src/llvm/optimization.cpp
@@ -0,0 +1,317 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * This file implements the basic optimization schemes including
+ * (1) instruction TLB (iTLB),
+ * (2) indirect branch target cache (IBTC),
+ * (3) cross-page block linking (CPBL), and
+ * (4) large page table (LPT).
+ */
+
+#include "tracer.h"
+#include "optimization.h"
+
+
+#if defined(ENALBE_CPU_PROFILE)
+# define PROFILE(X) do { X; } while (0)
+#else
+# define PROFILE(X) do { } while (0)
+#endif
+
+/* The following implements routines of the C interfaces for QEMU. */
+extern "C" {
+
+TranslationBlock *tbs;
+unsigned long alignment_count[2]; /* 0: misaligned, 1: aligned. */
+unsigned long aligned_boundary = 16;
+
+extern uint8_t *ibtc_ret_addr;
+
+/*
+ * iTLB (Instruction TLB)
+ */
+void itlb_update_entry(CPUArchState *env, TranslationBlock *tb)
+{
+ ITLB &itlb = cpu_get_itlb(env);
+ itlb.insert(tb->pc, tb->page_addr[0] & TARGET_PAGE_MASK);
+ if (tb->page_addr[1] != (tb_page_addr_t)-1)
+ itlb.insert(tb->pc + tb->size, tb->page_addr[1] & TARGET_PAGE_MASK);
+}
+
+int itlb_lookup(CPUArchState *env, target_ulong pc, uint64_t paddr)
+{
+ ITLB &itlb = cpu_get_itlb(env);
+ return itlb.get(pc) == (paddr & TARGET_PAGE_MASK);
+}
+
+/*
+ * IBTC (Indirect Branch Translation Cache)
+ */
+#if defined(ENABLE_IBTC)
+
+/* Update IBTC hash table.
+ * Note: we do not cache TBs that cross page boundary. */
+void ibtc_update_entry(CPUArchState *env, TranslationBlock *tb)
+{
+ IBTC &ibtc = cpu_get_ibtc(env);
+ if (!ibtc.needUpdate())
+ return;
+
+ ibtc.resetUpdate();
+
+#if defined(CONFIG_SOFTMMU)
+ if (tb->page_addr[1] != (tb_page_addr_t)-1)
+ return;
+#endif
+
+ ibtc.insert(tb->pc, tb);
+}
+
+/* Helper function to lookup the IBTC hash table. */
+void *helper_lookup_ibtc(CPUArchState *env)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ if (unlikely(cpu->tcg_exit_req != 0)) {
+ cpu->tcg_exit_req = 0;
+ return ibtc_ret_addr;
+ }
+
+ /* A match of 'pc', 'cs_base' and 'flags' results in a IBTC hit. Since
+ * cs_base is only meaningful with x86 guest and system mode (cs_base is
+ * always 0 for user-mode emulation and non-x86 guest), we only compare
+ * cs_base with system mode emulation of x86 guest. */
+
+ target_ulong pc = cpu_get_pc(env);
+ IBTC &ibtc = cpu_get_ibtc(env);
+ TranslationBlock *next_tb = ibtc.get(pc);
+
+ PROFILE( ibtc.incTotal() );
+
+ if (likely(next_tb)) {
+#if defined(CONFIG_SOFTMMU)
+ if (likely(itlb_lookup(env, pc, next_tb->page_addr[0])))
+#endif
+ if (likely(cpu_check_state(env, next_tb->cs_base, next_tb->flags))) {
+ cpu->current_tb = next_tb;
+ return next_tb->opt_ptr;
+ }
+ }
+
+ PROFILE( ibtc.incMiss() );
+
+ ibtc.setUpdate();
+ return ibtc_ret_addr;
+}
+#else
+void ibtc_update_entry(CPUArchState *env, TranslationBlock *tb) {}
+void *helper_lookup_ibtc(CPUArchState *env) { return ibtc_ret_addr; }
+#endif /* ENABLE_IBTC */
+
+
+/*
+ * CPBL (Cross-Page Block Linking)
+ */
+#if defined(ENABLE_CPBL)
+void *helper_lookup_cpbl(CPUArchState *env)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ if (unlikely(cpu->tcg_exit_req != 0)) {
+ cpu->tcg_exit_req = 0;
+ return ibtc_ret_addr;
+ }
+
+ /* A match of 'pc', 'cs_base' and 'flags' results in a CPBL hit. Since
+ * cs_base is only meaningful with x86 guest and system mode (cs_base is
+ * always 0 for user-mode emulation and non-x86 guest), we only compare
+ * cs_base with system mode emulation of x86 guest. */
+
+ target_ulong pc = cpu_get_pc(env);
+ TranslationBlock *next_tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
+
+ PROFILE( cpu_get_cpbl(env).incTotal() );
+
+ if (likely(next_tb && next_tb->pc == pc))
+ if (likely(cpu_check_state(env, next_tb->cs_base, next_tb->flags))) {
+ cpu->current_tb = next_tb;
+ return next_tb->opt_ptr;
+ }
+
+ PROFILE( cpu_get_cpbl(env).incMiss() );
+
+ return ibtc_ret_addr;
+}
+
+int helper_validate_cpbl(CPUArchState *env, target_ulong pc, int id)
+{
+ TranslationBlock *tb = &tbs[id];
+
+ PROFILE( cpu_get_cpbl(env).incValidateTotal() );
+ if (tb->page_addr[1] == (tb_page_addr_t)-1 &&
+ likely(itlb_lookup(env, pc, tb->page_addr[0])))
+ return 1;
+ if (likely(itlb_lookup(env, pc + TARGET_PAGE_SIZE, tb->page_addr[1])))
+ return 1;
+ PROFILE( cpu_get_cpbl(env).incValidateMiss() );
+ return 0;
+}
+
+#else
+void *helper_lookup_cpbl(CPUArchState *env) { return ibtc_ret_addr; }
+int helper_validate_cpbl(CPUArchState *env, target_ulong pc, int id) { return 0; }
+#endif /* ENABLE_CPBL */
+
+
+#if defined(ENABLE_LPAGE)
+int lpt_reset(CPUArchState *env)
+{
+ if (env->opt_link == nullptr)
+ return 0;
+ LargePageTable &lpt = cpu_get_lpt(env);
+ lpt.reset();
+ return 1;
+}
+/* Add a large page to LPT. */
+int lpt_add_page(CPUArchState *env, target_ulong addr, target_ulong size)
+{
+ LargePageTable &lpt = cpu_get_lpt(env);
+ lpt.insert(addr, size);
+ return 1;
+}
+
+/* Given an address, return 1 if this address overlaps with any tracked
+ * large page and return 0 otherwise. The large page record is NOT removed
+ * if it is found. */
+int lpt_search_page(CPUArchState *env, target_ulong addr, target_ulong *addrp,
+ target_ulong *sizep)
+{
+ LargePageTable &lpt = cpu_get_lpt(env);
+ return lpt.search(addr, LargePageTable::SEARCH, addrp, sizep);
+}
+
+/* Given an address, return the pte index if this address overlaps with
+ * any tracked large page and return -1 otherwise. If a large page is found,
+ * remove it from the list. */
+int lpt_flush_page(CPUArchState *env, target_ulong addr, target_ulong *addrp,
+ target_ulong *sizep)
+{
+ LargePageTable &lpt = cpu_get_lpt(env);
+ PROFILE( lpt.incTotal() );
+ if (lpt.search(addr, LargePageTable::FLUSH, addrp, sizep))
+ return 1;
+ PROFILE( lpt.incMiss() );
+ return 0;
+}
+#else
+int lpt_reset(CPUArchState *env) { return 0; }
+int lpt_add_page(CPUArchState *env, target_ulong addr, target_ulong size) { return 0; }
+int lpt_search_page(CPUArchState *env, target_ulong addr,
+ target_ulong *addrp, target_ulong *sizep) { return 0; }
+int lpt_flush_page(CPUArchState *env, target_ulong addr,
+ target_ulong *addrp, target_ulong *sizep) { return 0; }
+#endif
+
+/* Initialize the optimization schemes. */
+int optimization_init(CPUArchState *env)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ if (cpu->cpu_index == 0) {
+ tbs = tcg_ctx.tb_ctx->tbs;
+ if (!tbs) {
+ std::cerr << __func__ << ": fatal error.\n";
+ exit(0);
+ }
+ if (get_cpu_size() != sizeof(CPUArchState)) {
+ std::cerr << "Inconsistent CPUArchState size in C and C++.\n"
+ "This may be because sizeof empty struct in C is "
+ "different with C++. Please fix this.\n";
+ exit(0);
+ }
+ }
+
+ /* Create a processor tracer for each env. */
+ BaseTracer *Tracer = BaseTracer::CreateTracer(env);
+
+ /* Create optimization facilities. */
+ CPUOptimization *Opt = new CPUOptimization(cpu, Tracer);
+
+ /* Make an uplink to the optimizaiton facility object. */
+ env->opt_link = Opt;
+ return 1;
+}
+
+/* Finalize the optimization schemes. */
+int optimization_finalize(CPUArchState *env)
+{
+ if (env->opt_link == nullptr)
+ return 0;
+
+ PROFILE( cpu_get_ibtc(env).dump() );
+#if defined(CONFIG_SOFTMMU)
+ PROFILE( cpu_get_cpbl(env).dump() );
+ PROFILE( cpu_get_lpt(env).dump() );
+#endif
+
+ BaseTracer::DeleteTracer(env);
+ delete (CPUOptimization *)env->opt_link;
+ return 1;
+}
+
+/* Reset to default values of the optimizatiion schemes. */
+int optimization_reset(CPUArchState *env, int force_flush)
+{
+ if (env->opt_link == nullptr)
+ return 0;
+
+ ITLB &itlb = cpu_get_itlb(env);
+ IBTC &ibtc = cpu_get_ibtc(env);
+
+ itlb.reset();
+ if (force_flush)
+ ibtc.reset();
+
+ tracer_reset(env);
+ return 1;
+}
+
+int optimization_remove_entry(CPUArchState *env, TranslationBlock *tb)
+{
+ IBTC &ibtc = cpu_get_ibtc(env);
+ ibtc.remove(tb);
+ return 1;
+}
+
+int optimization_flush_page(CPUArchState *env, target_ulong pc)
+{
+#if defined(CONFIG_SOFTMMU)
+ ITLB &itlb = cpu_get_itlb(env);
+ itlb.flush(pc);
+#else
+ IBTC &ibtc = cpu_get_ibtc(env);
+ ibtc.reset();
+#endif
+ return 1;
+}
+
+int optimization_init_tb(TranslationBlock *tb, int id)
+{
+ tb->id = id;
+ tb->tid = -1;
+ tb->mode = BLOCK_NONE;
+ tb->opt_ptr = nullptr;
+ tb->exec_count = 0;
+ tb->patch_jmp = 0;
+ tb->patch_next = 0;
+ tb->jmp_pc[0] = tb->jmp_pc[1] = (target_ulong)-1;
+ tb->image = nullptr;
+ tb->state = nullptr;
+ tb->chain = nullptr;
+ return 1;
+}
+
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/pass/CombineCasts.cpp b/src/llvm/pass/CombineCasts.cpp
new file mode 100644
index 0000000..71a74ff
--- /dev/null
+++ b/src/llvm/pass/CombineCasts.cpp
@@ -0,0 +1,321 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/Transforms/Utils/Local.h"
+#include "llvm-target.h"
+#include "llvm-opc.h"
+#include "llvm-pass.h"
+#include "utils.h"
+
+#define PASS_NAME "CombineCasts"
+
+/*
+ * CombineCasts Pass
+ */
+class CombineCasts : public FunctionPass {
+ IRFactory *IF;
+ const DataLayout *DL;
+ MDFactory *MF;
+ IntegerType *Int8Ty;
+ IntegerType *Int32Ty;
+ IntegerType *Int64Ty;
+ IntegerType *IntPtrTy;
+ PointerType *Int8PtrTy;
+ PointerType *Int32PtrTy;
+ PointerType *Int64PtrTy;
+ Type *FloatTy;
+ Type *DoubleTy;
+ IVec toErase;
+
+public:
+ static char ID;
+ explicit CombineCasts() : FunctionPass(ID) {}
+ explicit CombineCasts(IRFactory *IF)
+ : FunctionPass(ID), IF(IF), DL(IF->getDL()), MF(IF->getMDFactory())
+ {
+ LLVMContext &Context = IF->getContext();;
+ Int8Ty = IntegerType::get(Context, 8);
+ Int32Ty = IntegerType::get(Context, 32);
+ Int64Ty = IntegerType::get(Context, 64);
+ IntPtrTy = DL->getIntPtrType(Context);
+ Int8PtrTy = Type::getInt8PtrTy(Context, 0);
+ Int32PtrTy = Type::getInt32PtrTy(Context, 0);
+ Int64PtrTy = Type::getInt64PtrTy(Context, 0);
+ FloatTy = Type::getFloatTy(Context);
+ DoubleTy = Type::getDoubleTy(Context);
+ }
+
+ Instruction *getUniqueUser(Instruction *I) {
+ if (I->hasOneUse())
+ return I->user_back();
+ return nullptr;
+ };
+
+ bool combineLoadCast(LoadInst *LI);
+ bool combineStoreCast(StoreInst *SI);
+ bool combineCastCast(Function &F);
+ bool simplifySignChange(Function &F);
+ bool runOnFunction(Function &F);
+};
+
+char CombineCasts::ID = 0;
+INITIALIZE_PASS(CombineCasts, "combinecast",
+ "Combine bitcast with guest memory loads/stores", false, false)
+
+FunctionPass *llvm::createCombineCasts(IRFactory *IF)
+{
+ return new CombineCasts(IF);
+}
+
+static bool hasSameCastingTy(ArrayRef<BitCastInst *> IL) {
+ Type *SrcTy = IL[0]->getSrcTy();
+ Type *DstTy = IL[0]->getDestTy();
+ for (BitCastInst *I : IL) {
+ if (I->getSrcTy() != SrcTy)
+ return false;
+ if (I->getDestTy() != DstTy)
+ return false;
+ }
+ return true;
+}
+
+/* This function aims to change the load type if (1) the type of loaded data is
+ * casted to another type, (2) only one user of the load instruction is bitcast,
+ * and (3) all other users of the load instruction are stores.
+ *
+ * For example:
+ * %0 = load <typeA>* %0 = load <typeB>*
+ * %1 = bitcast %0, <typeB> %1 = bitcast %0, <typeA>
+ *
+ * %2 = op <typeB> %1, ... => %2 = op <typeB> %0, ...
+ *
+ * store %0, <typeA>* store %1, <typeA>*
+ * store %1, <typeB>* store %0, <typeB>*
+ */
+bool CombineCasts::combineLoadCast(LoadInst *LI)
+{
+ Instruction *Ptr = dyn_cast<Instruction>(LI->getPointerOperand());
+
+ if (!Ptr)
+ return false;
+
+ /* Find all bitcast users of this load. */
+ SmallVector<BitCastInst *, 4> BCIs;
+ for (User *U : LI->users()) {
+ Instruction *UI = cast<Instruction>(U);
+ switch (UI->getOpcode()) {
+ default:
+ return false;
+ case Instruction::PHI:
+ case Instruction::Load:
+ case Instruction::Store:
+ break;
+ case Instruction::BitCast:
+ BCIs.push_back(cast<BitCastInst>(UI));
+ break;
+ }
+ }
+
+ if (BCIs.empty() || !hasSameCastingTy(BCIs))
+ return false;
+
+ Instruction *InsertPos = LI;
+ unsigned Alignment = LI->getAlignment();
+ unsigned Volatile = LI->isVolatile();
+ Type *SrcTy = LI->getType();
+ Type *DstTy = BCIs[0]->getDestTy();
+
+ Type *PtrTy = PointerType::get(DstTy, LI->getPointerAddressSpace());
+ if (isa<IntToPtrInst>(Ptr))
+ Ptr = new IntToPtrInst(Ptr->getOperand(0), PtrTy, "", InsertPos);
+ else
+ Ptr = new BitCastInst(Ptr, PtrTy, "", InsertPos);
+
+ Instruction *NewLI = new LoadInst(Ptr, "", Volatile, Alignment, InsertPos);
+ Instruction *NewBCI = new BitCastInst(NewLI, SrcTy, "", InsertPos);
+
+ if (MF->isGuestMemory(LI))
+ MF->setGuestMemory(NewLI);
+ for (BitCastInst *BCI : BCIs)
+ BCI->replaceAllUsesWith(NewLI);
+ LI->replaceAllUsesWith(NewBCI);
+
+ toErase.push_back(LI);
+ for (BitCastInst *BCI : BCIs)
+ toErase.push_back(BCI);
+
+ return true;
+}
+
+/* This function aims to change the store type if stored data is casted from
+ * another type.
+ *
+ * For example:
+ * %0 = <typeA>
+ * %1 = bitcast %0, <typeB> => store %0, <typeA>*
+ * store %1, <typeB>*
+ */
+bool CombineCasts::combineStoreCast(StoreInst *SI)
+{
+ Instruction *Ptr = dyn_cast<Instruction>(SI->getPointerOperand());
+ Instruction *Data = dyn_cast<Instruction>(SI->getValueOperand());
+
+ if (!Ptr || !Data || !isa<BitCastInst>(Data))
+ return false;
+
+ Instruction *InsertPos = SI;
+ unsigned Alignment = SI->getAlignment();
+ unsigned Volatile = SI->isVolatile();
+ BitCastInst *BCI = cast<BitCastInst>(Data);
+ Value *V = BCI->getOperand(0);
+ Type *SrcTy = V->getType();
+
+ Type *PtrTy = PointerType::get(SrcTy, SI->getPointerAddressSpace());
+ if (isa<IntToPtrInst>(Ptr))
+ Ptr = new IntToPtrInst(Ptr->getOperand(0), PtrTy, "", InsertPos);
+ else
+ Ptr = new BitCastInst(Ptr, PtrTy, "", InsertPos);
+
+ Instruction *NewSI = new StoreInst(V, Ptr, Volatile, Alignment, InsertPos);
+
+ if (MF->isGuestMemory(SI))
+ MF->setGuestMemory(NewSI);
+
+ toErase.push_back(SI);
+ return true;
+}
+
+/* This function aims to eliminate redundant casts.
+ * For example:
+ * %0 = <typeA> %0 = <typeA>
+ * %1 = bitcast %0, <typeB> =>
+ * %2 = bitcast %1, <typeC> %2 = bitcast %0, <typeC>
+ * = op <typeC> %2, ... = op <typeC> %2, ...
+ *
+ * And if <typeA> is the same as <typeC>, the code is further optimized to
+ * %0 = <typeA> %0 = <typeA>
+ * %1 = bitcast %0, <typeB> =>
+ * %2 = bitcast %1, <typeC>
+ * = op <typeC> %2, ... = op <typeA> %0, ...
+ */
+bool CombineCasts::combineCastCast(Function &F)
+{
+ SmallVector<Instruction*, 4> Worklist;
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; II++) {
+ Instruction *I = &*II;
+ if (isa<BitCastInst>(I))
+ Worklist.push_back(I);
+ }
+
+ for (auto I : Worklist) {
+ BitCastInst *CI = cast<BitCastInst>(I);
+ BitCastInst *CSrc = dyn_cast<BitCastInst>(CI->getOperand(0));
+ if (!CSrc)
+ continue;
+
+ Type *SrcTy = CSrc->getOperand(0)->getType();
+ Type *DstTy = CI->getType();
+ Value *Result = (SrcTy == DstTy) ? CSrc->getOperand(0) :
+ new BitCastInst(CSrc->getOperand(0), CI->getType(), "", CI);
+ I->replaceAllUsesWith(Result);
+ toErase.push_back(I);
+ }
+
+ if (toErase.empty())
+ return false;
+
+ ProcessErase(toErase);
+ return true;
+}
+
+/* This function converts sign change of float/double data (i.e., -num),
+ * which is implemented with integer operations, to use float/double ops.
+ * For example:
+ * %0 = bitcast float %num to i32
+ * %1 = xor i32 %0, 0x80000000 => %0 = fsub float 0, %num
+ * %2 = bitcast %1, float
+ */
+bool CombineCasts::simplifySignChange(Function &F)
+{
+ SmallVector<BitCastInst*, 16> Worklist;
+
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; II++) {
+ Instruction *I = &*II;
+ if (BitCastInst *BCI = dyn_cast<BitCastInst>(I)) {
+ Type *SrcTy = BCI->getSrcTy();
+ Type *DstTy = BCI->getDestTy();
+ if (SrcTy == FloatTy && DstTy == Int32Ty)
+ Worklist.push_back(BCI);
+ else if (SrcTy == DoubleTy && DstTy == Int64Ty)
+ Worklist.push_back(BCI);
+ }
+ }
+
+ for (auto I : Worklist) {
+ Type *Ty = I->getSrcTy();
+ Value *C = (Ty == FloatTy) ? CONST32(0x80000000)
+ : CONST64(0x8000000000000000LL);
+
+ /* Check whether the single user of this bitcast is Xor. */
+ Instruction *UI = getUniqueUser(I);
+ if (UI && UI->getOpcode() == Instruction::Xor && UI->getOperand(1) == C) {
+ /* Check whether the single user of this Xor is a bitcast
+ * instruction that casts the type back to the src type. */
+ Instruction *UUI = getUniqueUser(UI);
+ if (UUI && UUI->getOpcode() == Instruction::BitCast &&
+ cast<BitCastInst>(UUI)->getDestTy() == Ty) {
+ Value *V = BinaryOperator::Create(Instruction::FSub,
+ ConstantFP::get(Ty, 0),
+ I->getOperand(0), "", I);
+ UUI->replaceAllUsesWith(V);
+ toErase.push_back(UUI);
+ }
+ }
+ }
+
+ if (toErase.empty())
+ return false;
+
+ ProcessErase(toErase);
+ return true;
+}
+
+bool CombineCasts::runOnFunction(Function &F)
+{
+ bool Changed = false;
+ SmallVector<LoadInst *, 16> Loads;
+ SmallVector<StoreInst *, 16> Stores;
+
+ /* Collect all guest memory and non-volatile cpu state loads/stores. */
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; II++) {
+ Instruction *I = &*II;
+
+ if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
+ if (MF->isGuestMemory(LI) || !LI->isVolatile())
+ Loads.push_back(LI);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
+ if (MF->isGuestMemory(SI) || !SI->isVolatile())
+ Stores.push_back(SI);
+ }
+ }
+
+ for (auto LI : Loads)
+ Changed |= combineLoadCast(LI);
+ for (auto SI : Stores)
+ Changed |= combineStoreCast(SI);
+
+ if (toErase.size())
+ ProcessErase(toErase);
+
+ Changed |= combineCastCast(F);
+ Changed |= simplifySignChange(F);
+
+ return Changed;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/pass/CombineGuestMemory.cpp b/src/llvm/pass/CombineGuestMemory.cpp
new file mode 100644
index 0000000..0740a8b
--- /dev/null
+++ b/src/llvm/pass/CombineGuestMemory.cpp
@@ -0,0 +1,389 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm-debug.h"
+#include "llvm-opc.h"
+#include "llvm-target.h"
+#include "llvm-pass.h"
+#include "utils.h"
+
+#define PASS_NAME "CombineGuestMemory"
+
+/*
+ * CombineGuestMemory Pass
+ */
+class CombineGuestMemory : public FunctionPass {
+
+ struct StateInfo {
+ StateInfo() : Ptr(nullptr) {}
+ StateInfo(Value *ptr, APInt &offset, APInt &size)
+ : Ptr(ptr), Offset(offset), Size(size) {}
+ Value *Ptr;
+ APInt Offset;
+ APInt Size;
+ };
+
+ typedef std::pair<Value *, Value *> ValuePair;
+ typedef std::map<size_t, size_t> StateMap;
+ typedef DenseMap<ValuePair, StateInfo> CSMap;
+
+ IRFactory *IF;
+ const DataLayout *DL;
+ MDFactory *MF;
+ IntegerType *Int8Ty;
+ IntegerType *Int32Ty;
+ IntegerType *Int64Ty;
+ IntegerType *IntPtrTy;
+ PointerType *Int8PtrTy;
+ PointerType *Int32PtrTy;
+ PointerType *Int64PtrTy;
+ Value *CPU;
+ Value *GuestBase;
+ Instruction *InitLastInst;
+ StateMap LegalStates;
+ IVec toErase;
+
+public:
+ static char ID;
+ explicit CombineGuestMemory() : FunctionPass(ID) {}
+ explicit CombineGuestMemory(IRFactory *IF)
+ : FunctionPass(ID), IF(IF), DL(IF->getDL()), MF(IF->getMDFactory())
+ {
+ LLVMContext &Context = IF->getContext();;
+ Int8Ty = IntegerType::get(Context, 8);
+ Int32Ty = IntegerType::get(Context, 32);
+ Int64Ty = IntegerType::get(Context, 64);
+ IntPtrTy = DL->getIntPtrType(Context);
+ Int8PtrTy = Type::getInt8PtrTy(Context, 0);
+ Int32PtrTy = Type::getInt32PtrTy(Context, 0);
+ Int64PtrTy = Type::getInt64PtrTy(Context, 0);
+
+ GuestBase = IF->getGuestBase();
+
+ addLegalStates();
+ }
+
+ unsigned getAddressSpaceOperand(Value *I) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(I))
+ return LI->getPointerAddressSpace();
+ if (StoreInst *SI = dyn_cast<StoreInst>(I))
+ return SI->getPointerAddressSpace();
+ return -1U;
+ }
+
+ int getNumUsers(Instruction *I) {
+ return distance(I->user_begin(), I->user_end());
+ }
+
+ void addLegalStates();
+ bool isLegalState(Value *Ptr, APInt &Offset, APInt &Size);
+ bool isConsecutiveAccess(Value *A, Value *B, Value *&Ptr, APInt &Offset, APInt &Size);
+ bool tryCombineLoad(Value *A, Value *B, CSMap &States);
+ bool tryCombineStore(Value *A, Value *B, CSMap &States);
+ bool combineMemory(SmallVector<Value *, 8> &Memory, SmallVector<Value *, 8> &States);
+ bool runOnFunction(Function &F);
+};
+
+char CombineGuestMemory::ID = 0;
+INITIALIZE_PASS(CombineGuestMemory, "combinegm",
+ "Combine guest memory loads and stores", false, false)
+
+FunctionPass *llvm::createCombineGuestMemory(IRFactory *IF)
+{
+ return new CombineGuestMemory(IF);
+}
+
+
+void CombineGuestMemory::addLegalStates()
+{
+#if defined(TARGET_I386)
+ size_t Start = offsetof(CPUArchState, xmm_regs[0]);
+ size_t Size = sizeof(XMMReg);
+ for (int i = 0; i < CPU_NB_REGS; ++i)
+ LegalStates[Start + Size * i] = Size;
+#elif defined(TARGET_ARM)
+ size_t Start = offsetof(CPUArchState, vfp.regs[0]);
+ size_t Size = sizeof(float64) * 2;
+ for (int i = 0; i < 32; ++i)
+ LegalStates[Start + Size * i] = Size;
+#endif
+}
+
+bool CombineGuestMemory::isConsecutiveAccess(Value *A, Value *B, Value *&Ptr,
+ APInt &Offset, APInt &Size)
+{
+ Value *PtrA = getPointerOperand(A);
+ Value *PtrB = getPointerOperand(B);
+ unsigned ASA = getAddressSpaceOperand(A);
+ unsigned ASB = getAddressSpaceOperand(B);
+
+ if (!PtrA || !PtrB || (ASA != ASB))
+ return false;
+
+ Type *TyA = cast<PointerType>(PtrA->getType())->getElementType();
+ Type *TyB = cast<PointerType>(PtrB->getType())->getElementType();
+ if (DL->getTypeStoreSize(TyA) != DL->getTypeStoreSize(TyB))
+ return false;
+
+ unsigned PtrBitWidth = DL->getTypeSizeInBits(TyA);
+ APInt Sz(PtrBitWidth, DL->getTypeStoreSize(TyA));
+
+ APInt OffsetA(PtrBitWidth, 0), OffsetB(PtrBitWidth, 0);
+ PtrA = StripPointerWithConstantOffset(DL, PtrA, OffsetA, GuestBase);
+ PtrB = StripPointerWithConstantOffset(DL, PtrB, OffsetB, GuestBase);
+
+ APInt OffsetDelta = OffsetB - OffsetA;
+ if (PtrA == PtrB && OffsetDelta == Sz) {
+ Ptr = PtrA;
+ Offset = OffsetA;
+ Size = Sz + Sz;
+ return true;
+ }
+
+ return false;
+}
+
+bool CombineGuestMemory::isLegalState(Value *Ptr, APInt &Offset, APInt &Size)
+{
+ if (Ptr != CPU)
+ return false;
+ uint64_t Start = Offset.getZExtValue();
+ if (LegalStates.find(Start) == LegalStates.end() ||
+ Size.getZExtValue() > LegalStates[Start])
+ return false;
+ return true;
+}
+
+static bool hasMemoryViolation(Instruction *SA, Instruction *SB,
+ Instruction *EA, Instruction *EB)
+{
+ std::set<Value*> Insts;
+ Insts.insert(SA);
+ Insts.insert(SB);
+ Insts.insert(EA);
+ Insts.insert(EB);
+
+ BasicBlock::iterator BI = BasicBlock::iterator(SA);
+ BasicBlock::iterator BE = BasicBlock::iterator(EA);
+ for (; BI != BE; ++BI) {
+ Instruction *I = &*BI;
+ if (isa<CallInst>(I))
+ return true;
+ if (!isa<LoadInst>(I) && !isa<StoreInst>(I))
+ continue;
+ if (Insts.find(I) == Insts.end())
+ return true;
+ }
+
+ BI = BasicBlock::iterator(SB);
+ BE = BasicBlock::iterator(EB);
+ for (; BI != BE; ++BI) {
+ Instruction *I = &*BI;
+ if (isa<CallInst>(I))
+ return true;
+ if (!isa<LoadInst>(I) && !isa<StoreInst>(I))
+ continue;
+ if (Insts.find(I) == Insts.end())
+ return true;
+ }
+ return false;
+}
+
+bool CombineGuestMemory::tryCombineLoad(Value *A, Value *B, CSMap &States)
+{
+ /* First, check if the guest loads are 'only' used by the store instructions
+ * to consecutive CPU states, and if any other loads/stores occurs between
+ * the queried operation. */
+ LoadInst *LA = cast<LoadInst>(A);
+ LoadInst *LB = cast<LoadInst>(B);
+ if (getNumUsers(LA) != 1 || getNumUsers(LB) != 1)
+ return false;
+
+ Value *VA = *LA->user_begin();
+ Value *VB = *LB->user_begin();
+ CSMap::iterator CSI = States.find(ValuePair(VA, VB));
+ if (CSI == States.end())
+ return false;
+
+ Instruction *SA = cast<Instruction>(VA);
+ Instruction *SB = cast<Instruction>(VB);
+
+ if (hasMemoryViolation(LA, LB, SA, SB))
+ return false;
+
+ /* Here we found the guest memory operations are loaded and stored to the
+ * CPU states immediately. The operations are safe to combine. */
+ Instruction *InsertPos = SA;
+ StateInfo &SI = CSI->second;
+ uint64_t Size = SI.Size.getZExtValue();
+ unsigned AS = getAddressSpaceOperand(LA);
+ unsigned Align = Size / 2;
+ Type *Ty = PointerType::get(VectorType::get(Int8Ty, Size), AS);
+ Instruction *Ptr = cast<Instruction>(LA->getPointerOperand());
+ if (isa<IntToPtrInst>(Ptr))
+ Ptr = new IntToPtrInst(Ptr->getOperand(0), Ty, "", InsertPos);
+ else
+ Ptr = new BitCastInst(Ptr, Ty, "", InsertPos);
+ Instruction *NewLI = new LoadInst(Ptr, "", true, Align, InsertPos);
+ MF->setGuestMemory(NewLI);
+
+ Ty = PointerType::getUnqual(VectorType::get(Int8Ty, Size));
+ Value *Offset = ConstantInt::get(Ty->getContext(), SI.Offset);
+ Ptr = GetElementPtrInst::CreateInBounds(CPU, Offset, "", InitLastInst);
+ Ptr = new BitCastInst(Ptr, Ty, "", InitLastInst);
+ new StoreInst(NewLI, Ptr, false, InsertPos);
+
+ States.erase(CSI);
+ toErase.push_back(SA);
+ toErase.push_back(SB);
+ return true;
+}
+
+bool CombineGuestMemory::tryCombineStore(Value *A, Value *B, CSMap &States)
+{
+ /* First, check if the CPU state loads are 'only' used by the guest store
+ * instructions, and if any other loads/stores occurs between the
+ * queried operation. */
+ StoreInst *SA = cast<StoreInst>(A);
+ StoreInst *SB = cast<StoreInst>(B);
+ Instruction *LA = dyn_cast<Instruction>(SA->getOperand(0));
+ Instruction *LB = dyn_cast<Instruction>(SB->getOperand(0));
+
+ if (!LA || !LB)
+ return false;
+ if (getNumUsers(LA) != 1 || getNumUsers(LB) != 1)
+ return false;
+
+ CSMap::iterator CSI = States.find(ValuePair(LA, LB));
+ if (CSI == States.end())
+ return false;
+
+ if (hasMemoryViolation(LA, LB, SA, SB))
+ return false;
+
+ /* Here we found the CPU states are loaded and stored to the guest memory
+ * immediately. The operations are safe to combine. */
+ Instruction *InsertPos = SA;
+ StateInfo &SI = CSI->second;
+ uint64_t Size = SI.Size.getZExtValue();
+ Type *Ty = PointerType::getUnqual(VectorType::get(Int8Ty, Size));
+ Value *Offset = ConstantInt::get(Ty->getContext(), SI.Offset);
+ Instruction *Ptr = GetElementPtrInst::CreateInBounds(CPU, Offset, "", InitLastInst);
+ Ptr = new BitCastInst(Ptr, Ty, "", InitLastInst);
+ Value *V = new LoadInst(Ptr, "", false, InsertPos);
+
+ unsigned AS = getAddressSpaceOperand(SA);
+ unsigned Align = Size / 2;
+ Ty = PointerType::get(VectorType::get(Int8Ty, Size), AS);
+ Ptr = cast<Instruction>(SA->getPointerOperand());
+ if (isa<IntToPtrInst>(Ptr))
+ Ptr = new IntToPtrInst(Ptr->getOperand(0), Ty, "", InsertPos);
+ else
+ Ptr = new BitCastInst(Ptr, Ty, "", InsertPos);
+ Instruction *NewSI = new StoreInst(V, Ptr, true, Align, InsertPos);
+ MF->setGuestMemory(NewSI);
+
+ States.erase(CSI);
+ toErase.push_back(SA);
+ toErase.push_back(SB);
+ return true;
+}
+
+bool CombineGuestMemory::combineMemory(SmallVector<Value *, 8> &Memory,
+ SmallVector<Value *, 8> &States)
+{
+ bool Changed = false;
+ SmallPtrSet<Value *, 4> Used;
+ CSMap ConsecutiveStates;
+ Value *Ptr;
+ APInt Offset, Size;
+
+ /* Find consecutive CPU states. */
+ for (unsigned i = 1, e = States.size(); i != e; i++) {
+ if (!isConsecutiveAccess(States[i-1], States[i], Ptr, Offset, Size))
+ continue;
+
+ if (!isLegalState(Ptr, Offset, Size))
+ continue;
+
+ ConsecutiveStates[ValuePair(States[i-1], States[i])] =
+ StateInfo(Ptr, Offset, Size);
+ }
+
+ if (ConsecutiveStates.size() == 0)
+ return false;
+
+ /* Find and combine consecutive guest memory accesses if their referrenced
+ * CPU states are also consecutive. */
+ for (unsigned i = 1, e = Memory.size(); i != e; i++) {
+ if (Used.count(Memory[i-1]) || Used.count(Memory[i]))
+ continue;
+ if (!isConsecutiveAccess(Memory[i-1], Memory[i], Ptr, Offset, Size))
+ continue;
+
+ bool ret = false;
+ if (isa<LoadInst>(Memory[i-1]) && isa<LoadInst>(Memory[i])) {
+ ret = tryCombineLoad(Memory[i-1], Memory[i], ConsecutiveStates);
+ } else if (isa<StoreInst>(Memory[i-1]) && isa<StoreInst>(Memory[i])) {
+ ret = tryCombineStore(Memory[i-1], Memory[i], ConsecutiveStates);
+ }
+ if (ret) {
+ Used.insert(Memory[i-1]);
+ Used.insert(Memory[i]);
+ Changed = true;
+ }
+ }
+ return Changed;
+}
+
+bool CombineGuestMemory::runOnFunction(Function &F)
+{
+ bool Changed = false;
+
+#if defined(CONFIG_SOFTMMU)
+ return Changed;
+#endif
+
+ /* Skip if no state is allowed to be combined. */
+ if (LegalStates.empty())
+ return Changed;
+
+ CPU = IF->getDefaultCPU(F);
+ if (!CPU) {
+ dbg() << DEBUG_PASS << "CombineGuestMemory: Cannot find CPU pointer.\n";
+ return false;
+ }
+
+ InitLastInst = F.getEntryBlock().getTerminator();
+
+ for (auto FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
+ SmallVector<Value *, 8> Memory;
+ SmallVector<Value *, 8> States;
+ for (auto BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) {
+ Instruction *I = &*BI;
+ if (MF->isGuestMemory(I)) {
+ Memory.push_back(I);
+ } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
+ if (!LI->isVolatile())
+ States.push_back(LI);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
+ if (!SI->isVolatile())
+ States.push_back(SI);
+ }
+ }
+ if (Memory.size() >= 2 && States.size() >= 2)
+ Changed |= combineMemory(Memory, States);
+ }
+
+ if (!toErase.empty())
+ ProcessErase(toErase);
+
+ return Changed;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/pass/CombineZExtTrunc.cpp b/src/llvm/pass/CombineZExtTrunc.cpp
new file mode 100644
index 0000000..de9a87f
--- /dev/null
+++ b/src/llvm/pass/CombineZExtTrunc.cpp
@@ -0,0 +1,70 @@
+/*
+ * (C) 2015 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/Transforms/Utils/Local.h"
+#include "llvm-target.h"
+#include "llvm-opc.h"
+#include "llvm-pass.h"
+#include "utils.h"
+
+#define PASS_NAME "CombineZExtTrunc"
+
+/*
+ * CombineZExtTrunc Pass
+ */
+class CombineZExtTrunc : public FunctionPass {
+public:
+ static char ID;
+ explicit CombineZExtTrunc() : FunctionPass(ID) {}
+ bool runOnFunction(Function &F);
+};
+
+char CombineZExtTrunc::ID = 0;
+INITIALIZE_PASS(CombineZExtTrunc, "combinezet",
+ "Combine ZExt followed by Trunc", false, false)
+
+FunctionPass *llvm::createCombineZExtTrunc()
+{
+ return new CombineZExtTrunc;
+}
+
+bool CombineZExtTrunc::runOnFunction(Function &F)
+{
+ bool Changed = false;
+ IVec toErase;
+
+ SmallVector<Instruction*, 4> Worklist;
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; II++) {
+ Instruction *I = &*II;
+ if (isa<TruncInst>(I))
+ Worklist.push_back(I);
+ }
+
+ for (auto I : Worklist) {
+ TruncInst *TI = cast<TruncInst>(I);
+ ZExtInst *ZI = dyn_cast<ZExtInst>(TI->getOperand(0));
+ if (!ZI)
+ continue;
+
+ Type *SrcTy = ZI->getOperand(0)->getType();
+ Type *DstTy = TI->getType();
+ if (SrcTy == DstTy) {
+ I->replaceAllUsesWith(ZI->getOperand(0));
+ if (TI->use_empty())
+ toErase.push_back(TI);
+ Changed = true;
+ }
+ }
+
+ if (toErase.size())
+ ProcessErase(toErase);
+
+ return Changed;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/pass/FastMathPass.cpp b/src/llvm/pass/FastMathPass.cpp
new file mode 100644
index 0000000..2b6a592
--- /dev/null
+++ b/src/llvm/pass/FastMathPass.cpp
@@ -0,0 +1,87 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm-target.h"
+#include "llvm-pass.h"
+#include "fpu/softfloat-native-def.h"
+
+#define PASS_DEBUG "FastMathPass"
+
+class FastMathPass : public FunctionPass {
+public:
+ static char ID;
+ std::map<std::string, std::string> FPUNameMap;
+
+ explicit FastMathPass() : FunctionPass(ID)
+ {
+ TCGHelperInfo *FPUHelper = (TCGHelperInfo *)get_native_fpu_helpers();
+ for (int i = 0, e = num_native_fpu_helpers(); i != e; ++i) {
+ /* ex: llvm_int32_to_float32 --> int32_to_float32 */
+ TCGHelperInfo &fpu = FPUHelper[i];
+ const char *native = fpu.name;
+ const char *soft = native + 5;
+ FPUNameMap[soft] = native;
+ }
+ }
+ bool runOnFunction(Function &F);
+};
+
+bool FastMathPass::runOnFunction(Function &F)
+{
+ IVec toErase;
+ SmallVector<CallInst *, 16> InlineCalls;
+ Module *Mod = F.getParent();
+
+ for (auto I = inst_begin(F), E = inst_end(F); I != E; ++I) {
+ if (CallInst *CI = dyn_cast<CallInst>(&*I)) {
+ if (CI->isInlineAsm() ||
+ CI->getCalledFunction() == nullptr ||
+ CI->getCalledFunction()->isIntrinsic())
+ continue;
+
+ std::string Fname = CI->getCalledFunction()->getName();
+ if (FPUNameMap.count(Fname) == 0)
+ continue;
+
+ Function *Fn = Mod->getFunction(FPUNameMap[Fname]);
+ FunctionType *FTy = cast<FunctionType>(
+ cast<PointerType>(Fn->getType())->getElementType());
+
+ unsigned NumArgs = FTy->getNumParams();
+ assert(NumArgs <= CI->getNumArgOperands());
+
+ SmallVector<Value *, 4> Params;
+ for (unsigned i = 0; i != NumArgs; ++i)
+ Params.push_back(CI->getArgOperand(i));
+
+ CallInst *NewCI = CallInst::Create(Fn, Params, "", CI);
+ CI->replaceAllUsesWith(NewCI);
+ InlineCalls.push_back(NewCI);
+ toErase.push_back(CI);
+ }
+ }
+
+ ProcessErase(toErase);
+
+ while (!InlineCalls.empty())
+ InlineFunc(InlineCalls.pop_back_val());
+
+ return false;
+}
+
+char FastMathPass::ID = 0;
+INITIALIZE_PASS(FastMathPass, "fastmath",
+ "Transform softfloat subroutines to native FP operations", false, false)
+
+FunctionPass *llvm::createFastMathPass()
+{
+ return new FastMathPass();
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/pass/ProfileExec.cpp b/src/llvm/pass/ProfileExec.cpp
new file mode 100644
index 0000000..56a68e1
--- /dev/null
+++ b/src/llvm/pass/ProfileExec.cpp
@@ -0,0 +1,172 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm-debug.h"
+#include "llvm-soft-perfmon.h"
+#include "llvm-pass.h"
+#include "llvm-opc.h"
+#include "llvm.h"
+#include "utils.h"
+
+#define PASS_NAME "ProfileExec"
+
+extern LLVMEnv *LLEnv;
+
+/*
+ * Profile Pass
+ */
+class ProfileExec : public FunctionPass {
+ enum {
+ IDX_LOOP = 0,
+ IDX_EXIT,
+ IDX_INBR,
+ };
+
+ IRFactory *IF;
+ const DataLayout *DL;
+ MDFactory *MF;
+ IntegerType *Int8Ty;
+ IntegerType *Int32Ty;
+ IntegerType *Int64Ty;
+ IntegerType *IntPtrTy;
+ PointerType *Int8PtrTy;
+ PointerType *Int32PtrTy;
+ PointerType *Int64PtrTy;
+
+public:
+ static char ID;
+ explicit ProfileExec() : FunctionPass(ID) {}
+ explicit ProfileExec(IRFactory *IF)
+ : FunctionPass(ID), IF(IF), DL(IF->getDL()), MF(IF->getMDFactory())
+ {
+ LLVMContext &Context = IF->getContext();;
+ Int8Ty = IntegerType::get(Context, 8);
+ Int32Ty = IntegerType::get(Context, 32);
+ Int64Ty = IntegerType::get(Context, 64);
+ IntPtrTy = DL->getIntPtrType(Context);
+ Int8PtrTy = Type::getInt8PtrTy(Context, 0);
+ Int32PtrTy = Type::getInt32PtrTy(Context, 0);
+ Int64PtrTy = Type::getInt64PtrTy(Context, 0);
+ }
+ bool runOnFunction(Function &F);
+
+ Instruction *getInsertPos(BasicBlock *BB) {
+ if (BB == &BB->getParent()->getEntryBlock())
+ return &*++BB->begin();
+ return BB->getFirstNonPHI();
+ }
+};
+
+char ProfileExec::ID = 0;
+INITIALIZE_PASS(ProfileExec, "profile", "Profile trace execution", false, false)
+
+FunctionPass *llvm::createProfileExec(IRFactory *IF)
+{
+ return new ProfileExec(IF);
+}
+
+bool ProfileExec::runOnFunction(Function &F)
+{
+ if (!LLEnv->isTraceMode())
+ return false;
+ if (!SP->isEnabled())
+ return false;
+
+ Instruction *CPU = IF->getDefaultCPU(F);
+ if (!CPU) {
+ dbg() << DEBUG_PASS << PASS_NAME << ": Cannot find CPU pointer.\n";
+ return false;
+ }
+
+ TraceInfo *Trace = IF->getTrace();
+
+ for (auto FI = F.begin(), FE = F.end(); FI != FE; FI++) {
+ BasicBlock *BB = &*FI;
+ if (distance(succ_begin(BB), succ_end(BB)) != 0)
+ continue;
+
+ /* Find exit points and indirect branches. */
+ Trace->NumExit++;
+ if (isa<IndirectBrInst>(BB->getTerminator()))
+ Trace->NumIndirectBr++;
+ }
+
+ /* Insert code to profile trace exit counts. */
+ if (SP->Mode & SPM_EXIT) {
+ Instruction *InsertPos = &*++BasicBlock::iterator(CPU);
+ Value *NumExitPtr = GetElementPtrInst::CreateInBounds(CPU,
+ CONSTPtr(offsetof(CPUArchState, num_trace_exits)),
+ "", InsertPos);
+ NumExitPtr = new BitCastInst(NumExitPtr, Int64PtrTy, "", InsertPos);
+ Instruction *NumExits = new LoadInst(NumExitPtr, "", true, InsertPos);
+ NumExits = BinaryOperator::Create(Instruction::Add, NumExits,
+ CONST64(1), "", InsertPos);
+ new StoreInst(NumExits, NumExitPtr, true, InsertPos);
+ }
+
+ if (!(SP->Mode & SPM_TRACE))
+ return false;
+
+ SmallVector<CallInst*, 16> InlineCalls;
+ Function *Helper = IF->ResolveFunction("helper_profile_exec");
+
+ /* Prepare counter structures. */
+ if (!Trace->ExecCount) {
+ Trace->ExecCount = new uint64_t *[MAX_SPM_THREADS];
+ for (int i = 0; i < MAX_SPM_THREADS; i++)
+ Trace->ExecCount[i] = new uint64_t[3] {0, 0, 0};
+ }
+
+ /* Find all profiling point. */
+ std::vector<std::pair<Instruction *, int> > ProfilePoint;
+
+ SmallVector<std::pair<const BasicBlock*,const BasicBlock*>, 32> BackEdges;
+ FindFunctionBackedges(F, BackEdges);
+ for (unsigned i = 0, e = BackEdges.size(); i != e; ++i) {
+ auto BackEdgeBB = const_cast<BasicBlock*>(BackEdges[i].first);
+ ProfilePoint.push_back(std::make_pair(BackEdgeBB->getTerminator(), IDX_LOOP));
+ }
+
+ for (auto FI = F.begin(), FE = F.end(); FI != FE; FI++) {
+ BasicBlock *BB = &*FI;
+ if (distance(succ_begin(BB), succ_end(BB)) != 0)
+ continue;
+ bool isIndirectBr = isa<IndirectBrInst>(BB->getTerminator());
+ ProfilePoint.push_back(std::make_pair(getInsertPos(BB),
+ isIndirectBr ? IDX_INBR : IDX_EXIT));
+ }
+
+ /* Insert profiling routines. */
+ for (unsigned i = 0, e = ProfilePoint.size(); i != e; ++i) {
+ Instruction *InsertPos = ProfilePoint[i].first;
+ Value *Ty = CONST32(ProfilePoint[i].second);
+
+ Value *Counter = ConstantExpr::getIntToPtr(
+ CONSTPtr((uintptr_t)Trace->ExecCount),
+ PointerType::getUnqual(Int8Ty));
+
+ SmallVector<Value *, 4> Params;
+ Type *ParamTy = Helper->getFunctionType()->getParamType(0);
+ Value *Env = new BitCastInst(CPU, ParamTy, "", InsertPos);
+ Params.push_back(Env);
+ Params.push_back(Counter);
+ Params.push_back(Ty);
+
+ CallInst *CI = CallInst::Create(Helper, Params, "", InsertPos);
+ MF->setConst(CI);
+ InlineCalls.push_back(CI);
+ }
+
+ while (!InlineCalls.empty())
+ InlineFunc(InlineCalls.pop_back_val());
+
+ return true;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/pass/RedundantStateElimination.cpp b/src/llvm/pass/RedundantStateElimination.cpp
new file mode 100644
index 0000000..2e5f715
--- /dev/null
+++ b/src/llvm/pass/RedundantStateElimination.cpp
@@ -0,0 +1,179 @@
+/*
+ * (C) 2017 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm-debug.h"
+#include "llvm-opc.h"
+#include "llvm-target.h"
+#include "llvm-pass.h"
+#include "utils.h"
+
+#define PASS_NAME "RedundantStateElimination"
+
+/*
+ * The RedundantStateElimination pass aims to remove
+ * (1) redundant stores to PC, and
+ * (2) redundant loads and stores enclosed by two helper function calls.
+ */
+class RedundantStateElimination : public FunctionPass {
+ IRFactory *IF;
+ MDFactory *MF;
+ const DataLayout *DL;
+ Value *CPU;
+ IVec toErase;
+
+public:
+ static char ID;
+ explicit RedundantStateElimination() : FunctionPass(ID) {}
+ explicit RedundantStateElimination(IRFactory *IF)
+ : FunctionPass(ID), IF(IF), MF(IF->getMDFactory()), DL(IF->getDL()) {}
+
+ int getNumUsers(Instruction *I) {
+ return distance(I->user_begin(), I->user_end());
+ }
+
+ bool isStateOfPC(Value *Ptr) {
+ intptr_t Off = 0;
+ Value *Base = getBaseWithConstantOffset(DL, Ptr, Off);
+ if (Base == CPU && IRFactory::isStateOfPC(Off))
+ return true;
+ return false;
+ }
+
+ bool isDirectDominator(LoadInst *LI, StoreInst *SI) {
+ Instruction *A = LI, *B = SI;
+ if (A->getParent() != B->getParent())
+ return false;
+ for (auto II = BasicBlock::iterator(A), EE = A->getParent()->end();
+ II != EE; ++II) {
+ if (&*II == B)
+ return true;
+ /* If a non-const helper function is between the two instructions,
+ * this is not a direct domination because the helper function could
+ * cause side effect. */
+ auto CI = dyn_cast<CallInst>(II);
+ if (CI && !MDFactory::isConst(CI))
+ return false;
+ }
+ return false;
+ }
+
+ bool removePCState(Function &F);
+ bool removeHelperState(Function &F);
+ bool runOnFunction(Function &F);
+};
+
+char RedundantStateElimination::ID = 0;
+INITIALIZE_PASS(RedundantStateElimination, "rse",
+ "Eliminate redundant CPU state loads/stores", false, false)
+
+FunctionPass *llvm::createRedundantStateElimination(IRFactory *IF)
+{
+ return new RedundantStateElimination(IF);
+}
+
+/* Eliminate redundant stores to PC for each basic block. */
+bool RedundantStateElimination::removePCState(Function &F)
+{
+ for (auto FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
+ bool Found = false;
+
+ for (auto BI = FI->rbegin(), BE = FI->rend(); BI != BE; ++BI) {
+ Instruction *I = &*BI;
+ if (MF->isGuestMemory(I))
+ continue;
+
+ if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
+ if (isStateOfPC(getPointerOperand(SI))) {
+ if (!Found)
+ Found = true;
+ else
+ toErase.push_back(SI);
+ }
+ } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
+ if (isStateOfPC(getPointerOperand(LI)))
+ Found = false;
+ }
+ }
+ }
+
+ if (toErase.empty())
+ return false;
+
+ ProcessErase(toErase);
+ return true;
+
+}
+
+/* Eliminate redundant loads/stores enclosed by two helper function calls.
+ * The redundant loads and stores are generated by StateMappingPass for
+ * handling synchronization of CPU states around helper function calls.
+ * A load and store can be removed if a state value is loaded and immediately
+ * stored back to the same state. For example:
+ *
+ * Before optimization: After optimization:
+ * instructions to sync states instructions to sync states
+ * call void @helper_function1() call void @helper_function1()
+ *
+ * %v0 = load i32, i32* %state0
+ * %v1 = load i32, i32* %state1
+ * store i32 %v0, i32* %state0
+ * store i32 %v1, i32* %state1
+ *
+ * call void @helper_function2() call void @helper_function2()
+ * instructions to reload states instructions to reload states
+ */
+bool RedundantStateElimination::removeHelperState(Function &F)
+{
+ for (auto FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
+ for (auto BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) {
+ Instruction *I = &*BI;
+ if (MF->isGuestMemory(I))
+ continue;
+
+ StoreInst *SI = dyn_cast<StoreInst>(I);
+ if (!SI || SI->isVolatile())
+ continue;
+
+ LoadInst *LI = dyn_cast<LoadInst>(getValueOperand(SI));
+ if (LI && isDirectDominator(LI, SI)) {
+ /* We can try removing the store instruction if LI is a direct
+ * dominator of SI. */
+ Value *PtrA = getPointerOperand(LI);
+ Value *PtrB = getPointerOperand(SI);
+ if (StripPointer(PtrA) == CPU && PtrA == PtrB)
+ toErase.push_back(SI);
+ }
+ }
+ }
+
+ if (toErase.empty())
+ return false;
+
+ ProcessErase(toErase);
+ return true;
+}
+
+bool RedundantStateElimination::runOnFunction(Function &F)
+{
+ bool Changed = false;
+
+ CPU = IF->getDefaultCPU(F);
+ if (!CPU) {
+ dbg() << DEBUG_PASS << "RedundantStateElimination: Cannot find CPU pointer.\n";
+ return false;
+ }
+
+ Changed |= removePCState(F);
+#if 0
+ Changed |= removeHelperState(F);
+#endif
+
+ return Changed;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/pass/ReplaceIntrinsic.cpp b/src/llvm/pass/ReplaceIntrinsic.cpp
new file mode 100644
index 0000000..62505f4
--- /dev/null
+++ b/src/llvm/pass/ReplaceIntrinsic.cpp
@@ -0,0 +1,137 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm-types.h"
+#include "llvm-debug.h"
+#include "llvm-target.h"
+#include "llvm-pass.h"
+
+
+#define PASS_NAME "ReplaceIntrinsic"
+
+/*
+ * HQEMU does not allow helpers to contain any memory or debug intrinsics.
+ * This pass substitutes memory intrinsics to load/store instuctions and
+ * removes debug intrinsics (generated by Clang with -g flag).
+ */
+class ReplaceIntrinsic : public FunctionPass {
+ IVec toErase;
+public:
+ static char ID;
+ explicit ReplaceIntrinsic() : FunctionPass(ID) {}
+
+ Value *ConvertType(Value *V, Type *T, Instruction *InsertPos) {
+ if (likely(V->getType() == T))
+ return V;
+ return new BitCastInst(V, T, "", InsertPos);
+ }
+
+ bool replaceMemoryIntrinsic(IntrinsicInst *I);
+ bool runOnFunction(Function &F);
+};
+
+char ReplaceIntrinsic::ID = 0;
+INITIALIZE_PASS(ReplaceIntrinsic, "replaceintrinsic",
+ "Replace memory and debug intrinsics generated by clang",
+ false, false)
+
+FunctionPass *llvm::createReplaceIntrinsic()
+{
+ return new ReplaceIntrinsic();
+}
+
+
+/*
+ * Transform memcpy/memmove/memset to load/store instruction.
+ * Clang attempts to move memory data using LLVM memory intrinsic instructions.
+ * This causes the statemapping pass to miss some guest states. (Statemapping
+ * only considers guest states accessed by general load/store insts).
+ * So, we simply rewrite the memory intrinsics to load/store instuctions.
+ */
+bool ReplaceIntrinsic::replaceMemoryIntrinsic(IntrinsicInst *I)
+{
+ switch (I->getIntrinsicID()) {
+ case Intrinsic::memset:
+ case Intrinsic::memcpy:
+ case Intrinsic::memmove:
+ break;
+ default:
+ return false;
+ }
+
+ LLVMContext &Context = I->getContext();
+ Type *Int8PtrTy = Type::getInt8PtrTy(Context);
+ CallInst *CI = cast<CallInst>(I);
+
+ if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(I)) {
+ /* memcpy/memmove */
+ Value *Src = MTI->getSource();
+ Value *Dst = MTI->getDest();
+ Value *NumBytes = MTI->getLength();
+
+ if (CI->getArgOperand(0)->getType() != Int8PtrTy ||
+ CI->getArgOperand(1)->getType() != Int8PtrTy ||
+ !isa<ConstantInt>(NumBytes) ||
+ MTI->isVolatile())
+ return false;
+
+ /* Remove this instruction if the access size is zero. */
+ size_t Len = cast<ConstantInt>(NumBytes)->getZExtValue();
+ if (Len == 0)
+ goto done;
+
+ Type *Ty = Type::getIntNPtrTy(Context, Len * 8);
+ Src = ConvertType(Src, Ty, I);
+ Dst = ConvertType(Dst, Ty, I);
+ Src = new LoadInst(Src, "", false, I);
+ new StoreInst(Src, Dst, false, I);
+ } else if (MemSetInst *MSI = dyn_cast<MemSetInst>(I)) {
+ /* memset */
+ Value *Src = MSI->getValue();
+ Value *Dst = MSI->getDest();
+ Value *NumBytes = MSI->getLength();
+
+ if (CI->getArgOperand(0)->getType() != Int8PtrTy ||
+ !isa<ConstantInt>(Src) ||
+ !isa<ConstantInt>(NumBytes) ||
+ MSI->isVolatile())
+ return false;
+
+ size_t Val = cast<ConstantInt>(Src)->getZExtValue();
+ size_t Len = cast<ConstantInt>(NumBytes)->getZExtValue();
+ if (Val != 0)
+ return false;
+ if (Len == 0)
+ goto done;
+
+ Type *Ty = Type::getIntNPtrTy(Context, Len * 8);
+ Src = ConstantInt::get(Type::getIntNTy(Context, Len * 8), 0);
+ Dst = ConvertType(Dst, Ty, I);
+ new StoreInst(Src, Dst, false, I);
+ }
+
+done:
+ toErase.push_back(I);
+ return true;
+}
+
+bool ReplaceIntrinsic::runOnFunction(Function &F)
+{
+ for (auto I = inst_begin(&F), E = inst_end(&F); I != E; ++I) {
+ Instruction *Inst = &*I;
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) {
+ if (replaceMemoryIntrinsic(II))
+ continue;
+ if (isa<DbgInfoIntrinsic>(II))
+ toErase.push_back(II);
+ }
+ }
+ ProcessErase(toErase);
+ return true;
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/pass/SimplifyPointer.cpp b/src/llvm/pass/SimplifyPointer.cpp
new file mode 100644
index 0000000..87afbdd
--- /dev/null
+++ b/src/llvm/pass/SimplifyPointer.cpp
@@ -0,0 +1,334 @@
+//===- SimplifyPointer.cpp - Reassociate guest pointer arithmetic ---------===//
+//
+// The HQEMU Dynamic Binary Translator Infrastructure
+//
+// (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+// COVART Laboratory, CSIE Department, National Taiwan University, Taiwan.
+// See COPYRIGHT in top-level directory.
+//
+//===----------------------------------------------------------------------===//
+// This pass implements a simple pointer arithmetic reassociator for easier
+// pointer stripping. It gets scalar evolution results of all guest pointers
+// which are in simplest form. Next, it inserts new instructions to evaluate the
+// simplified expressions to construct new pointers, and rewrites corresponding
+// guest load/store with new pointers.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpander.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/InstIterator.h"
+
+#include "llvm-opc.h"
+#include "llvm-pass.h"
+#include "llvm-target.h"
+#include "utils.h"
+
+#define PASS_NAME "SIMPTR"
+#define DEBUG_TYPE "SIMPTR"
+
+//#define VERBOSE
+
+/// \brief Dump pass debug message with pass name mark.
+static inline llvm::raw_ostream &pout() {
+ return dbg() << DEBUG_PASS << PASS_NAME ": ";
+}
+
+/// \returns True if \p A dominates \p B.
+static bool dominates(Value *A, Value *B, DominatorTree *DT) {
+ auto *AI = dyn_cast<Instruction>(A);
+ auto *BI = dyn_cast<Instruction>(B);
+ if (AI && BI)
+ return DT->dominates(AI, BI);
+ return false;
+}
+
+class SimplifyPointer : public FunctionPass {
+public:
+ using ValueList = SmallVector<Value *, 32>;
+ using InstrList = SmallVector<Instruction *, 32>;
+ using ExprValMap = DenseMap<const SCEV *, Value *>;
+
+ // Pass identification, replacement for type id.
+ static char ID;
+
+ // LLVM pass constructor and destructor.
+ explicit SimplifyPointer() : FunctionPass(ID){};
+ explicit SimplifyPointer(IRFactory *IF)
+ : FunctionPass(ID), IF(IF), MF(IF->getMDFactory()), DL(IF->getDL()) {
+ // Initialize all.
+ initializeSimplifyPointerPass(*PassRegistry::getPassRegistry());
+ }
+
+ // LLVM pass public interfaces.
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+ bool runOnFunction(Function &F) override;
+
+private:
+ /// \return The evaluation result of expression \p S or null if not cached.
+ Value *lookupBaseExpressionCache(const SCEV *S) const {
+ auto V = BaseExprVal.find(S);
+ if (V != BaseExprVal.end())
+ return V->second;
+ return nullptr;
+ }
+
+ /// \returns True if spread constants in the expression tree of \p S can be
+ /// collected by reassociation and reduced to \p FoldVal.
+ ///
+ /// It traverses the expression tree of \p S and propagates constant nodes
+ /// from add, multiply and recurrent add nodes, i.e., (%1 + %2 + 5) * (%3 - 7)
+ /// should return 5 * -7 = -35.
+ bool foldConstantExpression(const SCEV *S, int64_t &FoldVal) const;
+
+ /// \returns The first non-pointer value traced along the use-define chain of
+ /// casting which starts from \p V and ends with a IntToPtrInst, or null if
+ /// the length of searching chain exceeds \p MaxLookup.
+ ///
+ /// In the context of DBT, pointer type is represented and manipulated as
+ /// integer data until used as a pointer. Therefore, it follows:
+ ///
+ /// [Expression Tree]
+ /// + + + +
+ /// \ / \ /
+ /// - ... -
+ /// \ /
+ /// +
+ /// [Scalar Root]
+ /// |
+ /// [Casting]
+ /// |
+ /// [Load/Store]
+ ///
+ /// This method targets the scalar root value.
+ Value *findPointerScalarRoot(Value *V, unsigned MaxLookup = 4);
+
+ /// \brief Simplify the pointer arithmetic of \p LSI based on scalar evolution
+ /// results which folds constants into simplest form. After extracting the
+ /// folded constant from the expression, the rest nodes can form a base
+ /// expression which is likely a common sub-expression of other \p LSI.
+ ///
+ /// It assumes \p LSI has the following use-define chain starting from its
+ /// pointer and containing only add, multiply and recurrent add nodes.
+ ///
+ /// [Expression Tree] [Expression Tree] [Expression Tree]
+ /// + A B + + + B A + +
+ /// \ / \ / \ / \ / \ /
+ /// - ... - - ... - - (B-A)
+ /// \ / \ / \ /
+ /// + + +
+ /// [Scalar Root] >> [Scalar Root] >> [Scalar Root]
+ /// | | |
+ /// [Casting] [Casting] [Casting]
+ /// | | |
+ /// [LSI] [LSI] [LSI]
+ ///
+ /// Suppose A and B are constants, they can be folded into (B-A) with scalar
+ /// evolution results. Need to insert instructions for other operations in
+ /// tree (e.g., the new sub in the right-most figure).
+ ///
+ /// First it tries to find the folded constant and substract it from root
+ /// expression to form the base expression. Then it generates instructions to
+ /// evaluate the base expression.
+ bool tryToSimplifyPointer(Instruction *I);
+
+ // HQEMU internal infrastructure.
+ IRFactory *IF = nullptr;
+ MDFactory *MF = nullptr;
+ // LLVM analysis and data type info.
+ const DataLayout *DL = nullptr;
+ DominatorTree *DT = nullptr;
+ ScalarEvolution *SE = nullptr;
+
+ /// The cache of base expression to corresponding evaluated value map.
+ ExprValMap BaseExprVal;
+};
+
+bool SimplifyPointer::foldConstantExpression(const SCEV *S,
+ int64_t &FoldVal) const {
+ // Handle expression tree of scalar root containing only add, multiply and
+ // recurrent add nodes.
+ if (auto *AddSE = dyn_cast<SCEVAddExpr>(S)) {
+ FoldVal = 0;
+ for (auto Op : AddSE->operands()) {
+ int64_t Val;
+ if (foldConstantExpression(Op, Val))
+ FoldVal += Val;
+ }
+ return true;
+ } else if (auto *MulSE = dyn_cast<SCEVMulExpr>(S)) {
+ FoldVal = 1;
+ for (auto Op : MulSE->operands()) {
+ int64_t Val;
+ // If one operand of multiplication fails to report a constant, entire
+ // expression becomes non-constant as well.
+ if (foldConstantExpression(Op, Val))
+ FoldVal *= Val;
+ else
+ return false;
+ }
+ return true;
+ } else if (auto *RecSE = dyn_cast<SCEVAddRecExpr>(S)) {
+ // Trace only the start expression, because the step expression must be
+ // multiplied by the loop trip count which is unlikely constant.
+ return foldConstantExpression(RecSE->getStart(), FoldVal);
+ } else if (auto *ConstSE = dyn_cast<SCEVConstant>(S)) {
+ FoldVal = ConstSE->getValue()->getValue().getSExtValue();
+ return true;
+ }
+ return false;
+}
+
+Value *SimplifyPointer::findPointerScalarRoot(Value *V, unsigned MaxLookup) {
+ if (!V || !V->getType()->isPointerTy())
+ return V;
+
+ for (unsigned i = 0; i < MaxLookup; ++i) {
+ if (BitCastInst *Cast = dyn_cast<BitCastInst>(V)) {
+ V = Cast->getOperand(0);
+ } else if (IntToPtrInst *Cast = dyn_cast<IntToPtrInst>(V)) {
+ // Found first scalar, return it.
+ V = Cast->getOperand(0);
+ return V;
+ }
+ }
+ return nullptr;
+}
+
+bool SimplifyPointer::tryToSimplifyPointer(Instruction *LSI) {
+ Value *Ptr = getPointerOperand(LSI);
+ Value *Root = findPointerScalarRoot(Ptr);
+ Type *RootTy = Root->getType();
+ Type *PtrTy = Ptr->getType();
+ if (!Ptr || !Root || !RootTy->isIntegerTy())
+ return false;
+
+#ifdef VERBOSE
+ if (DM.getDebugMode() & DEBUG_PASS) {
+ pout() << "Visiting memory instruction.\n";
+ pout() << "- " << *LSI << ".\n";
+ }
+#endif
+
+ // Traverse the simplest form expression tree and collect folded constants.
+ // Note the folded constant can be zero (base = root) if no folded constant
+ // is found.
+ auto *RootSE = SE->getSCEV(Root);
+ int64_t FoldConst = 0;
+ foldConstantExpression(RootSE, FoldConst);
+
+ // Substract offset constant from root expression to get the base expression,
+ // then query base expression cache to find whether it has been evaluated.
+ auto *BaseSE = SE->getMinusSCEV(RootSE,
+ SE->getConstant(RootTy, FoldConst, true));
+ Value *Base = lookupBaseExpressionCache(BaseSE);
+
+ // Create instructions to evaluate base expression if cache miss or previously
+ // computed value doesn't dominate load/store instruction.
+ if (!Base || !dominates(Base, LSI, DT)) {
+#ifdef VERBOSE
+ pout() << " Need to build base expression.\n";
+ pout() << " - Base " << *BaseSE << ".\n";
+ pout() << " - Offset " << FoldConst << ".\n";
+#endif
+ // Expand the base expression if it is safe.
+ if (isSafeToExpand(BaseSE, *SE)) {
+#if defined(LLVM_V35)
+ SCEVExpander Expander(*SE, "");
+#else
+ SCEVExpander Expander(*SE, *DL, "");
+#endif
+ Base = Expander.expandCodeFor(BaseSE, RootTy, LSI);
+ }
+ } else {
+#ifdef VERBOSE
+ pout() << " Use cached base expression value.\n";
+ pout() << " - Base " << *BaseSE << ".\n";
+ pout() << " - Offset " << FoldConst << ".\n";
+#endif
+ }
+
+ // Neither using cached value nor re-computing works, abort.
+ if (!Base)
+ return false;
+
+ // Add back folded constant (offset) to new root value and feed the result as
+ // new pointer to load/store instruction.
+ IRBuilder<> Builder(IF->getContext());
+
+ bool FoldZero = (FoldConst == 0);
+ Value *Offset = ConstantInt::get(RootTy, FoldConst);
+
+ Builder.SetInsertPoint(LSI);
+ Value *NewRoot = FoldZero ? Base : Builder.CreateAdd(Base, Offset);
+ Value *NewPtr = Builder.CreateIntToPtr(NewRoot, PtrTy);
+ LSI->replaceUsesOfWith(Ptr, NewPtr);
+
+ // Cache base expression value.
+ BaseExprVal[BaseSE] = Base;
+
+ return true;
+}
+
+void SimplifyPointer::getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<DominatorTreeWrapperPass>();
+#if defined(LLVM_V35)
+ AU.addRequired<ScalarEvolution>();
+#else
+ AU.addRequired<ScalarEvolutionWrapperPass>();
+#endif
+}
+
+bool SimplifyPointer::runOnFunction(Function &F) {
+ DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+#if defined(LLVM_V35)
+ SE = &getAnalysis<ScalarEvolution>();
+#else
+ SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+#endif
+
+ bool Changed = false;
+
+ InstrList MemoryInstrs;
+ for (auto FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
+ BasicBlock *BB = &*FI;
+
+ // Skip dead basic blocks.
+ if (!DT->isReachableFromEntry(BB))
+ continue;
+
+ // Collect all guest memory instructions.
+ for (auto BI = BB->begin(), BE = BB->end(); BI != BE; ++BI) {
+ Instruction *I = &*BI;
+ if (MDFactory::isGuestMemory(I))
+ MemoryInstrs.push_back(I);
+ }
+ }
+
+ // Try to simplify pointers of collected load/store instructions.
+ for (Instruction *I : MemoryInstrs)
+ Changed |= tryToSimplifyPointer(I);
+
+ return Changed;
+}
+
+char SimplifyPointer::ID = 0;
+INITIALIZE_PASS_BEGIN(SimplifyPointer, "simplifypointer",
+ "Reassiciate pointer arithmetic", false, false)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
+#if defined(LLVM_V35)
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolution)
+#else
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
+#endif
+INITIALIZE_PASS_END(SimplifyPointer, "simplifypointer",
+ "Reassiciate pointer arithmetic", false, false)
+
+FunctionPass *llvm::createSimplifyPointer(IRFactory *IF) {
+ return new SimplifyPointer(IF);
+}
+
+/*
+ * vim: ts=2 sts=2 sw=2 expandtab
+ */
diff --git a/src/llvm/pass/StateMappingPass.cpp b/src/llvm/pass/StateMappingPass.cpp
new file mode 100644
index 0000000..0d9dd9b
--- /dev/null
+++ b/src/llvm/pass/StateMappingPass.cpp
@@ -0,0 +1,885 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "llvm-debug.h"
+#include "llvm-opc.h"
+#include "llvm-target.h"
+#include "llvm-pass.h"
+
+#define PASS_NAME "StateMapping"
+
+
+/*
+ * StateMappingPass is used to eliminate the redundant loads and stores to the
+ * CPUArchState. The loads and stores of the guest memory operations are not
+ * removed in order not to violate the memory model of the guest architecture.
+ *
+ * The state mapping rules are:
+ * - A guest state is not overlapped: (i.e., same access size)
+ * - Same type: map to this type.
+ * - Different type: select type in the order: vector, float and integer;
+ * use bitcast to convert between different types.
+ * - A guest state is overlapped with other state(s):
+ * - Query StateType to find state size (i.e., boundary) and type:
+ * - Vector type: use insert/extract to manipulate a vector element.
+ * - Other types: use shift to manipulate a vector element.
+ */
+class StateMappingPass : public FunctionPass {
+ IRFactory *IF; /* Uplink to the IRFactory */
+
+public:
+ static char ID;
+ explicit StateMappingPass() : FunctionPass(ID) {}
+ explicit StateMappingPass(IRFactory *IF) : FunctionPass(ID), IF(IF) {}
+
+ bool runOnFunction(Function &F);
+};
+
+struct StateMapping {
+ StateMapping()
+ : State(nullptr), Addr(nullptr), Ty(nullptr), AI(nullptr),
+ hasLoad(false), hasStore(false) {}
+
+ StateData *State;
+ Value *Addr;
+ Type *Ty;
+ AllocaInst *AI;
+ bool hasLoad;
+ bool hasStore;
+
+ intptr_t getSize() { return State->End - State->Start; }
+ intptr_t getStart() { return State->Start; }
+ intptr_t getEnd() { return State->End; }
+ Value *getAddr() { return Addr; }
+ Type *getType() { return Ty; }
+ bool isVector() { return Ty->isVectorTy(); }
+
+ bool overlap(StateRange &Range) {
+ if (Range.empty())
+ return false;
+ intptr_t Start = getStart();
+ intptr_t End = getEnd();
+ auto I = --Range.upper_bound(Start);
+ for (; I != Range.end() && I->first < End; ++I) {
+ if (I->second > Start)
+ return true;
+ }
+ return false;
+ }
+};
+
+struct ElementInfo {
+ ElementInfo() : Shift(0), NumElts(0), EltTy(nullptr), StateTy(nullptr) {}
+
+ intptr_t Shift;
+ unsigned NumElts;
+ Type *EltTy;
+ Type *StateTy;
+};
+
+class StateMapper {
+ typedef std::vector<StateMapping> StateMapList;
+
+ IRFactory *IF;
+ const DataLayout *DL;
+ Instruction *CPU; /* The CPU pointer */
+ Instruction *PreCastPos; /* The position to cast CPU states */
+ Instruction *PreLoadPos; /* The position to preload CPU states */
+ IVec toErase; /* The instructions to be removed */
+
+ FlatType &StateType;
+ StateAnalyzer Analyzer;
+ StateMapList StateMaps;
+
+public:
+ StateMapper(IRFactory *IF)
+ : IF(IF), DL(IF->getDL()), StateType(IF->getTranslator().getStateType()),
+ Analyzer(DL) {}
+
+ bool run(Function &F) {
+ if (!init(F))
+ return false;
+
+ AnalyzeState(F);
+ if (!StateMaps.empty())
+ PromoteState(F);
+
+ ProcessErase(toErase);
+ return true;
+ }
+
+ /* Rearrange instructions in the 'init' block. */
+ bool init(Function &F);
+
+ /* Analyze instructions in a Function that access CPU states. */
+ void AnalyzeState(Function &F);
+
+ /* Compute state mapping information. */
+ void ComputeStateMap(StateMapping &StateMap, StateData &State);
+
+ /* Determine if the state can be operated as a vector. */
+ Type *TryVectorState(StateData &State, Type *Ty);
+
+ /* Map state references to the virtual states. */
+ void PromoteState(Function &F);
+
+ /* Rewrite state loads and stores. */
+ void RewriteLoad(StateMapping &StateMap, StateRef &Ref);
+ void RewriteStore(StateMapping &StateMap, StateRef &Ref);
+ void RewriteLoadVector(StateMapping &StateMap, StateRef &Ref);
+ void RewriteStoreVector(StateMapping &StateMap, StateRef &Ref);
+
+ /* Compute state and element types for element insertion and extraction. */
+ void getElementInfo(StateMapping &StateMap, StateRef &Ref, ElementInfo &Info);
+
+ /* Sync CPU states around helper calls. */
+ void SyncHelperState();
+
+ /* Store dirty states at the leaf blocks. */
+ void ProcessExitBB(BasicBlock *BB);
+
+ /* Get the pointer without GEP and BitCast. */
+ void StripPointer(Value *V, IVec &IV);
+
+ /* Move the pointer before InsertPos. */
+ void MoveStatePointer(Value *V);
+
+ /* Load state from Src and store it to Dest. */
+ void CopyState(Value *Dest, Value *Src, Instruction *InsertPos);
+
+ bool isLegalState(Value *Ptr, intptr_t &Off);
+
+ /* Return true if the input is alias of a state pointer. */
+ bool isStatePointer(Value *V) {
+ if (auto BCI = dyn_cast<BitCastInst>(V)) {
+ if (BCI->getOperand(0) == CPU)
+ return true;
+ return isStatePointer(BCI->getOperand(0));
+ } else if (auto GEP = dyn_cast<GetElementPtrInst>(V))
+ return GEP->getOperand(0) == CPU;
+ return false;
+ }
+
+ bool isSimpleFunction(Function *F) {
+ HelperMap &Helpers = IF->getHelpers();
+ if (Helpers.find(F->getName()) == Helpers.end() ||
+ Helpers[F->getName()]->hasNestedCall)
+ return false;
+ return true;
+ }
+
+ Value *ConvertType(Value *V, Type *Ty, Instruction *InsertPos) {
+ return V->getType() == Ty ? V : new BitCastInst(V, Ty, "", InsertPos);
+ }
+};
+
+/* Return a pre-defined state name. */
+static std::string getStateName(intptr_t Off)
+{
+#if defined(TARGET_I386)
+ if (Off == offsetof(CPUArchState,xmm_regs[0])) return "xmm0";
+ if (Off == offsetof(CPUArchState,xmm_regs[1])) return "xmm1";
+ if (Off == offsetof(CPUArchState,xmm_regs[2])) return "xmm2";
+ if (Off == offsetof(CPUArchState,xmm_regs[3])) return "xmm3";
+ if (Off == offsetof(CPUArchState,xmm_regs[4])) return "xmm4";
+ if (Off == offsetof(CPUArchState,xmm_regs[5])) return "xmm5";
+ if (Off == offsetof(CPUArchState,xmm_regs[6])) return "xmm6";
+ if (Off == offsetof(CPUArchState,xmm_regs[7])) return "xmm7";
+ if (Off == offsetof(CPUArchState,xmm_t0)) return "xmm_t0";
+#endif
+ return "";
+}
+
+/* Determine if the offset is to access the temporary state. */
+static inline bool isLocalState(intptr_t Off)
+{
+#if defined(TARGET_I386)
+ if (Off == offsetof(CPUArchState, xmm_t0))
+ return true;
+#endif
+ return false;
+}
+
+/* Return states that should be ignored during state mapping. */
+static bool isSkipState(intptr_t Off)
+{
+ if (Off == (intptr_t)(offsetof(CPUState, tcg_exit_req) - ENV_OFFSET))
+ return true;
+
+#define stateof(X) \
+ (Off >= (intptr_t)offsetof(CPUArchState,X) && \
+ Off < (intptr_t)(offsetof(CPUArchState,X) + sizeof(((CPUArchState*)0)->X)))
+#define is_fpstatus(X) \
+ (stateof(X.float_detect_tininess) || \
+ stateof(X.float_rounding_mode) || \
+ stateof(X.float_exception_flags) || \
+ stateof(X.floatx80_rounding_precision) || \
+ stateof(X.flush_to_zero) || \
+ stateof(X.flush_inputs_to_zero) || \
+ stateof(X.default_nan_mode))
+
+#if defined(TARGET_ARM)
+ if (is_fpstatus(vfp.fp_status) || is_fpstatus(vfp.standard_fp_status))
+ return true;
+#elif defined(TARGET_I386)
+ if (is_fpstatus(fp_status))
+ return true;
+#endif
+ return false;
+
+#undef stateof
+#undef is_fpstatus
+}
+
+/* Check if the state is legal for state mapping. A legal state must have CPU
+ * as the base pointer, plus a positive constant offset. */
+bool StateMapper::isLegalState(Value *Ptr, intptr_t &Off)
+{
+ Value *Base = getBaseWithConstantOffset(DL, Ptr, Off);
+ if (Off < 0)
+ return false;
+ if (Base == CPU && !isSkipState(Off) && !IRFactory::isStateOfPC(Off))
+ return true;
+ return false;
+}
+
+/* Get the pointer without GEP and BitCast. The stripped GEP and BitCast
+ * instructions are returned to the caller. */
+void StateMapper::StripPointer(Value *V, IVec &IV)
+{
+ std::set<Value *> Visited;
+ Visited.insert(V);
+ do {
+ if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
+ IV.push_back(GEP);
+ V = GEP->getOperand(0);
+ } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(V)) {
+ IV.push_back(BCI);
+ V = BCI->getOperand(0);
+ } else
+ return;
+ if (Visited.find(V) != Visited.end())
+ break;
+ Visited.insert(V);
+ } while (true);
+}
+
+/* Move the pointer before InsertPos. */
+void StateMapper::MoveStatePointer(Value *V)
+{
+ IVec toMove;
+ StripPointer(V, toMove);
+ while (!toMove.empty()) {
+ Instruction *I = toMove.back();
+ toMove.pop_back();
+ if (I->getParent() == CPU->getParent())
+ continue;
+ I->moveBefore(PreCastPos);
+ }
+}
+
+/* Copy state data from src address to destination address. */
+void StateMapper::CopyState(Value *Dest, Value *Src, Instruction *InsertPos)
+{
+ if (!isa<AllocaInst>(Src)) {
+ MoveStatePointer(Src);
+ LoadInst *LI = new LoadInst(Src, "", false, InsertPos);
+ new StoreInst(LI, Dest, false, InsertPos);
+
+ if (Src->getType()->getPointerElementType()->isVectorTy())
+ LI->setAlignment(4);
+ } else {
+ MoveStatePointer(Dest);
+ LoadInst *LI = new LoadInst(Src, "", false, InsertPos);
+ StoreInst *SI = new StoreInst(LI, Dest, false, InsertPos);
+
+ if (Dest->getType()->getPointerElementType()->isVectorTy())
+ SI->setAlignment(4);
+ }
+}
+
+/* Store dirty states at the leaf blocks. */
+void StateMapper::ProcessExitBB(BasicBlock *BB)
+{
+ Instruction *InsertPos = nullptr;
+ for (auto BI = BB->begin(), BE = BB->end(); BI != BE; ++BI) {
+ if (MDFactory::isExit(&*BI)) {
+ InsertPos = &*BI;
+ break;
+ }
+ }
+ if (!InsertPos)
+ InsertPos = BB->getTerminator();
+
+ for (auto &StateMap : StateMaps) {
+ if (!StateMap.hasStore || isLocalState(StateMap.getStart()))
+ continue;
+ CopyState(StateMap.Addr, StateMap.AI, InsertPos);
+ }
+}
+
+/* Sync CPU states around helper calls. */
+void StateMapper::SyncHelperState()
+{
+ CallList &Calls = Analyzer.getCalls();
+ if (Calls.empty())
+ return;
+
+ /*
+ * Rules of syncing states around calls:
+ * 1. Dirty states (i.e., stores) are written back before calls.
+ * 2. All states, including loads and stores, are read back after calls.
+ *
+ * If the helper is a simple function, only dependent states are synced.
+ * If the helper is a complicated function, all states are synced.
+ */
+ HelperMap &Helpers = IF->getHelpers();
+ DenseMap<CallInst*, std::set<unsigned> > StoreBeforeCall;
+ DenseMap<CallInst*, std::set<unsigned> > LoadAfterCall;
+
+ for (auto CI : Calls) {
+ Function *Func = CI->getCalledFunction();
+ std::string Name = Func->getName();
+
+ if (isSimpleFunction(Func)) {
+ /* A pre-defined helper without nested call. */
+ HelperInfo *Helper = Helpers[Name];
+ for (unsigned i = 0, e = StateMaps.size(); i != e; ++i) {
+ auto &StateMap = StateMaps[i];
+ if (StateMap.hasStore && StateMap.overlap(Helper->StateUse))
+ StoreBeforeCall[CI].insert(i);
+
+ if (StateMap.overlap(Helper->StateDef))
+ LoadAfterCall[CI].insert(i);
+
+ if (Helper->mayConflictArg) {
+ unsigned NumArgs = CI->getNumArgOperands();
+ for (unsigned j = 1; j < NumArgs; ++j) {
+ intptr_t Off = 0;
+ Value *Arg = CI->getArgOperand(j);
+ if (!isLegalState(Arg, Off))
+ continue;
+ if (Off + Helper->ConflictSize <= StateMap.getStart() ||
+ Off >= StateMap.getEnd())
+ continue;
+ if (StateMap.hasStore)
+ StoreBeforeCall[CI].insert(i);
+ LoadAfterCall[CI].insert(i);
+ }
+ }
+ }
+ } else {
+ /* Sync states for a complicated function (an unknown helper or a
+ * helper with nested calls). */
+ for (unsigned i = 0, e = StateMaps.size(); i != e; ++i) {
+ auto &StateMap = StateMaps[i];
+ if (StateMap.hasStore)
+ StoreBeforeCall[CI].insert(i);
+ LoadAfterCall[CI].insert(i);
+ }
+ }
+ }
+
+ /* Perform state syncing. */
+ for (auto CI : Calls) {
+ Instruction *InsertPos = CI;
+
+ if (!StoreBeforeCall.empty()) {
+ for (auto i : StoreBeforeCall[CI]) {
+ auto &StateMap = StateMaps[i];
+ CopyState(StateMap.Addr, StateMap.AI, InsertPos);
+ }
+ }
+
+ InsertPos = &*std::next(BasicBlock::iterator(InsertPos));
+ if (isa<UnreachableInst>(InsertPos)) {
+ /* No read back is required after tail call. */
+ continue;
+ }
+
+ if (!LoadAfterCall.empty()) {
+ for (auto i : LoadAfterCall[CI]) {
+ auto &StateMap = StateMaps[i];
+ CopyState(StateMap.AI, StateMap.Addr, InsertPos);
+ }
+ }
+ }
+}
+
+static inline bool isSameSize(StateMapping &StateMap, StateRef &Ref)
+{
+ return StateMap.getSize() == Ref.getSize();
+}
+
+/* Compute state and element types for element insertion and extraction. */
+void StateMapper::getElementInfo(StateMapping &StateMap, StateRef &Ref,
+ ElementInfo &Info)
+{
+ intptr_t StateSize = StateMap.getSize();
+ intptr_t Size = Ref.getSize();
+ intptr_t Shift = Ref.Start - StateMap.getStart();
+ Type *StateTy = StateMap.getType();
+ LLVMContext &Context = StateTy->getContext();
+
+ if (!StateMap.isVector()) {
+ /* Use int-N to emulate the state. */
+ Info.NumElts = 1;
+ Info.EltTy = Type::getIntNTy(Context, Size * 8);
+ Info.StateTy = Type::getIntNTy(Context, StateSize * 8);
+ Info.Shift = Shift;
+ return;
+ }
+
+ /* The state is emulated as a vector. */
+ if (StateSize % Size == 0 && Shift % Size == 0) {
+ Type *EltTy = Type::getIntNTy(Context, Size * 8);
+
+ Info.NumElts = 1;
+ Info.EltTy = EltTy;
+ Info.StateTy = VectorType::get(EltTy, StateSize / Size);
+ Info.Shift = Shift / Size;
+ } else {
+ VectorType *VecTy = cast<VectorType>(StateTy);
+ Type *EltTy = VecTy->getScalarType();
+ intptr_t EltSize = DL->getTypeSizeInBits(EltTy) / 8;
+
+ Info.NumElts = Size / EltSize;
+ Info.EltTy = VectorType::get(EltTy, Info.NumElts);
+ Info.StateTy = StateTy;
+ Info.Shift = Shift / EltSize;
+ }
+}
+
+void StateMapper::RewriteLoad(StateMapping &StateMap, StateRef &Ref)
+{
+ LoadInst *LI = cast<LoadInst>(Ref.I);
+ Type *Ty = LI->getType();
+ Instruction *InsertPos = LI;
+
+ /* The same reference size as the state size. */
+ if (isSameSize(StateMap, Ref)) {
+ Value *V = new LoadInst(StateMap.AI, "", false, InsertPos);
+ V = ConvertType(V, Ty, InsertPos);
+ LI->replaceAllUsesWith(V);
+ toErase.push_back(LI);
+ return;
+ }
+
+ if (StateMap.isVector()) {
+ RewriteLoadVector(StateMap, Ref);
+ return;
+ }
+
+ /* This is a non-vector state. Transform the state to the type of Int-N
+ * and use logical shift to extract/insert element data. */
+ ElementInfo Info;
+ getElementInfo(StateMap, Ref, Info);
+
+ Value *V = new LoadInst(StateMap.AI, "", false, InsertPos);
+ V = ConvertType(V, Info.StateTy, InsertPos);
+
+ /* Extract the element. */
+ if (Info.Shift) {
+ Value *Shift = ConstantInt::get(V->getType(), Info.Shift * 8);
+ V = BinaryOperator::Create(Instruction::LShr, V, Shift, "", InsertPos);
+ }
+ V = new TruncInst(V, Info.EltTy, "", InsertPos);
+ V = ConvertType(V, Ty, InsertPos);
+
+ LI->replaceAllUsesWith(V);
+ toErase.push_back(LI);
+}
+
+void StateMapper::RewriteStore(StateMapping &StateMap, StateRef &Ref)
+{
+ StoreInst *SI = cast<StoreInst>(Ref.I);
+ Value *Data = SI->getValueOperand();
+ Instruction *InsertPos = SI;
+
+ /* The same reference size as the state size. */
+ if (isSameSize(StateMap, Ref)) {
+ Value *V = ConvertType(Data, StateMap.getType(), InsertPos);
+ new StoreInst(V, StateMap.AI, false, InsertPos);
+ toErase.push_back(SI);
+ return;
+ }
+
+ if (StateMap.isVector()) {
+ RewriteStoreVector(StateMap, Ref);
+ return;
+ }
+
+ /* This is a non-vector state. Transform the state to the type of Int-N
+ * and use logical shift to extract/insert element data. */
+ ElementInfo Info;
+ getElementInfo(StateMap, Ref, Info);
+
+ Value *V = new LoadInst(StateMap.AI, "", false, InsertPos);
+ V = ConvertType(V, Info.StateTy, InsertPos);
+
+ /* Insert the element. */
+ Data = ConvertType(Data, Info.EltTy, InsertPos);
+ Data = new ZExtInst(Data, Info.StateTy, "", InsertPos);
+
+ if (Info.Shift) {
+ Value *Shift = ConstantInt::get(Data->getType(), Info.Shift * 8);
+ Data = BinaryOperator::Create(Instruction::Shl, Data, Shift, "", InsertPos);
+ }
+
+ unsigned numBits = StateMap.getSize() * 8;
+ unsigned loBit = Info.Shift * 8, hiBit = loBit + Ref.getSize() * 8;
+ APInt mask = ~APInt::getBitsSet(numBits, loBit, hiBit);
+ Value *Mask = ConstantInt::get(Data->getContext(), mask);
+
+ V = BinaryOperator::Create(Instruction::And, V, Mask, "", InsertPos);
+ V = BinaryOperator::Create(Instruction::Or, V, Data, "", InsertPos);
+ V = ConvertType(V, StateMap.getType(), InsertPos);
+
+ new StoreInst(V, StateMap.AI, false, InsertPos);
+ toErase.push_back(SI);
+}
+
+void StateMapper::RewriteLoadVector(StateMapping &StateMap, StateRef &Ref)
+{
+ LoadInst *LI = cast<LoadInst>(Ref.I);
+ Type *Ty = LI->getType();
+ Instruction *InsertPos = LI;
+
+ /* Compute offset, size and element type of this vector operation. */
+ ElementInfo Info;
+ getElementInfo(StateMap, Ref, Info);
+
+ Value *V = new LoadInst(StateMap.AI, "", false, InsertPos);
+ V = ConvertType(V, Info.StateTy, InsertPos);
+
+ /* Extract the element(s) from the vector value. */
+ IntegerType *I32 = IntegerType::get(V->getContext(), 32);
+
+ if (Info.EltTy->isVectorTy()) {
+ /* Multiple elements to load. Use shufflevector. */
+ Value *UndefVal = UndefValue::get(Info.StateTy);
+ SmallVector<Constant*, 8> Indices;
+ for (unsigned i = 0, e = Info.Shift; i != e; ++i)
+ Indices.push_back(ConstantInt::get(I32, Info.Shift + i));
+ Value *CV = ConstantVector::get(Indices);
+ V = new ShuffleVectorInst(V, UndefVal, CV, "", InsertPos);
+ } else {
+ /* Only one element. Use extractelement. */
+ V = ExtractElementInst::Create(V,
+ ConstantInt::get(I32, Info.Shift), "", InsertPos);
+ }
+
+ V = ConvertType(V, Ty, InsertPos);
+
+ LI->replaceAllUsesWith(V);
+ toErase.push_back(LI);
+}
+
+void StateMapper::RewriteStoreVector(StateMapping &StateMap, StateRef &Ref)
+{
+ StoreInst *SI = cast<StoreInst>(Ref.I);
+ Value *Data = SI->getValueOperand();
+ Instruction *InsertPos = SI;
+
+ /* Compute offset, size and element type of this vector operation. */
+ ElementInfo Info;
+ getElementInfo(StateMap, Ref, Info);
+
+ Value *V = new LoadInst(StateMap.AI, "", false, InsertPos);
+ V = ConvertType(V, Info.StateTy, InsertPos);
+ Data = ConvertType(Data, Info.EltTy, InsertPos);
+
+ /* Extract element(s) from data and insert it into the vector value. */
+ IntegerType *I32 = IntegerType::get(V->getContext(), 32);
+
+ if (Info.EltTy->isVectorTy()) {
+ SmallVector<Value *, 8> Partial;
+ for (unsigned i = 0, e = Info.NumElts; i != e; ++i) {
+ Partial.push_back(ExtractElementInst::Create(Data,
+ ConstantInt::get(I32, i), "", InsertPos));
+ }
+ for (unsigned i = 0, e = Info.NumElts; i != e; ++i) {
+ V = InsertElementInst::Create(V, Partial[i],
+ ConstantInt::get(I32, Info.Shift + i), "", InsertPos);
+ }
+ } else {
+ /* Only one element. Use insertelement. */
+ V = InsertElementInst::Create(V, Data,
+ ConstantInt::get(I32, Info.Shift), "", InsertPos);
+ }
+
+ V = ConvertType(V, StateMap.getType(), InsertPos);
+
+ new StoreInst(V, StateMap.AI, false, InsertPos);
+ toErase.push_back(SI);
+}
+
+/* Map state references to the virtual states. */
+void StateMapper::PromoteState(Function &F)
+{
+ /* Pre-load CPU states. */
+ Type *IntPtrTy = DL->getIntPtrType(CPU->getContext());
+ for (auto &StateMap : StateMaps) {
+ if (!StateMap.Addr) {
+ Value *Off = ConstantInt::get(IntPtrTy, StateMap.getStart());
+ Value *GEP = GetElementPtrInst::CreateInBounds(CPU, Off, "",
+ PreCastPos);
+ StateMap.Addr = new BitCastInst(GEP,
+ PointerType::getUnqual(StateMap.getType()), "",
+ PreCastPos);
+ }
+
+ std::string StateName = StateMap.Addr->getName();
+ if (StateName == "")
+ StateName = getStateName(StateMap.getStart());
+ if (StateName == "")
+ StateName = "state";
+ StateName.append(".a");
+
+ StateMap.AI = CreateAlloca(StateMap.getType(), 0, StateName, PreCastPos);
+ CopyState(StateMap.AI, StateMap.Addr, PreLoadPos);
+ }
+
+ /* Rewrite loads and stores. */
+ for (auto &StateMap : StateMaps) {
+ for (auto Ref : StateMap.State->Refs) {
+ if (isa<LoadInst>(Ref->I))
+ RewriteLoad(StateMap, *Ref);
+ else
+ RewriteStore(StateMap, *Ref);
+ }
+ }
+
+ /* Sync CPU states around helper calls. */
+ SyncHelperState();
+
+ /* Post-store dirty values back to CPU states for each exiting block. */
+ for (auto BI = F.begin(), BE = F.end(); BI != BE; ++BI) {
+ BasicBlock *BB = &*BI;
+ if (distance(succ_begin(BB), succ_end(BB)) == 0) /* leaf node */
+ ProcessExitBB(BB);
+ }
+}
+
+/* Determine if the state can be operated as a vector. */
+Type *StateMapper::TryVectorState(StateData &State, Type *Ty)
+{
+ intptr_t StateStart = State.Start;
+ intptr_t StateEnd = State.End;
+ intptr_t StateSize = StateEnd - StateStart;
+
+ /* If the reference type (from the IR) is already a vector type, use it.
+ * Otherwise, query StateType to determine if it is a vector state. */
+ VectorType *VecTy = dyn_cast<VectorType>(Ty);
+ if (!VecTy) {
+ auto TI = --StateType.upper_bound(StateStart);
+ for (; TI != StateType.end() && TI->first < StateEnd; ++TI) {
+ if (TI->second->isVectorTy()) {
+ VecTy = cast<VectorType>(TI->second);
+ break;
+ }
+ }
+ }
+
+ if (!VecTy)
+ return nullptr;
+
+ /* This is a vector state. Now, we need to check whether all state refs can
+ * be composed by the vector element type: (a) the state size is a multiple
+ * of the vector element size, and (b) the size and shift of each state ref
+ * are both a multiple of the vector element size. */
+ Type *ElementTy = VecTy->getScalarType();
+ intptr_t ElementSize = DL->getTypeSizeInBits(ElementTy) / 8;
+ if (StateSize % ElementSize != 0)
+ return nullptr;
+
+ for (auto Ref : State.Refs) {
+ if (Ref->getSize() % ElementSize != 0 ||
+ (Ref->Start - StateStart) % ElementSize != 0)
+ return nullptr;
+ }
+ return VectorType::get(ElementTy, StateSize / ElementSize);
+}
+
+/* Compute state mapping information based on the state mapping rules. */
+void StateMapper::ComputeStateMap(StateMapping &StateMap, StateData &State)
+{
+ /* State mapping rule:
+ * - A guest state is not overlapped: (i.e., same access size)
+ * - Same type: map to this type.
+ * - Different type: select type in the order: vector, float and integer;
+ * use bitcast to convert between different types.
+ * - A guest state is overlapped with other state(s):
+ * - Query StateType to find state size (i.e., boundary) and type:
+ * - Vector type: use insert/extract to manipulate a vector element.
+ * - Other types: use shift to manipulate a sub-register element. */
+ bool sameSize = true;
+ bool hasLoad = false;
+ bool hasStore = false;
+
+ for (auto Ref : State.Refs) {
+ hasLoad |= isa<LoadInst>(Ref->I);
+ hasStore |= isa<StoreInst>(Ref->I);
+ }
+
+ StateRef *Ref = State.Refs.front();
+ Type *Ty = Ref->getType();
+ Value *Addr = getPointerOperand(Ref->I);
+ intptr_t Size = Ref->getSize();
+
+ for (unsigned i = 1, e = State.Refs.size(); i != e; ++i) {
+ StateRef *NextRef = State.Refs[i];
+ Type *NextTy = NextRef->getType();
+ Value *NextAddr = getPointerOperand(NextRef->I);
+
+ /* Check type. */
+ if (Ty != NextTy) {
+ /* Select type in the order: vector, float and integer. */
+ bool Swap = false;
+ if (Ty->isVectorTy() && NextTy->isVectorTy()) {
+ /* We prefer a vector type of small element type. */
+ Type *ATy = cast<VectorType>(Ty)->getScalarType();
+ Type *BTy = cast<VectorType>(NextTy)->getScalarType();
+ if (DL->getTypeSizeInBits(BTy) < DL->getTypeSizeInBits(ATy))
+ Swap = true;
+ } else if (!Ty->isVectorTy() && NextTy->isVectorTy()) {
+ Swap = true;
+ } else if (Ty->isIntegerTy() && NextTy->isFloatTy()) {
+ Swap = true;
+ }
+
+ if (Swap) {
+ std::swap(Ty, NextTy);
+ std::swap(Addr, NextAddr);
+ }
+ }
+
+ /* Check size. */
+ if (Size != NextRef->getSize())
+ sameSize = false;
+ }
+
+ if (sameSize) {
+ /* The same reference size as the state size. */
+ StateMap.Ty = Ty;
+ StateMap.Addr = Addr;
+ } else {
+ /* Different reference sizes. */
+ intptr_t StateSize = State.End - State.Start;
+ Type *VecTy = TryVectorState(State, Ty);
+ StateMap.Ty = VecTy ? VecTy
+ : Type::getIntNTy(Ty->getContext(), StateSize * 8);
+ StateMap.Addr = nullptr;
+ }
+ StateMap.State = &State;
+ StateMap.hasLoad = hasLoad;
+ StateMap.hasStore = hasStore;
+}
+
+/* Analyze instructions in a Function that access CPU states. */
+void StateMapper::AnalyzeState(Function &F)
+{
+ /* Collect instructions (load/store/call) that access CPU states.
+ * Loads/stores that access guest memory or are tagged with volatile
+ * (e.g., accessing the states: %pc and %tcg_exit_req) are ignored. */
+
+ for (auto II = inst_begin(F), EE = inst_end(F); II != EE; ++II) {
+ Instruction *I = &*II;
+ intptr_t Off = 0;
+ if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
+ if (MDFactory::isGuestMemory(I) || LI->isVolatile())
+ continue;
+
+ if (isLegalState(LI->getPointerOperand(), Off))
+ Analyzer.addStateRef(I, Off);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
+ if (MDFactory::isGuestMemory(I) || SI->isVolatile())
+ continue;
+
+ if (isLegalState(SI->getPointerOperand(), Off))
+ Analyzer.addStateRef(I, Off);
+ } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
+ /* Skip const helper, inlineasm and intrinsic function call. */
+ if (MDFactory::isConst(CI))
+ continue;
+ if (CI->isInlineAsm() || isa<IntrinsicInst>(CI))
+ continue;
+
+ Analyzer.addCall(CI);
+ }
+ }
+
+ /* Ask Analyzer to put state references into groups. */
+ Analyzer.computeState();
+
+ StateList &States = Analyzer.getStateList();
+ if (States.empty())
+ return;
+
+ /* Compute state mapping info. */
+ StateMaps.resize(States.size());
+ for (unsigned i = 0, e = States.size(); i != e; ++i)
+ ComputeStateMap(StateMaps[i], States[i]);
+}
+
+/* Rearrange instructions in the 'init' block. */
+bool StateMapper::init(Function &F)
+{
+ /*
+ * We would like to rearrange the instructions in the 'init' block, in which
+ * gep/cast instructions are in front of other instructions in the block.
+ * For example:
+ * %0 = getelementptr i8* %cpu, i64 0
+ * %1 = bitcast i8* %0 to i32* # gep/cast insns
+ * -------------------------------------- # precast_pos
+ * -------------------------------------- # preload_pos
+ * %2 = load i32, i32* %1 # the other insns
+ * br label %entry
+ */
+ CPU = IF->getDefaultCPU(F);
+ if (!CPU || CPU->getParent() != &F.getEntryBlock())
+ return false;
+
+ Instruction *InsertPos = &*std::next(BasicBlock::iterator(CPU));
+ PreLoadPos = new UnreachableInst(CPU->getContext(), InsertPos);
+ PreCastPos = new UnreachableInst(CPU->getContext(), PreLoadPos);
+
+ toErase.push_back(PreLoadPos);
+ toErase.push_back(PreCastPos);
+
+ /* Move gep/cast instructions. */
+ IVec toMove;
+ BasicBlock *BB = CPU->getParent();
+ for (auto BI = BB->begin(), BE = BB->end(); BI != BE; ++BI) {
+ Instruction *I = &*BI;
+ if (isStatePointer(I))
+ toMove.push_back(I);
+ }
+ for (auto I : toMove)
+ I->moveBefore(PreCastPos);
+
+ return true;
+}
+
+/*
+ * StateMappingPass
+ */
+bool StateMappingPass::runOnFunction(Function &F)
+{
+ return StateMapper(IF).run(F);
+}
+
+char StateMappingPass::ID = 0;
+INITIALIZE_PASS(StateMappingPass, "statemap",
+ "Eliminate redundant loads/stores by mapping CPU states", false, false)
+
+FunctionPass *llvm::createStateMappingPass(IRFactory *IF)
+{
+ return new StateMappingPass(IF);
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/pmu/arm/arm-events.cpp b/src/llvm/pmu/arm/arm-events.cpp
new file mode 100644
index 0000000..3da7339
--- /dev/null
+++ b/src/llvm/pmu/arm/arm-events.cpp
@@ -0,0 +1,42 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "pmu/pmu-global.h"
+
+namespace pmu {
+
+/* ARMv8 recommended implementation defined event types.
+ * (copied from linux-4.x/arch/arm64/kernel/perf_event.c) */
+#define ICACHE_MISS_CONFIG (0x01)
+#define MEM_LOADS_CONFIG (0x06)
+#define MEM_STORES_CONFIG (0x07)
+
+
+extern EventID PreEvents[PMU_EVENT_MAX]; /* Pre-defined events. */
+
+static void ARMSetupEventCode()
+{
+#define SetupEvent(_Event,_Config) \
+ PreEvents[_Event].Type = PERF_TYPE_RAW; \
+ PreEvents[_Event].Config = _Config;
+
+ SetupEvent(PMU_ICACHE_MISSES, ICACHE_MISS_CONFIG);
+ SetupEvent(PMU_MEM_LOADS, MEM_LOADS_CONFIG);
+ SetupEvent(PMU_MEM_STORES, MEM_STORES_CONFIG);
+
+#undef SetEventCode
+}
+
+int ARMInit()
+{
+ ARMSetupEventCode();
+ return PMU_OK;
+}
+
+} /* namespace pmu */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/pmu/pmu-events.cpp b/src/llvm/pmu/pmu-events.cpp
new file mode 100644
index 0000000..d3f2d08
--- /dev/null
+++ b/src/llvm/pmu/pmu-events.cpp
@@ -0,0 +1,414 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include <algorithm>
+#include <signal.h>
+#include <sys/time.h>
+#include "llvm-soft-perfmon.h"
+#include "pmu/pmu-global.h"
+#include "pmu/pmu-events.h"
+
+
+namespace {
+
+/* Mutex */
+class Mutex {
+ pthread_mutex_t M;
+public:
+ Mutex() { pthread_mutex_init(&M, nullptr); }
+ inline void acquire() { pthread_mutex_lock(&M); }
+ inline void release() { pthread_mutex_unlock(&M); }
+ inline bool trylock() { return pthread_mutex_trylock(&M) == 0; }
+};
+
+class MutexGuard {
+ Mutex &M;
+public:
+ MutexGuard(Mutex &M) : M(M) { M.acquire(); }
+ ~MutexGuard() { M.release(); }
+};
+
+}
+
+/*
+ * Performance Monitoring Unit (PMU).
+ */
+namespace pmu {
+
+static Mutex Lock;
+
+SampleList *ReadSampleData(PMUEvent *Event);
+
+/* The timer interrupt handler. */
+void DefaultHandler(int signum, siginfo_t *info, void *data)
+{
+ /* If the thread is signaled while it is currently holding the lock, we
+ * might enter deadlock if we attempt to acquire the lock. Use trylock to
+ * detect such a condition and return from this handler if we cannot
+ * successfully acquire the lock. */
+ if (Lock.trylock() == false)
+ return;
+
+ /* We have hold the lock. Iterate over all sampling events and process
+ * the sample buffer. */
+
+ auto &SampleEvents = EventMgr->SampleEvents;
+ if (SampleEvents.empty()) {
+ Lock.release();
+ return;
+ }
+
+ struct timeval Start, End, Elapse;
+ if (SP->Mode & SPM_HPM)
+ gettimeofday(&Start, nullptr);
+
+ for (auto I = SampleEvents.begin(), E = SampleEvents.end(); I != E; ++I) {
+ PMUEvent *Event = *I;
+ if (Event->Mode & MODE_SAMPLE) {
+ SampleList *Data = ReadSampleData(Event);
+ if (Data)
+ Event->SampleHandler(Event->Hndl, SampleDataPtr(Data),
+ Event->Opaque);
+ }
+ }
+
+ auto &ChangedEvents = EventMgr->ChangedEvents;
+ if (!ChangedEvents.empty()) {
+ for (auto *Event : ChangedEvents) {
+ if (Event->State == STATE_GOTO_STOP) {
+ Event->State = STATE_STOP;
+ SampleEvents.remove(Event);
+ } else if (Event->State == STATE_GOTO_START) {
+ Event->State = STATE_START;
+ SampleEvents.push_back(Event);
+ }
+ }
+ ChangedEvents.clear();
+ }
+
+ if (SP->Mode & SPM_HPM) {
+ gettimeofday(&End, nullptr);
+ timersub(&End, &Start, &Elapse);
+ SP->SampleTime += Elapse.tv_sec * 1e6 + Elapse.tv_usec;
+ }
+
+ if (!SampleEvents.empty())
+ EventMgr->EventTimer->Start();
+ Lock.release();
+}
+
+/*
+ * Event Manager
+ */
+EventManager::EventManager()
+{
+ for (unsigned i = 0; i < PMU_MAX_EVENTS; ++i) {
+ Events[i].Hndl = i;
+ FreeEvents.push_back(&Events[i]);
+ }
+
+ /* Install the signal handler for the timer. */
+ struct sigaction act;
+ memset(&act, 0, sizeof(struct sigaction));
+ act.sa_sigaction = DefaultHandler;
+ act.sa_flags = SA_SIGINFO;
+ sigaction(PMU_SIGNAL_NUM, &act, 0);
+
+ EventTimer = new Timer(PMU_SIGNAL_NUM, SysConfig.SignalReceiver);
+}
+
+EventManager::~EventManager()
+{
+ EventTimer->Stop();
+ delete EventTimer;
+}
+
+/* Return the event of the input handle. */
+PMUEvent *EventManager::GetEvent(Handle Hndl)
+{
+ if (Hndl >= PMU_MAX_EVENTS)
+ return nullptr;
+ return &Events[Hndl];
+}
+
+/* Add a counting event and return its handle. */
+Handle EventManager::AddEvent(int fd)
+{
+ MutexGuard Locked(Lock);
+
+ if (FreeEvents.empty())
+ return PMU_INVALID_HNDL;
+
+ auto Event = FreeEvents.front();
+ FreeEvents.pop_front();
+
+ Event->FD.push_back(fd);
+ Event->Data.Base = nullptr;
+ Event->Aux.Base = nullptr;
+ Event->OverflowHandler = nullptr;
+
+ Event->Mode = MODE_COUNTER;
+ Event->State = STATE_STOP;
+
+ return Event->Hndl;
+}
+
+/* Add a sampling event and return its handle. */
+Handle EventManager::AddSampleEvent(unsigned NumFDs, int *FD, uint64_t DataSize,
+ void *Data, uint32_t Mode,
+ SampleConfig &Config)
+{
+ MutexGuard Locked(Lock);
+
+ if (FreeEvents.empty())
+ return PMU_INVALID_HNDL;
+
+ auto Event = FreeEvents.front();
+ FreeEvents.pop_front();
+
+ for (unsigned i = 0; i < NumFDs; ++i)
+ Event->FD.push_back(FD[i]);
+
+ Event->Data.Base = Data;
+ Event->Data.Size = DataSize;
+ Event->Data.Prev = 0;
+ Event->Aux.Base = nullptr;
+ Event->Aux.Size = 0;
+ Event->Aux.Prev = 0;
+ Event->Watermark = std::min(Config.Watermark, DataSize);
+ Event->SampleHandler = Config.SampleHandler;
+ Event->Opaque = Config.Opaque;
+
+ Event->Mode = MODE_SAMPLE | Mode;
+ Event->State = STATE_STOP;
+
+ return Event->Hndl;
+}
+
+/* Notify that an event is started. */
+void EventManager::StartEvent(PMUEvent *Event, bool ShouldLock)
+{
+ if (ShouldLock) {
+ MutexGuard Locked(Lock);
+
+ /* We don't add this event to the sampling event list if user doesn't
+ * provide a valid overflow handler for a sampling event. */
+ if (Event->State == STATE_STOP && Event->OverflowHandler) {
+ SampleEvents.push_back(Event);
+ EventTimer->Start();
+ }
+ Event->State = STATE_START;
+ } else {
+ /* We are within the overflow handling and it's not safe to change the
+ * structure of the sampling event list. Here we only change the state
+ * of the event and the event list will be fixed at the end of the
+ * overflow handling. */
+ if (Event->State == STATE_STOP && Event->OverflowHandler) {
+ Event->State = STATE_GOTO_START;
+ ChangedEvents.push_back(Event);
+ }
+ }
+}
+
+/* Notify that an event is stopped. */
+void EventManager::StopEvent(PMUEvent *Event, bool ShouldLock)
+{
+ if (ShouldLock) {
+ /* If this is a sampling event and is currently under sampling, remove
+ * it from the sampling event list. */
+ Lock.acquire();
+ if (Event->State == STATE_START && Event->OverflowHandler) {
+ SampleEvents.remove(Event);
+ if (SampleEvents.empty())
+ EventTimer->Stop();
+ }
+ Event->State = STATE_STOP;
+ Lock.release();
+ } else {
+ /* We are within the overflow handling and it's not safe to change the
+ * structure of the sampling event list. Here we only change the state
+ * of the event and the event list will be fixed at the end of the
+ * overflow handling. */
+ if (Event->State == STATE_START && Event->OverflowHandler) {
+ Event->State = STATE_GOTO_STOP;
+ ChangedEvents.push_back(Event);
+ }
+ }
+}
+
+/* Notify that an event is deleted. */
+void EventManager::DeleteEvent(PMUEvent *Event)
+{
+ MutexGuard Locked(Lock);
+
+ Event->FD.clear();
+ FreeEvents.push_back(Event);
+}
+
+/* Stop the event manager. */
+void EventManager::Pause()
+{
+ MutexGuard Locked(Lock);
+ if (!SampleEvents.empty())
+ EventTimer->Stop();
+}
+
+/* Restart the event manager. */
+void EventManager::Resume()
+{
+ MutexGuard Locked(Lock);
+ if (!SampleEvents.empty())
+ EventTimer->Start();
+}
+
+/*
+ * Buffer processing
+ */
+static uint8_t *CopyData(uint8_t *Data, uint64_t DataSize, uint64_t Head, uint64_t Tail) {
+ uint64_t Mask = DataSize - 1;
+ uint64_t Size = Head - Tail;
+ uint64_t HeadOff = Head & Mask;
+ uint64_t TailOff = Tail & Mask;
+ uint8_t *Buf = new uint8_t[Size];
+
+ if (HeadOff > TailOff) {
+ memcpy(Buf, Data + TailOff, Size);
+ } else {
+ uint64_t UpperSize = DataSize - TailOff;
+ memcpy(Buf, Data + TailOff, UpperSize);
+ memcpy(&Buf[UpperSize], Data, HeadOff);
+ }
+ return Buf;
+}
+
+/* Process and decode the sample buffer. */
+SampleList *ReadSampleData(PMUEvent *Event)
+{
+ uint64_t Head = perf_read_data_head(Event->Data.Base);
+ uint64_t Old = Event->Data.Prev;
+ uint64_t Size = Head - Old;
+ uint8_t *Data = (uint8_t *)Event->Data.Base + SysConfig.PageSize;
+ uint64_t DataSize = Event->Data.Size - SysConfig.PageSize;
+ SampleList *OutData = nullptr;
+
+ if (Size < Event->Watermark)
+ return OutData;
+
+ OutData = new SampleList;
+ if (Size == 0)
+ return OutData;
+
+ /* Overwrite head if we failed to keep up with the mmap data. */
+ if (Size > DataSize) {
+ Event->Data.Prev = Head;
+ perf_write_data_tail(Event->Data.Base, Head);
+ return OutData;
+ }
+
+ /* Process the buffer. */
+ uint8_t *Buf = CopyData(Data, DataSize, Head, Old);
+ uint8_t *Orig = Buf, *BufEnd = Buf + Size;
+ bool SampleIP = Event->Mode & MODE_SAMPLE_IP;
+ bool ReadFormat = Event->Mode & MODE_SAMPLE_READ;
+ bool ReadGroup = Event->FD.size() > 1;
+
+ while (1) {
+ /* Check if we have enough size for the event header. */
+ if (Buf + sizeof(struct perf_event_header) > BufEnd)
+ break;
+
+ auto *Header = (struct perf_event_header *)Buf;
+ Buf += sizeof(struct perf_event_header);
+
+ /* Check if we have enough size for the sample payload. */
+ if (Buf + Header->size > BufEnd)
+ break;
+
+ if (Header->size == 0)
+ continue;
+
+ /* Skip this sample if it's not a PERF_RECORD_SAMPLE type. */
+ if (Header->type != PERF_RECORD_SAMPLE) {
+ Buf += Header->size;
+ continue;
+ }
+
+ if (SampleIP) { /* if PERF_SAMPLE_IP */
+ uint64_t ip = *(uint64_t *)Buf;
+ Buf += 8;
+ OutData->push_back(ip);
+ }
+ if (ReadFormat) { /* if PERF_SAMPLE_READ */
+ if (ReadGroup) {
+ uint64_t nr = *(uint64_t *)Buf;
+ Buf += 8;
+ while (nr--) {
+ uint64_t value = *(uint64_t *)Buf;
+ Buf += 8;
+ OutData->push_back(value);
+ }
+ } else {
+ uint64_t value = *(uint64_t *)Buf;
+ Buf += 8;
+ OutData->push_back(value);
+ }
+ }
+ }
+
+ delete [] Orig;
+
+ /* We have finished the buffer. Update data tail. */
+ Event->Data.Prev = Head;
+ perf_write_data_tail(Event->Data.Base, Head);
+
+ return OutData;
+}
+
+/*
+ * Timer
+ */
+Timer::Timer(int Signum, int TID)
+{
+ struct sigevent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.sigev_value.sival_int = 0;
+ ev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
+ ev.sigev_signo = Signum;
+ ev._sigev_un._tid = TID;
+ timer_create(CLOCK_REALTIME, &ev, &T);
+}
+
+Timer::~Timer()
+{
+ Stop();
+ timer_delete(T);
+}
+
+/* Fire a timer which expires just once. */
+void Timer::Start()
+{
+ struct itimerspec Timeout;
+ Timeout.it_interval.tv_sec = 0;
+ Timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
+ Timeout.it_value.tv_sec = 0;
+ Timeout.it_value.tv_nsec = SysConfig.Timeout;
+ timer_settime(T, 0 /* RELATIVE */, &Timeout, NULL);
+}
+
+void Timer::Stop()
+{
+ struct itimerspec Timeout;
+ Timeout.it_interval.tv_sec = 0;
+ Timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
+ Timeout.it_value.tv_sec = 0;
+ Timeout.it_value.tv_nsec = 0;
+ timer_settime(T, 0 /* RELATIVE */, &Timeout, NULL);
+}
+
+} /* namespace pmu */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/pmu/pmu.cpp b/src/llvm/pmu/pmu.cpp
new file mode 100644
index 0000000..640997f
--- /dev/null
+++ b/src/llvm/pmu/pmu.cpp
@@ -0,0 +1,491 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include "pmu/pmu-global.h"
+#include "pmu/pmu-events.h"
+
+/*
+ * Performance Monitoring Unit (PMU) tools.
+ */
+namespace pmu {
+
+static bool InitOnce;
+
+EventManager *EventMgr; /* Event manager. */
+GlobalConfig SysConfig; /* System-wide configuration. */
+EventID PreEvents[PMU_EVENT_MAX]; /* Pre-defined events. */
+
+
+/* Initialize system-wide configuration. */
+static void SetupGlobalConfig(PMUConfig &Config)
+{
+ /* Get page size. */
+ SysConfig.PageSize = getpagesize();
+
+ /* Configure timeout and signal receiver for the timer. */
+ SysConfig.SignalReceiver = Config.SignalReceiver;
+ if (SysConfig.SignalReceiver <= 0)
+ SysConfig.SignalReceiver = getpid();
+
+ SysConfig.Timeout = Config.Timeout;
+ if (SysConfig.Timeout == 0)
+ SysConfig.Timeout = PMU_TIMER_PERIOD;
+
+ SysConfig.Timeout *= 1000; /* nanosecond */
+
+ /* Determine the Linux Perf version used by this tool and the kernel.
+ * We set the last few bytes of the perf_event_attr structure and see the
+ * size field returned from the kernel. */
+
+ SysConfig.PerfVersion = 0;
+ SysConfig.OSPerfVersion = 0;
+
+ struct perf_event_attr attr;
+ perf_attr_init(&attr, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES);
+ attr.aux_watermark = 1;
+ int fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+ close(fd);
+
+#define CheckPerfVersion(_Ver) \
+ do { \
+ SysConfig.PerfVersion = _Ver; \
+ if (attr.size == PERF_ATTR_SIZE_VER##_Ver) \
+ SysConfig.OSPerfVersion = _Ver; \
+ } while(0)
+
+ CheckPerfVersion(1);
+ CheckPerfVersion(2);
+ CheckPerfVersion(3);
+ CheckPerfVersion(4);
+ CheckPerfVersion(5);
+
+#undef CheckPerfVersion
+}
+
+/* Initialize pre-defined events. */
+static void SetupDefaultEvent()
+{
+ for (unsigned i = 0; i < PMU_EVENT_MAX; ++i) {
+ PreEvents[i].Type = -1;
+ PreEvents[i].Config = -1;
+ }
+
+#define SetupEvent(_Event,_Config) \
+ PreEvents[_Event].Type = PERF_TYPE_HARDWARE; \
+ PreEvents[_Event].Config = _Config;
+
+ /* Basic events. */
+ SetupEvent(PMU_CPU_CYCLES, PERF_COUNT_HW_CPU_CYCLES);
+ SetupEvent(PMU_REF_CPU_CYCLES, PERF_COUNT_HW_REF_CPU_CYCLES);
+ SetupEvent(PMU_INSTRUCTIONS, PERF_COUNT_HW_INSTRUCTIONS);
+ SetupEvent(PMU_LLC_REFERENCES, PERF_COUNT_HW_CACHE_REFERENCES);
+ SetupEvent(PMU_LLC_MISSES, PERF_COUNT_HW_CACHE_MISSES);
+ SetupEvent(PMU_BRANCH_INSTRUCTIONS, PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
+ SetupEvent(PMU_BRANCH_MISSES, PERF_COUNT_HW_BRANCH_MISSES);
+
+#undef SetEventCode
+}
+
+/* Initialize the PMU module. */
+int PMU::Init(PMUConfig &Config)
+{
+ if (InitOnce == true)
+ return PMU_OK;
+
+ /* Set the global configuration. */
+ SetupGlobalConfig(Config);
+
+ /* Initialize pre-defined event codes. */
+ SetupDefaultEvent();
+
+ /* Allocate event manager. */
+ EventMgr = new EventManager;
+
+ /* Initialize target-specific events. */
+#if defined(__i386__) || defined(__x86_64__)
+ X86Init();
+#elif defined(__arm__) || defined (__aarch64__)
+ ARMInit();
+#elif defined(_ARCH_PPC) || defined(_ARCH_PPC64)
+ PPCInit();
+#endif
+
+ Config.PerfVersion = SysConfig.PerfVersion;
+ Config.OSPerfVersion = SysConfig.OSPerfVersion;
+
+ InitOnce = true;
+ return PMU_OK;
+}
+
+/* Finalize the PMU module. */
+int PMU::Finalize(void)
+{
+ if (InitOnce == false)
+ return PMU_OK;
+
+ delete EventMgr;
+
+ InitOnce = false;
+ return PMU_OK;
+}
+
+/* Stop the PMU module. */
+int PMU::Pause(void)
+{
+ EventMgr->Pause();
+ return PMU_OK;
+}
+
+/* Restart the PMU module. */
+int PMU::Resume(void)
+{
+ EventMgr->Resume();
+ return PMU_OK;
+}
+
+/* Start a counting/sampling/tracing event. */
+int PMU::Start(Handle Hndl)
+{
+ auto Event = EventMgr->GetEvent(Hndl);
+ if (!Event)
+ return PMU_EINVAL;
+
+ if (perf_event_start(Event->getFD()) != 0)
+ return PMU_EEVENT;
+
+ EventMgr->StartEvent(Event);
+
+ return PMU_OK;
+}
+
+/* Stop a counting/sampling/tracing event. */
+int PMU::Stop(Handle Hndl)
+{
+ auto Event = EventMgr->GetEvent(Hndl);
+ if (!Event)
+ return PMU_EINVAL;
+
+ if (perf_event_stop(Event->getFD()) != 0)
+ return PMU_EEVENT;
+
+ EventMgr->StopEvent(Event);
+
+ return PMU_OK;
+}
+
+/* Reset the hardware counter. */
+int PMU::Reset(Handle Hndl)
+{
+ auto Event = EventMgr->GetEvent(Hndl);
+ if (!Event)
+ return PMU_EINVAL;
+
+ if (perf_event_reset(Event->getFD()) != 0)
+ return PMU_EEVENT;
+ return PMU_OK;
+}
+
+/* Remove an event. */
+int PMU::Cleanup(Handle Hndl)
+{
+ auto Event = EventMgr->GetEvent(Hndl);
+ if (!Event)
+ return PMU_EINVAL;
+
+ /* Do stop the event if the user hasn't called it. */
+ if (Event->State != STATE_STOP) {
+ int EC = Stop(Hndl);
+ if (EC != PMU_OK)
+ return EC;
+ }
+
+ /* At this point, this event has been removed from the sampling list and we
+ * no longer get overflow handling (if this is a sampling event). We are
+ * now able to release all resources. */
+
+ /* Stop all events in a group. */
+ for (auto fd : Event->FD)
+ perf_event_stop(fd);
+
+ /* Release allocated buffers. */
+ if (Event->Data.Base)
+ munmap(Event->Data.Base, Event->Data.Size);
+ if (Event->Aux.Base)
+ munmap(Event->Aux.Base, Event->Aux.Size);
+
+ for (auto fd : Event->FD)
+ close(fd);
+
+ EventMgr->DeleteEvent(Event);
+ return PMU_OK;
+}
+
+/* Start/stop a sampling/tracing event without acquiring a lock.
+ * Note that these two function should only be used within the overflow
+ * handler. Since the overflow handling is already in a locked section,
+ * acquiring a lock is not required. */
+int PMU::StartUnlocked(Handle Hndl)
+{
+ auto Event = EventMgr->GetEvent(Hndl);
+ if (!Event)
+ return PMU_EINVAL;
+ if (Event->Mode & MODE_COUNTER)
+ return PMU_EINVAL;
+
+ if (perf_event_start(Event->getFD()) != 0)
+ return PMU_EEVENT;
+
+ EventMgr->StartEvent(Event, false);
+
+ return PMU_OK;
+}
+
+int PMU::StopUnlocked(Handle Hndl)
+{
+ auto Event = EventMgr->GetEvent(Hndl);
+ if (!Event)
+ return PMU_EINVAL;
+ if (Event->Mode & MODE_COUNTER)
+ return PMU_EINVAL;
+
+ if (perf_event_stop(Event->getFD()) != 0)
+ return PMU_EEVENT;
+
+ EventMgr->StopEvent(Event, false);
+
+ return PMU_OK;
+}
+
+/* Open an event using the pre-defined event code. */
+int PMU::CreateEvent(unsigned EventCode, Handle &Hndl)
+{
+ int fd;
+ struct perf_event_attr Attr;
+
+ Hndl = PMU_INVALID_HNDL;
+
+ if (EventCode >= PMU_EVENT_MAX)
+ return PMU_EINVAL;
+ if (PreEvents[EventCode].Type == -1)
+ return PMU_ENOEVENT;
+
+ perf_attr_init(&Attr, PreEvents[EventCode].Type, PreEvents[EventCode].Config);
+ fd = sys_perf_event_open(&Attr, 0, -1, -1, 0);
+ if (fd < 0)
+ return ErrorCode(errno);
+
+ Hndl = EventMgr->AddEvent(fd);
+ if (Hndl == PMU_INVALID_HNDL) {
+ close(fd);
+ return PMU_ENOMEM;
+ }
+ return PMU_OK;
+}
+
+/* Open an event using the raw event number and umask value.
+ * The raw event code is computed as (RawEvent | (Umask << 8)). */
+int PMU::CreateRawEvent(unsigned RawEvent, unsigned Umask, Handle &Hndl)
+{
+ int fd;
+ struct perf_event_attr Attr;
+
+ Hndl = PMU_INVALID_HNDL;
+
+ perf_attr_init(&Attr, PERF_TYPE_RAW, RawEvent | (Umask << 8));
+ fd = sys_perf_event_open(&Attr, 0, -1, -1, 0);
+ if (fd < 0)
+ return ErrorCode(errno);
+
+ Hndl = EventMgr->AddEvent(fd);
+ if (Hndl == PMU_INVALID_HNDL) {
+ close(fd);
+ return PMU_ENOMEM;
+ }
+ return PMU_OK;
+}
+
+/* Open a sampling event, with the 1st EventCode as the interrupt event.
+ * The sample data will be recorded in a vector of type 'uint64_t'.
+ * The following vector shows the data format of sampling with N events:
+ * { pc, val1, val2, ..., valN, # 1st sample
+ * ...
+ * pc, val1, val2, ..., valN }; # nth sample
+ *
+ * Note that ownwership of the output vector is transferred to the user.
+ * It is the user's responsibility to free the resource of the vector. */
+int PMU::CreateSampleEvent(SampleConfig &Config, Handle &Hndl)
+{
+ unsigned i, NumEvents = Config.NumEvents;
+ unsigned NumPages = Config.NumPages;
+ uint64_t Period = Config.Period;
+ int fds[PMU_GROUP_EVENTS], EC = PMU_ENOMEM;
+ uint64_t DataSize;
+ void *Data;
+
+ Hndl = PMU_INVALID_HNDL;
+
+ if (NumPages == 0)
+ NumPages = PMU_SAMPLE_PAGES;
+ if (Period < 1e3)
+ Period = PMU_SAMPLE_PERIOD;
+
+ if (NumEvents == 0 || NumEvents > PMU_GROUP_EVENTS || !isPowerOf2(NumPages))
+ return PMU_EINVAL;
+
+ /* Check event codes. */
+ for (i = 0; i < NumEvents; ++i) {
+ unsigned EventCode = Config.EventCode[i];
+ if (EventCode >= PMU_EVENT_MAX)
+ return PMU_EINVAL;
+ if (PreEvents[EventCode].Type == -1)
+ return PMU_ENOEVENT;
+ }
+
+ /* Open the events. If more than one event is requested, set read_format
+ * to PERF_FORMAT_GROUP. */
+ fds[0] = -1;
+ for (i = 0; i < NumEvents; ++i) {
+ struct perf_event_attr Attr;
+ unsigned EventCode = Config.EventCode[i];
+ perf_attr_init(&Attr, PreEvents[EventCode].Type, PreEvents[EventCode].Config);
+
+ Attr.disabled = !i;
+ if (i == 0) {
+ Attr.sample_period = Period;
+ Attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_READ;
+ Attr.read_format = (NumEvents > 1) ? PERF_FORMAT_GROUP : 0;
+ }
+
+ fds[i] = sys_perf_event_open(&Attr, 0, -1, fds[0], 0);
+ if (fds[i] < 0) {
+ EC = ErrorCode(errno);
+ goto failed;
+ }
+ }
+
+ /* Allocate buffer for the sampling data. */
+ DataSize = (1 + NumPages) * SysConfig.PageSize;
+ Data = mmap(nullptr, DataSize, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0);
+ if (Data == MAP_FAILED)
+ goto failed;
+
+ Hndl = EventMgr->AddSampleEvent(NumEvents, fds, DataSize, Data,
+ MODE_SAMPLE_IP | MODE_SAMPLE_READ, Config);
+ if (Hndl == PMU_INVALID_HNDL) {
+ munmap(Data, DataSize);
+ goto failed;
+ }
+ return PMU_OK;
+
+failed:
+ while (--i)
+ close(fds[i]);
+ return EC;
+}
+
+/* Generate an IP histogram using EventCode as the interrupt event.
+ * The IP histogram will be recorded in a vector of type 'uint64_t' with
+ * the format: { pc1, pc2, pc3, ..., pcN }.
+ * Note that ownwership of the output vector is transferred to the user.
+ * It is the user's responsibility to free the resource of the vector. */
+int PMU::CreateSampleIP(Sample1Config &Config, Handle &Hndl)
+{
+ int fd;
+ unsigned EventCode = Config.EventCode;
+ unsigned NumPages = Config.NumPages;
+ uint64_t Period = Config.Period;
+ uint64_t DataSize;
+ void *Data;
+
+ Hndl = PMU_INVALID_HNDL;
+
+ if (NumPages == 0)
+ NumPages = PMU_SAMPLE_PAGES;
+ if (Period < 1e3)
+ Period = PMU_SAMPLE_PERIOD;
+
+ if (!isPowerOf2(NumPages))
+ return PMU_EINVAL;
+
+ /* Check the events. */
+ if (EventCode >= PMU_EVENT_MAX)
+ return PMU_EINVAL;
+ if (PreEvents[EventCode].Type == -1)
+ return PMU_ENOEVENT;
+
+ struct perf_event_attr Attr;
+ perf_attr_init(&Attr, PreEvents[EventCode].Type, PreEvents[EventCode].Config);
+
+ Attr.disabled = 1;
+ Attr.sample_period = Period;
+ Attr.sample_type = PERF_SAMPLE_IP;
+
+ fd = sys_perf_event_open(&Attr, 0, -1, -1, 0);
+ if (fd < 0)
+ return ErrorCode(errno);
+
+ /* Allocate buffer for the sampling data. */
+ DataSize = (1 + NumPages) * SysConfig.PageSize;
+ Data = mmap(nullptr, DataSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (Data == MAP_FAILED)
+ goto failed;
+
+ /* Set the sampling config. */
+ SampleConfig SConfig;
+ SConfig.NumEvents = 1;
+ SConfig.EventCode[0] = Config.EventCode;
+ SConfig.NumPages = NumPages;
+ SConfig.Period = Period;
+ SConfig.Watermark = Config.Watermark;
+ SConfig.SampleHandler = Config.SampleHandler;
+ SConfig.Opaque = Config.Opaque;
+
+ Hndl = EventMgr->AddSampleEvent(1, &fd, DataSize, Data, MODE_SAMPLE_IP, SConfig);
+ if (Hndl == PMU_INVALID_HNDL) {
+ munmap(Data, DataSize);
+ goto failed;
+ }
+ return PMU_OK;
+
+failed:
+ close(fd);
+ return PMU_ENOMEM;
+}
+
+/* Read value from the hardware counter. */
+int PMU::ReadEvent(Handle Hndl, uint64_t &Value)
+{
+ auto Event = EventMgr->GetEvent(Hndl);
+ if (!Event)
+ return PMU_EINVAL;
+
+ if (read(Event->getFD(), &Value, sizeof(uint64_t)) != sizeof(uint64_t))
+ return PMU_EEVENT;
+ return PMU_OK;
+}
+
+/* Convert error code to string. */
+const char *PMU::strerror(int ErrCode)
+{
+ switch (ErrCode) {
+ case PMU_OK: return "Success";
+ case PMU_EINVAL: return "Invalid argument";
+ case PMU_ENOMEM: return "Insufficient memory";
+ case PMU_ENOEVENT: return "Pre-defined event not available";
+ case PMU_EEVENT: return "Hardware event error";
+ case PMU_EPERM: return "Permission denied";
+ case PMU_EINTER: return "Internal error";
+ case PMU_EDECODER: return "Decoder error";
+ default: return "Unknown error";
+ }
+}
+
+} /* namespace pmu */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/pmu/ppc/ppc-events.cpp b/src/llvm/pmu/ppc/ppc-events.cpp
new file mode 100644
index 0000000..249de52
--- /dev/null
+++ b/src/llvm/pmu/ppc/ppc-events.cpp
@@ -0,0 +1,37 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "pmu/pmu-global.h"
+
+namespace pmu {
+
+#define ICACHE_MISS_CONFIG (0x200fd)
+#define MEM_LOADS_CONFIG (0x100fc)
+
+extern EventID PreEvents[PMU_EVENT_MAX]; /* Pre-defined events. */
+
+static void PPCSetupEventCode()
+{
+#define SetupEvent(_Event,_Config) \
+ PreEvents[_Event].Type = PERF_TYPE_RAW; \
+ PreEvents[_Event].Config = _Config;
+
+ SetupEvent(PMU_ICACHE_MISSES, ICACHE_MISS_CONFIG);
+ SetupEvent(PMU_MEM_LOADS, MEM_LOADS_CONFIG);
+
+#undef SetEventCode
+}
+
+int PPCInit()
+{
+ PPCSetupEventCode();
+ return PMU_OK;
+}
+
+} /* namespace pmu */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/pmu/x86/x86-events.cpp b/src/llvm/pmu/x86/x86-events.cpp
new file mode 100644
index 0000000..fe25f70
--- /dev/null
+++ b/src/llvm/pmu/x86/x86-events.cpp
@@ -0,0 +1,41 @@
+/*
+ * (C) 2018 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include "pmu/pmu-global.h"
+
+namespace pmu {
+
+#define ICACHE_HIT_CONFIG (0x83 | (0x1 << 8)) /* skylake/event=0x83,umask=0x1/ */
+#define ICACHE_MISS_CONFIG (0x83 | (0x2 << 8)) /* skylake/event=0x83,umask=0x2/ */
+#define MEM_LOADS_CONFIG (0xd0 | (0x81 << 8 )) /* skylake/event=0xd0,umask=0x81/ */
+#define MEM_STORES_CONFIG (0xd0 | (0x82 << 8 )) /* skylake/event=0xd0,umask=0x82/ */
+
+extern EventID PreEvents[PMU_EVENT_MAX]; /* Pre-defined events. */
+
+static void X86SetupEventCode()
+{
+#define SetupEvent(_Event,_Config) \
+ PreEvents[_Event].Type = PERF_TYPE_RAW; \
+ PreEvents[_Event].Config = _Config;
+
+ SetupEvent(PMU_ICACHE_HITS, ICACHE_HIT_CONFIG);
+ SetupEvent(PMU_ICACHE_MISSES, ICACHE_MISS_CONFIG);
+ SetupEvent(PMU_MEM_LOADS, MEM_LOADS_CONFIG);
+ SetupEvent(PMU_MEM_STORES, MEM_STORES_CONFIG);
+
+#undef SetEventCode
+}
+
+int X86Init()
+{
+ X86SetupEventCode();
+ return PMU_OK;
+}
+
+} /* namespace pmu */
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/tracer.cpp b/src/llvm/tracer.cpp
new file mode 100644
index 0000000..9e37442
--- /dev/null
+++ b/src/llvm/tracer.cpp
@@ -0,0 +1,365 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * This file implements the trace/region formation algorithm.
+ */
+
+
+#include "utils.h"
+#include "tracer.h"
+#include "llvm-state.h"
+
+#define USE_RELAXED_NET
+
+
+unsigned ProfileThreshold = NET_PROFILE_THRESHOLD;
+unsigned PredictThreshold = NET_PREDICT_THRESHOLD;
+
+static inline void start_trace_profiling(TranslationBlock *tb)
+{
+ /* Turn on trace profiling by jumping to the next instruction. */
+ uintptr_t jmp_addr = tb_get_jmp_entry(tb);
+#if defined(TCG_TARGET_I386)
+ patch_jmp(jmp_addr, jmp_addr + 5);
+#elif defined(TCG_TARGET_ARM) || defined(TCG_TARGET_AARCH64)
+ patch_jmp(jmp_addr, jmp_addr + 4);
+#elif defined(TCG_TARGET_PPC64)
+ patch_jmp(jmp_addr, jmp_addr + 16);
+#endif
+}
+
+static inline void copy_image(CPUArchState *env, TranslationBlock *tb)
+{
+#if defined(CONFIG_LLVM) && defined(CONFIG_SOFTMMU)
+ char *p = new char[tb->size];
+ for (int i = 0, e = tb->size; i != e; ++i)
+ p[i] = cpu_ldub_code(env, tb->pc + i);
+ tb->image = (void *)p;
+#endif
+}
+
+static inline void tracer_handle_chaining(uintptr_t next_tb, TranslationBlock *tb)
+{
+#if defined(CONFIG_LLVM)
+ llvm_handle_chaining(next_tb, tb);
+#else
+ /* see if we can patch the calling TB. When the TB spans two pages, we
+ * cannot safely do a direct jump. */
+ if (next_tb != 0 && tb->page_addr[1] == (tb_page_addr_t)-1
+ && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
+ tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
+ next_tb & TB_EXIT_MASK, tb);
+ }
+#endif
+}
+
+
+#if defined(CONFIG_LLVM)
+#include "llvm.h"
+#include "llvm-soft-perfmon.h"
+#include "llvm-hard-perfmon.h"
+static inline void OptimizeBlock(CPUArchState *env, TranslationBlock *TB)
+{
+ auto Request = OptimizationInfo::CreateRequest(TB);
+ LLVMEnv::OptimizeBlock(env, std::move(Request));
+}
+static inline void OptimizeTrace(CPUArchState *env, NETTracer::TBVec &TBs,
+ int LoopHeadIdx)
+{
+ auto Request = OptimizationInfo::CreateRequest(TBs, LoopHeadIdx);
+ LLVMEnv::OptimizeTrace(env, std::move(Request));
+}
+static inline void RegisterThread(CPUArchState *env, BaseTracer *tracer)
+{
+ if (ENV_GET_CPU(env)->cpu_index < 0)
+ return;
+ HP->RegisterThread(tracer);
+}
+static inline void UnregisterThread(CPUArchState *env, BaseTracer *tracer)
+{
+ if (ENV_GET_CPU(env)->cpu_index < 0)
+ return;
+ HP->UnregisterThread(tracer);
+ SP->NumTraceExits += env->num_trace_exits;
+}
+static inline void NotifyCacheEnter(CPUArchState *env)
+{
+ if (ENV_GET_CPU(env)->cpu_index < 0)
+ return;
+ HP->NotifyCacheEnter(cpu_get_tracer(env));
+}
+static inline void NotifyCacheLeave(CPUArchState *env)
+{
+ if (ENV_GET_CPU(env)->cpu_index < 0)
+ return;
+ HP->NotifyCacheLeave(cpu_get_tracer(env));
+}
+#else
+static inline void OptimizeBlock(CPUArchState *, TranslationBlock *) {}
+static inline void OptimizeTrace(CPUArchState *, NETTracer::TBVec &, int) {}
+static inline void RegisterThread(CPUArchState *, BaseTracer *) {}
+static inline void UnregisterThread(CPUArchState *, BaseTracer *) {}
+static inline void NotifyCacheEnter(CPUArchState *) {}
+static inline void NotifyCacheLeave(CPUArchState *) {}
+#endif
+
+
+/*
+ * BaseTracer
+ */
+BaseTracer *BaseTracer::CreateTracer(CPUArchState *env)
+{
+#if defined(CONFIG_LLVM)
+ switch (LLVMEnv::TransMode) {
+ case TRANS_MODE_NONE:
+ return new BaseTracer(env);
+ case TRANS_MODE_BLOCK:
+ return new SingleBlockTracer(env);
+ case TRANS_MODE_HYBRIDS:
+ return new NETTracer(env, TRANS_MODE_HYBRIDS);
+ case TRANS_MODE_HYBRIDM:
+ return new NETTracer(env, TRANS_MODE_HYBRIDM);
+ default:
+ break;
+ }
+#endif
+ return new BaseTracer(env);
+}
+
+void BaseTracer::DeleteTracer(CPUArchState *env)
+{
+ auto Tracer = cpu_get_tracer(env);
+ if (Tracer) {
+ delete Tracer;
+ Tracer = nullptr;
+ }
+}
+
+
+/*
+ * SingleBlockTracer
+ */
+SingleBlockTracer::SingleBlockTracer(CPUArchState *env) : BaseTracer(env)
+{
+ if (tracer_mode == TRANS_MODE_NONE)
+ tracer_mode = TRANS_MODE_BLOCK;
+}
+
+void SingleBlockTracer::Record(uintptr_t next_tb, TranslationBlock *tb)
+{
+ /* Optimize the block if we see this block for the first time. */
+ if (update_tb_mode(tb, BLOCK_NONE, BLOCK_ACTIVE))
+ OptimizeBlock(Env, tb);
+ TB = tb;
+}
+
+
+/*
+ * NETTracer
+ */
+NETTracer::NETTracer(CPUArchState *env, int Mode) : BaseTracer(env)
+{
+ if (tracer_mode == TRANS_MODE_NONE)
+ tracer_mode = Mode;
+ RegisterThread(Env, this);
+}
+
+NETTracer::~NETTracer()
+{
+ UnregisterThread(Env, this);
+}
+
+void NETTracer::Reset()
+{
+ TBs.clear();
+ Env->start_trace_prediction = 0;
+}
+
+void NETTracer::Record(uintptr_t next_tb, TranslationBlock *tb)
+{
+ bool NewTB = (tb->mode == BLOCK_NONE);
+
+ /* Promote tb to the active state before any checks if it is a new tb. */
+ if (update_tb_mode(tb, BLOCK_NONE, BLOCK_ACTIVE)) {
+ tcg_save_state(Env, tb);
+ copy_image(Env, tb);
+ }
+
+ if (isTraceHead(next_tb, tb, NewTB)) {
+ if (update_tb_mode(tb, BLOCK_ACTIVE, BLOCK_TRACEHEAD))
+ start_trace_profiling(tb);
+ }
+
+ Env->fallthrough = 0;
+}
+
+/* Determine whether tb is a potential trace head. tb is a trace head if it is
+ * (1) a target of an existing trace exit,
+ * (2) a target of an indirect branch,
+ * (3) (relaxed NET) a block in a cyclic path (i.e., seen more than once), or
+ * (original NET) a target of a backward branch. */
+bool NETTracer::isTraceHead(uintptr_t next_tb, TranslationBlock *tb, bool NewTB)
+{
+ /* Rule 1: a target of an existing trace exit. */
+ if ((next_tb & TB_EXIT_MASK) == TB_EXIT_LLVM)
+ return true;
+
+ /* Rule 2: a target of an indirect branch.
+ * Here we check 'next_tb == 0', which can cover the cases other than the
+ * indirect branches (e.g., system calls and exceptions). It is fine to
+ * also start trace formation from the successors of these blocks. */
+ if (next_tb == 0 && Env->fallthrough == 0)
+ return true;
+
+#ifdef USE_RELAXED_NET
+ /* Rule 3: a block in a cyclic path (i.e., seen more than once). */
+ if (!NewTB)
+ return true;
+#else
+ /* Rule 3: a target of a backward branch. */
+ if (next_tb != 0) {
+ TranslationBlock *pred = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
+ if (tb->pc <= pred->pc)
+ return true;
+ }
+#endif
+ return false;
+}
+
+void NETTracer::Profile(TranslationBlock *tb)
+{
+ if (Atomic<uint32_t>::inc_return(&tb->exec_count) != ProfileThreshold)
+ return;
+
+#if 0
+ /* If the execution is already in the prediction mode, process the
+ * previously recorded trace. */
+ if (Env->start_trace_prediction && !TBs.empty()) {
+ OptimizeTrace(Env, TBs, -1);
+ Reset();
+ }
+#endif
+
+ /* We reach a profile threshold, stop trace profiling and start trace tail
+ * prediction. The profiling is disabled by setting the jump directly to
+ * trace prediction stub. */
+ patch_jmp(tb_get_jmp_entry(tb), tb_get_jmp_next(tb));
+ Env->start_trace_prediction = 1;
+}
+
+void NETTracer::Predict(TranslationBlock *tb)
+{
+ /* The trace prediction will terminate if a cyclic path is detected.
+ * (i.e., current tb has existed in the tracing butter either in the
+ * head or middle of the buffer.) */
+ int LoopHeadIdx = -1;
+
+#if defined(CONFIG_LLVM)
+ /* Skip this trace if the next block is an annotated loop head and
+ * is going to be included in the middle of a trace. */
+ if (!TBs.empty() && TBs[0] != tb &&
+ llvm_has_annotation(tb->pc, ANNOTATION_LOOP)) {
+ goto trace_building;
+ }
+#endif
+
+#if defined(USE_TRACETREE_ONLY)
+ /* We would like to have a straight-line or O-shape trace.
+ * (the 6-shape trace is excluded) */
+ if (!TBs.empty() && tb == TBs[0]) {
+ LoopHeadIdx = 0;
+ goto trace_building;
+ }
+#elif defined(USE_RELAXED_NET)
+ /* Find any cyclic path in recently recorded blocks. */
+ for (int i = 0, e = TBs.size(); i != e; ++i) {
+ if (tb == TBs[i]) {
+ LoopHeadIdx = i;
+ goto trace_building;
+ }
+ }
+#else
+ if (!TBs.empty()) {
+ if (tb == TBs[0]) {
+ /* Cyclic path. */
+ LoopHeadIdx = 0;
+ goto trace_building;
+ }
+ if (tb->pc <= TBs[TBs.size() - 1]->pc) {
+ /* Backward branch. */
+ goto trace_building;
+ }
+ }
+#endif
+
+ TBs.push_back(tb);
+
+ /* Stop if the maximum prediction length is reached. */
+ if (TBs.size() == PredictThreshold)
+ goto trace_building;
+
+ return;
+
+trace_building:
+ /* If the trace is a loop with a branch to the middle of the loop body,
+ * we forms two sub-traces: (1) the loop starting from the loopback to
+ * the end of the trace and (2) the original trace. */
+ /* NOTE: We want to find more traces so the original trace is included. */
+
+ if (LoopHeadIdx > 0) {
+ /* Loopback at the middle. The sub-trace (1) is optimized first. */
+ TBVec Loop(TBs.begin() + LoopHeadIdx, TBs.end());
+ update_tb_mode(Loop[0], BLOCK_ACTIVE, BLOCK_TRACEHEAD);
+ OptimizeTrace(Env, Loop, 0);
+ }
+ OptimizeTrace(Env, TBs, LoopHeadIdx);
+
+ Reset();
+}
+
+
+/* The follows implement routines of the C interfaces for QEMU. */
+extern "C" {
+
+int tracer_mode = TRANS_MODE_NONE;
+
+void tracer_reset(CPUArchState *env)
+{
+ auto Tracer = cpu_get_tracer(env);
+ Tracer->Reset();
+}
+
+/* This routine is called when QEMU is going to leave the dispatcher and enter
+ * the code cache to execute block code `tb'. Here, we determine whether tb is
+ * a potential trace head and should perform trace formation. */
+void tracer_exec_tb(CPUArchState *env, uintptr_t next_tb, TranslationBlock *tb)
+{
+ auto Tracer = cpu_get_tracer(env);
+ Tracer->Record(next_tb, tb);
+
+ tracer_handle_chaining(next_tb, tb);
+}
+
+
+/* Helper function to perform trace profiling. */
+void helper_NET_profile(CPUArchState *env, int id)
+{
+ auto &Tracer = getNETTracer(env);
+ Tracer.Profile(&tbs[id]);
+}
+
+/* Helper function to perform trace prediction. */
+void helper_NET_predict(CPUArchState *env, int id)
+{
+ auto &Tracer = getNETTracer(env);
+ Tracer.Predict(&tbs[id]);
+}
+
+} /* extern "C" */
+
+
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/src/llvm/utils.cpp b/src/llvm/utils.cpp
new file mode 100644
index 0000000..69e77af
--- /dev/null
+++ b/src/llvm/utils.cpp
@@ -0,0 +1,223 @@
+/*
+ * (C) 2016 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include "utils.h"
+
+
+/* Remove a CFG starting from Root. */
+void GraphNode::DeleteCFG(GraphNode *Root)
+{
+ NodeVec VisitStack;
+ NodeSet Visited;
+ VisitStack.push_back(Root);
+ do {
+ GraphNode *Parent = VisitStack.back();
+ VisitStack.pop_back();
+ if (Visited.find(Parent) == Visited.end()) {
+ Visited.insert(Parent);
+ for (auto Child : Parent->getChildren())
+ VisitStack.push_back(Child);
+ }
+ } while(!VisitStack.empty());
+
+ for (auto I = Visited.begin(), E = Visited.end(); I != E; ++I)
+ delete *I;
+}
+
+#ifdef LOCK_FREE
+/* Lock-free FIFO queue algorithm of Michael and Scott (MS-queue).
+ * The code is based on the paper published in PODC'96:
+ * Maged M. Michael and Michael L. Scott, "Simple, Fast, and Practical
+ * Non-Blocking and Blocking Concurrent Queue Algorithms," Proc. 15th ACM
+ * Symp. on Principles of Distributed Computing, pages 267-275, 1996.
+ */
+static inline char CAS2(volatile struct pointer_t *ptr,
+ struct pointer_t _old,
+ struct pointer_t _new)
+{
+ char flag = 0;
+
+#if defined(__i386__)
+ asm volatile("lock; cmpxchg8b %0; setz %1;"
+ : "=m" (*ptr), "=q" (flag)
+ : "d" (_old.count), "a" (_old.ptr), "c" (_new.count), "b" (_new.ptr)
+ : "memory", "cc");
+#elif defined(__x86_64__)
+ asm volatile("lock; cmpxchg16b %0; setz %1;"
+ : "=m" (*ptr), "=q" (flag)
+ : "d" (_old.count), "a" (_old.ptr), "c" (_new.count), "b" (_new.ptr)
+ : "memory", "cc");
+#elif defined(__arm__)
+ unsigned long oldval, res;
+ asm volatile("ldrex %1, [%3]\n"
+ "mov %0, #0\n"
+ "teq %1, %4\n"
+ "strexeq %0, %5, [%3]\n"
+ : "=&r" (res), "=&r" (oldval), "+Qo" (*ptr->ptr)
+ : "r" (ptr->ptr), "Ir" (_old.ptr), "r" (_new.ptr)
+ : "cc");
+ flag = !res;
+#endif
+ return flag;
+}
+
+Queue::Queue()
+{
+ node_t *dummy = new_node(nullptr);
+ Q.head.ptr = Q.tail.ptr = dummy;
+ Q.head.count = Q.tail.count = 0;
+}
+
+void Queue::enqueue(void *data)
+{
+ pointer_t tail, next, insert;
+ node_t *node = new_node(data);
+ insert.ptr = node;
+
+ for (;;) {
+ tail = Q.tail;
+ next = tail.ptr->next;
+
+ /* If Tail is consistent (addresses and versions are not changed),
+ continue to enqueue. */
+ if (CAS2(&Q.tail, tail, Q.tail)) {
+ /* If Tail is pointing to the last node, continue to enqueue.
+ Otherwise, try to advance Tail because it might be pointing
+ to the second last node. */
+ if (next.ptr == nullptr) { /* Last node */
+ /* Try to insert node at the end of the linked list.
+ if it succeeds, exit the loop. */
+ insert.count = next.count + 1;
+ if (CAS2(&(tail.ptr->next), next, insert))
+ break;
+ } else {
+ next.count = tail.count + 1;
+ CAS2(&Q.tail, tail, next);
+ }
+ }
+ }
+
+ /* Enqueue is done, try to swing Tail to the inserted node. */
+ insert.count = tail.count + 1;
+ CAS2(&Q.tail, tail, insert);
+}
+
+void *Queue::dequeue()
+{
+ pointer_t head, tail, next;
+ void *data;
+
+ for (;;) {
+ head = Q.head;
+ tail = Q.tail;
+ next = head.ptr->next;
+
+ /* If Head is consistent (addresses and versions are not changed),
+ continue to dequeue. */
+ if (CAS2(&Q.head, head, Q.head)) {
+ /* If Queue is empty, stop dequeueing. If Tail falling behind,
+ try to advance it. Otherwise, continue to dequeue. */
+ if (head.ptr == tail.ptr) {
+ if (next.ptr == nullptr) /* Queue is empty */
+ return nullptr;
+
+ /* Tail is falling behand, try to advance it. */
+ next.count = tail.count + 1;
+ CAS2(&Q.tail, tail, next);
+ } else {
+ /* We must read value before CAS, otherwise another dequeue
+ might free the next node. */
+ data = next.ptr->value;
+ next.count = head.count + 1;
+ if (CAS2(&Q.head, head, next))
+ break;
+ }
+ }
+ }
+
+ /* Dequeue succeeded. It is safe to free the dummy node.
+ Node pointed by Head becomes the new dummy node */
+ delete_node(head.ptr);
+
+ return data;
+}
+#else
+Queue::Queue(void)
+{
+ node_t *dummy = new node_t(nullptr);
+ Q.head = Q.tail = dummy;
+ pthread_mutex_init(&lock, nullptr);
+}
+
+void Queue::enqueue(void *data)
+{
+ node_t *node = new node_t(data);
+
+ pthread_mutex_lock(&lock);
+ Q.tail->next = node;
+ Q.tail = node;
+ pthread_mutex_unlock(&lock);
+}
+
+void *Queue::dequeue()
+{
+ node_t *node, *new_head;
+ void *data;
+
+ pthread_mutex_lock(&lock);
+ node = Q.head;
+ new_head = node->next;
+ if (new_head == nullptr) {
+ pthread_mutex_unlock(&lock);
+ return nullptr;
+ }
+
+ data = new_head->value;
+ Q.head = new_head;
+ pthread_mutex_unlock(&lock);
+
+ delete node;
+ return data;
+}
+#endif
+
+/* Get the thread ID. */
+pid_t gettid()
+{
+#ifdef SYS_gettid
+ return (pid_t)syscall(SYS_gettid);
+#elif defined(__NR_gettid)
+ return (pid_t)syscall(__NR_gettid);
+#else
+ return -1;
+#endif
+}
+
+
+/* Patch a direct jump from patch_addr to addr. */
+void patch_jmp(volatile uintptr_t patch_addr, volatile uintptr_t addr)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ tb_set_jmp_target1(patch_addr + 1, addr);
+#elif defined(__aarch64__)
+ tb_set_jmp_target1(patch_addr, addr);
+#elif defined(__arm__)
+ *(uintptr_t *)patch_addr = addr;
+#elif defined(_ARCH_PPC) || defined(_ARCH_PPC64)
+ tb_set_jmp_target1(patch_addr, addr);
+#endif
+}
+
+void patch_jmp(volatile uintptr_t patch_addr, volatile void *addr)
+{
+ patch_jmp(patch_addr, (uintptr_t)addr);
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
diff --git a/src/llvm/xml/tinyxml2.cpp b/src/llvm/xml/tinyxml2.cpp
new file mode 100644
index 0000000..354200c
--- /dev/null
+++ b/src/llvm/xml/tinyxml2.cpp
@@ -0,0 +1,2013 @@
+/*
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+#include "tinyxml2.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <new>
+#include <cstddef>
+
+#include <fcntl.h>
+using namespace tinyxml2;
+
+static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
+static const char LF = LINE_FEED;
+static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
+static const char CR = CARRIAGE_RETURN;
+static const char SINGLE_QUOTE = '\'';
+static const char DOUBLE_QUOTE = '\"';
+
+// Bunch of unicode info at:
+// http://www.unicode.org/faq/utf_bom.html
+// ef bb bf (Microsoft "lead bytes") - designates UTF-8
+
+static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+
+#define DELETE_NODE( node ) { \
+ if ( node ) { \
+ MemPool* pool = node->memPool; \
+ node->~XMLNode(); \
+ pool->Free( node ); \
+ } \
+}
+#define DELETE_ATTRIBUTE( attrib ) { \
+ if ( attrib ) { \
+ MemPool* pool = attrib->memPool; \
+ attrib->~XMLAttribute(); \
+ pool->Free( attrib ); \
+ } \
+}
+
+struct Entity {
+ const char* pattern;
+ int length;
+ char value;
+};
+
+static const int NUM_ENTITIES = 5;
+static const Entity entities[NUM_ENTITIES] =
+{
+ { "quot", 4, DOUBLE_QUOTE },
+ { "amp", 3, '&' },
+ { "apos", 4, SINGLE_QUOTE },
+ { "lt", 2, '<' },
+ { "gt", 2, '>' }
+};
+
+
+StrPair::~StrPair()
+{
+ Reset();
+}
+
+
+void StrPair::Reset()
+{
+ if ( flags & NEEDS_DELETE ) {
+ delete [] start;
+ }
+ flags = 0;
+ start = 0;
+ end = 0;
+}
+
+
+void StrPair::SetStr( const char* str, int flags )
+{
+ Reset();
+ size_t len = strlen( str );
+ start = new char[ len+1 ];
+ memcpy( start, str, len+1 );
+ end = start + len;
+ this->flags = flags | NEEDS_DELETE;
+}
+
+
+char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
+{
+ TIXMLASSERT( endTag && *endTag );
+
+ char* start = p; // fixme: hides a member
+ char endChar = *endTag;
+ size_t length = strlen( endTag );
+
+ // Inner loop of text parsing.
+ while ( *p ) {
+ if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
+ Set( start, p, strFlags );
+ return p + length;
+ }
+ ++p;
+ }
+ return 0;
+}
+
+
+char* StrPair::ParseName( char* p )
+{
+ char* start = p;
+
+ if ( !start || !(*start) ) {
+ return 0;
+ }
+
+ if ( !XMLUtil::IsAlpha( *p ) ) {
+ return 0;
+ }
+
+ while( *p && (
+ XMLUtil::IsAlphaNum( (unsigned char) *p )
+ || *p == '_'
+ || *p == '-'
+ || *p == '.'
+ || *p == ':' ))
+ {
+ ++p;
+ }
+
+ if ( p > start ) {
+ Set( start, p, 0 );
+ return p;
+ }
+ return 0;
+}
+
+
+
+const char* StrPair::GetStr()
+{
+ if ( flags & NEEDS_FLUSH ) {
+ *end = 0;
+ flags ^= NEEDS_FLUSH;
+
+ if ( flags ) {
+ char* p = start; // the read pointer
+ char* q = start; // the write pointer
+
+ while( p < end ) {
+ if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
+ // CR-LF pair becomes LF
+ // CR alone becomes LF
+ // LF-CR becomes LF
+ if ( *(p+1) == LF ) {
+ p += 2;
+ }
+ else {
+ ++p;
+ }
+ *q++ = LF;
+ }
+ else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
+ if ( *(p+1) == CR ) {
+ p += 2;
+ }
+ else {
+ ++p;
+ }
+ *q++ = LF;
+ }
+ else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
+ // Entities handled by tinyXML2:
+ // - special entities in the entity table [in/out]
+ // - numeric character reference [in]
+ // &#20013; or &#x4e2d;
+
+ if ( *(p+1) == '#' ) {
+ char buf[10] = { 0 };
+ int len;
+ p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
+ for( int i=0; i<len; ++i ) {
+ *q++ = buf[i];
+ }
+ TIXMLASSERT( q <= p );
+ }
+ else {
+ int i=0;
+ for(; i<NUM_ENTITIES; ++i ) {
+ if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
+ && *(p+entities[i].length+1) == ';' )
+ {
+ // Found an entity convert;
+ *q = entities[i].value;
+ ++q;
+ p += entities[i].length + 2;
+ break;
+ }
+ }
+ if ( i == NUM_ENTITIES ) {
+ // fixme: treat as error?
+ ++p;
+ ++q;
+ }
+ }
+ }
+ else {
+ *q = *p;
+ ++p;
+ ++q;
+ }
+ }
+ *q = 0;
+ }
+ flags = (flags & NEEDS_DELETE);
+ }
+ return start;
+}
+
+
+
+
+// --------- XMLUtil ----------- //
+
+const char* XMLUtil::ReadBOM( const char* p, bool* bom )
+{
+ *bom = false;
+ const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
+ // Check for BOM:
+ if ( *(pu+0) == TIXML_UTF_LEAD_0
+ && *(pu+1) == TIXML_UTF_LEAD_1
+ && *(pu+2) == TIXML_UTF_LEAD_2 )
+ {
+ *bom = true;
+ p += 3;
+ }
+ return p;
+}
+
+
+void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
+{
+ int i;
+ const unsigned long BYTE_MASK = 0xBF;
+ const unsigned long BYTE_MARK = 0x80;
+ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+ if (input < 0x80)
+ *length = 1;
+ else if ( input < 0x800 )
+ *length = 2;
+ else if ( input < 0x10000 )
+ *length = 3;
+ else if ( input < 0x200000 )
+ *length = 4;
+ else
+ { *length = 0; return; } // This code won't covert this correctly anyway.
+
+ output += *length;
+
+ for (i = *length; i > 0; --i) {
+ if (i == 1) {
+ --output;
+ *output = (char)(input | FIRST_BYTE_MARK[*length]);
+ } else {
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ }
+ }
+}
+
+
+const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
+{
+ // Presume an entity, and pull it out.
+ *length = 0;
+
+ if ( *(p+1) == '#' && *(p+2) )
+ {
+ unsigned long ucs = 0;
+ ptrdiff_t delta = 0;
+ unsigned mult = 1;
+
+ if ( *(p+2) == 'x' )
+ {
+ // Hexadecimal.
+ if ( !*(p+3) ) return 0;
+
+ const char* q = p+3;
+ q = strchr( q, ';' );
+
+ if ( !q || !*q ) return 0;
+
+ delta = q-p;
+ --q;
+
+ while ( *q != 'x' )
+ {
+ if ( *q >= '0' && *q <= '9' )
+ ucs += mult * (*q - '0');
+ else if ( *q >= 'a' && *q <= 'f' )
+ ucs += mult * (*q - 'a' + 10);
+ else if ( *q >= 'A' && *q <= 'F' )
+ ucs += mult * (*q - 'A' + 10 );
+ else
+ return 0;
+ mult *= 16;
+ --q;
+ }
+ }
+ else
+ {
+ // Decimal.
+ if ( !*(p+2) ) return 0;
+
+ const char* q = p+2;
+ q = strchr( q, ';' );
+
+ if ( !q || !*q ) return 0;
+
+ delta = q-p;
+ --q;
+
+ while ( *q != '#' )
+ {
+ if ( *q >= '0' && *q <= '9' )
+ ucs += mult * (*q - '0');
+ else
+ return 0;
+ mult *= 10;
+ --q;
+ }
+ }
+ // convert the UCS to UTF-8
+ ConvertUTF32ToUTF8( ucs, value, length );
+ return p + delta + 1;
+ }
+ return p+1;
+}
+
+
+void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
+}
+
+
+void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
+}
+
+
+void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
+}
+
+
+void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
+}
+
+
+void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
+}
+
+
+bool XMLUtil::ToInt( const char* str, int* value )
+{
+ if ( TIXML_SSCANF( str, "%d", value ) == 1 )
+ return true;
+ return false;
+}
+
+bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
+{
+ if ( TIXML_SSCANF( str, "%u", value ) == 1 )
+ return true;
+ return false;
+}
+
+bool XMLUtil::ToBool( const char* str, bool* value )
+{
+ int ival = 0;
+ if ( ToInt( str, &ival )) {
+ *value = (ival==0) ? false : true;
+ return true;
+ }
+ if ( StringEqual( str, "true" ) ) {
+ *value = true;
+ return true;
+ }
+ else if ( StringEqual( str, "false" ) ) {
+ *value = false;
+ return true;
+ }
+ return false;
+}
+
+
+bool XMLUtil::ToFloat( const char* str, float* value )
+{
+ if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+bool XMLUtil::ToDouble( const char* str, double* value )
+{
+ if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+
+char* XMLDocument::Identify( char* p, XMLNode** node )
+{
+ XMLNode* returnNode = 0;
+ char* start = p;
+ p = XMLUtil::SkipWhiteSpace( p );
+ if( !p || !*p )
+ {
+ return p;
+ }
+
+ // What is this thing?
+ // - Elements start with a letter or underscore, but xml is reserved.
+ // - Comments: <!--
+ // - Decleration: <?
+ // - Everthing else is unknown to tinyxml.
+ //
+
+ static const char* xmlHeader = { "<?" };
+ static const char* commentHeader = { "<!--" };
+ static const char* dtdHeader = { "<!" };
+ static const char* cdataHeader = { "<![CDATA[" };
+ static const char* elementHeader = { "<" }; // and a header for everything else; check last.
+
+ static const int xmlHeaderLen = 2;
+ static const int commentHeaderLen = 4;
+ static const int dtdHeaderLen = 2;
+ static const int cdataHeaderLen = 9;
+ static const int elementHeaderLen = 1;
+
+#if defined(_MSC_VER)
+#pragma warning ( push )
+#pragma warning ( disable : 4127 )
+#endif
+ TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
+ TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+ if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
+ returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
+ returnNode->memPool = &commentPool;
+ p += xmlHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
+ returnNode = new (commentPool.Alloc()) XMLComment( this );
+ returnNode->memPool = &commentPool;
+ p += commentHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
+ XMLText* text = new (textPool.Alloc()) XMLText( this );
+ returnNode = text;
+ returnNode->memPool = &textPool;
+ p += cdataHeaderLen;
+ text->SetCData( true );
+ }
+ else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
+ returnNode = new (commentPool.Alloc()) XMLUnknown( this );
+ returnNode->memPool = &commentPool;
+ p += dtdHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
+ returnNode = new (elementPool.Alloc()) XMLElement( this );
+ returnNode->memPool = &elementPool;
+ p += elementHeaderLen;
+ }
+ else {
+ returnNode = new (textPool.Alloc()) XMLText( this );
+ returnNode->memPool = &textPool;
+ p = start; // Back it up, all the text counts.
+ }
+
+ *node = returnNode;
+ return p;
+}
+
+
+bool XMLDocument::Accept( XMLVisitor* visitor ) const
+{
+ if ( visitor->VisitEnter( *this ) )
+ {
+ for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
+ {
+ if ( !node->Accept( visitor ) )
+ break;
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+// --------- XMLNode ----------- //
+
+XMLNode::XMLNode( XMLDocument* doc ) :
+ document( doc ),
+ parent( 0 ),
+ firstChild( 0 ), lastChild( 0 ),
+ prev( 0 ), next( 0 )
+{
+}
+
+
+XMLNode::~XMLNode()
+{
+ DeleteChildren();
+ if ( parent ) {
+ parent->Unlink( this );
+ }
+}
+
+
+void XMLNode::SetValue( const char* str, bool staticMem )
+{
+ if ( staticMem )
+ value.SetInternedStr( str );
+ else
+ value.SetStr( str );
+}
+
+
+void XMLNode::DeleteChildren()
+{
+ while( firstChild ) {
+ XMLNode* node = firstChild;
+ Unlink( node );
+
+ DELETE_NODE( node );
+ }
+ firstChild = lastChild = 0;
+}
+
+
+void XMLNode::Unlink( XMLNode* child )
+{
+ TIXMLASSERT( child->parent == this );
+ if ( child == firstChild )
+ firstChild = firstChild->next;
+ if ( child == lastChild )
+ lastChild = lastChild->prev;
+
+ if ( child->prev ) {
+ child->prev->next = child->next;
+ }
+ if ( child->next ) {
+ child->next->prev = child->prev;
+ }
+ child->parent = 0;
+}
+
+
+void XMLNode::DeleteChild( XMLNode* node )
+{
+ TIXMLASSERT( node->parent == this );
+ DELETE_NODE( node );
+}
+
+
+XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
+{
+ if ( lastChild ) {
+ TIXMLASSERT( firstChild );
+ TIXMLASSERT( lastChild->next == 0 );
+ lastChild->next = addThis;
+ addThis->prev = lastChild;
+ lastChild = addThis;
+
+ addThis->next = 0;
+ }
+ else {
+ TIXMLASSERT( firstChild == 0 );
+ firstChild = lastChild = addThis;
+
+ addThis->prev = 0;
+ addThis->next = 0;
+ }
+ addThis->parent = this;
+ return addThis;
+}
+
+
+XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
+{
+ if ( firstChild ) {
+ TIXMLASSERT( lastChild );
+ TIXMLASSERT( firstChild->prev == 0 );
+
+ firstChild->prev = addThis;
+ addThis->next = firstChild;
+ firstChild = addThis;
+
+ addThis->prev = 0;
+ }
+ else {
+ TIXMLASSERT( lastChild == 0 );
+ firstChild = lastChild = addThis;
+
+ addThis->prev = 0;
+ addThis->next = 0;
+ }
+ addThis->parent = this;
+ return addThis;
+}
+
+
+XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
+{
+ TIXMLASSERT( afterThis->parent == this );
+ if ( afterThis->parent != this )
+ return 0;
+
+ if ( afterThis->next == 0 ) {
+ // The last node or the only node.
+ return InsertEndChild( addThis );
+ }
+ addThis->prev = afterThis;
+ addThis->next = afterThis->next;
+ afterThis->next->prev = addThis;
+ afterThis->next = addThis;
+ addThis->parent = this;
+ return addThis;
+}
+
+
+
+
+const XMLElement* XMLNode::FirstChildElement( const char* value ) const
+{
+ for( XMLNode* node=firstChild; node; node=node->next ) {
+ XMLElement* element = node->ToElement();
+ if ( element ) {
+ if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
+ return element;
+ }
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::LastChildElement( const char* value ) const
+{
+ for( XMLNode* node=lastChild; node; node=node->prev ) {
+ XMLElement* element = node->ToElement();
+ if ( element ) {
+ if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
+ return element;
+ }
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
+{
+ for( XMLNode* element=this->next; element; element = element->next ) {
+ if ( element->ToElement()
+ && (!value || XMLUtil::StringEqual( value, element->Value() )))
+ {
+ return element->ToElement();
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
+{
+ for( XMLNode* element=this->prev; element; element = element->prev ) {
+ if ( element->ToElement()
+ && (!value || XMLUtil::StringEqual( value, element->Value() )))
+ {
+ return element->ToElement();
+ }
+ }
+ return 0;
+}
+
+
+char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
+{
+ // This is a recursive method, but thinking about it "at the current level"
+ // it is a pretty simple flat list:
+ // <foo/>
+ // <!-- comment -->
+ //
+ // With a special case:
+ // <foo>
+ // </foo>
+ // <!-- comment -->
+ //
+ // Where the closing element (/foo) *must* be the next thing after the opening
+ // element, and the names must match. BUT the tricky bit is that the closing
+ // element will be read by the child.
+ //
+ // 'endTag' is the end tag for this node, it is returned by a call to a child.
+ // 'parentEnd' is the end tag for the parent, which is filled in and returned.
+
+ while( p && *p ) {
+ XMLNode* node = 0;
+
+ p = document->Identify( p, &node );
+ if ( p == 0 || node == 0 ) {
+ break;
+ }
+
+ StrPair endTag;
+ p = node->ParseDeep( p, &endTag );
+ if ( !p ) {
+ DELETE_NODE( node );
+ node = 0;
+ if ( !document->Error() ) {
+ document->SetError( XML_ERROR_PARSING, 0, 0 );
+ }
+ break;
+ }
+
+ // We read the end tag. Return it to the parent.
+ if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
+ if ( parentEnd ) {
+ *parentEnd = static_cast<XMLElement*>(node)->value;
+ }
+ DELETE_NODE( node );
+ return p;
+ }
+
+ // Handle an end tag returned to this level.
+ // And handle a bunch of annoying errors.
+ XMLElement* ele = node->ToElement();
+ if ( ele ) {
+ if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
+ document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
+ p = 0;
+ }
+ else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
+ document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
+ p = 0;
+ }
+ else if ( !endTag.Empty() ) {
+ if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
+ document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
+ p = 0;
+ }
+ }
+ }
+ if ( p == 0 ) {
+ DELETE_NODE( node );
+ node = 0;
+ }
+ if ( node ) {
+ this->InsertEndChild( node );
+ }
+ }
+ return 0;
+}
+
+// --------- XMLText ---------- //
+char* XMLText::ParseDeep( char* p, StrPair* )
+{
+ const char* start = p;
+ if ( this->CData() ) {
+ p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+ if ( !p ) {
+ document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
+ }
+ return p;
+ }
+ else {
+ p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );
+ if ( !p ) {
+ document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
+ }
+ if ( p && *p ) {
+ return p-1;
+ }
+ }
+ return 0;
+}
+
+
+XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = document;
+ }
+ XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
+ text->SetCData( this->CData() );
+ return text;
+}
+
+
+bool XMLText::ShallowEqual( const XMLNode* compare ) const
+{
+ return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
+}
+
+
+bool XMLText::Accept( XMLVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+// --------- XMLComment ---------- //
+
+XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLComment::~XMLComment()
+{
+ //printf( "~XMLComment\n" );
+}
+
+
+char* XMLComment::ParseDeep( char* p, StrPair* )
+{
+ // Comment parses as text.
+ const char* start = p;
+ p = value.ParseText( p, "-->", StrPair::COMMENT );
+ if ( p == 0 ) {
+ document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = document;
+ }
+ XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
+ return comment;
+}
+
+
+bool XMLComment::ShallowEqual( const XMLNode* compare ) const
+{
+ return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
+}
+
+
+bool XMLComment::Accept( XMLVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+// --------- XMLDeclaration ---------- //
+
+XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLDeclaration::~XMLDeclaration()
+{
+ //printf( "~XMLDeclaration\n" );
+}
+
+
+char* XMLDeclaration::ParseDeep( char* p, StrPair* )
+{
+ // Declaration parses as text.
+ const char* start = p;
+ p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+ if ( p == 0 ) {
+ document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = document;
+ }
+ XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
+ return dec;
+}
+
+
+bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
+{
+ return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
+}
+
+
+
+bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+// --------- XMLUnknown ---------- //
+
+XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLUnknown::~XMLUnknown()
+{
+}
+
+
+char* XMLUnknown::ParseDeep( char* p, StrPair* )
+{
+ // Unknown parses as text.
+ const char* start = p;
+
+ p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+ if ( !p ) {
+ document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = document;
+ }
+ XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
+ return text;
+}
+
+
+bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
+{
+ return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
+}
+
+
+bool XMLUnknown::Accept( XMLVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+// --------- XMLAttribute ---------- //
+char* XMLAttribute::ParseDeep( char* p, bool processEntities )
+{
+ // Parse using the name rules: bug fix, was using ParseText before
+ p = name.ParseName( p );
+ if ( !p || !*p ) return 0;
+
+ // Skip white space before =
+ p = XMLUtil::SkipWhiteSpace( p );
+ if ( !p || *p != '=' ) return 0;
+
+ ++p; // move up to opening quote
+ p = XMLUtil::SkipWhiteSpace( p );
+ if ( *p != '\"' && *p != '\'' ) return 0;
+
+ char endTag[2] = { *p, 0 };
+ ++p; // move past opening quote
+
+ p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
+ return p;
+}
+
+
+void XMLAttribute::SetName( const char* n )
+{
+ name.SetStr( n );
+}
+
+
+int XMLAttribute::QueryIntValue( int* value ) const
+{
+ if ( XMLUtil::ToInt( Value(), value ))
+ return XML_NO_ERROR;
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
+{
+ if ( XMLUtil::ToUnsigned( Value(), value ))
+ return XML_NO_ERROR;
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+int XMLAttribute::QueryBoolValue( bool* value ) const
+{
+ if ( XMLUtil::ToBool( Value(), value )) {
+ return XML_NO_ERROR;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+int XMLAttribute::QueryFloatValue( float* value ) const
+{
+ if ( XMLUtil::ToFloat( Value(), value ))
+ return XML_NO_ERROR;
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+int XMLAttribute::QueryDoubleValue( double* value ) const
+{
+ if ( XMLUtil::ToDouble( Value(), value ))
+ return XML_NO_ERROR;
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+void XMLAttribute::SetAttribute( const char* v )
+{
+ value.SetStr( v );
+}
+
+
+void XMLAttribute::SetAttribute( int v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ value.SetStr( buf );
+}
+
+
+void XMLAttribute::SetAttribute( unsigned v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ value.SetStr( buf );
+}
+
+
+void XMLAttribute::SetAttribute( bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ value.SetStr( buf );
+}
+
+void XMLAttribute::SetAttribute( double v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ value.SetStr( buf );
+}
+
+void XMLAttribute::SetAttribute( float v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ value.SetStr( buf );
+}
+
+
+// --------- XMLElement ---------- //
+XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
+ closingType( 0 ),
+ rootAttribute( 0 )
+{
+}
+
+
+XMLElement::~XMLElement()
+{
+ while( rootAttribute ) {
+ XMLAttribute* next = rootAttribute->next;
+ DELETE_ATTRIBUTE( rootAttribute );
+ rootAttribute = next;
+ }
+}
+
+
+XMLAttribute* XMLElement::FindAttribute( const char* name )
+{
+ XMLAttribute* a = 0;
+ for( a=rootAttribute; a; a = a->next ) {
+ if ( XMLUtil::StringEqual( a->Name(), name ) )
+ return a;
+ }
+ return 0;
+}
+
+
+const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
+{
+ XMLAttribute* a = 0;
+ for( a=rootAttribute; a; a = a->next ) {
+ if ( XMLUtil::StringEqual( a->Name(), name ) )
+ return a;
+ }
+ return 0;
+}
+
+
+const char* XMLElement::Attribute( const char* name, const char* value ) const
+{
+ const XMLAttribute* a = FindAttribute( name );
+ if ( !a )
+ return 0;
+ if ( !value || XMLUtil::StringEqual( a->Value(), value ))
+ return a->Value();
+ return 0;
+}
+
+
+const char* XMLElement::GetText() const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ return FirstChild()->ToText()->Value();
+ }
+ return 0;
+}
+
+
+int XMLElement::QueryIntText( int* _value ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->ToText()->Value();
+ if ( XMLUtil::ToInt( t, _value ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+int XMLElement::QueryUnsignedText( unsigned* _value ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->ToText()->Value();
+ if ( XMLUtil::ToUnsigned( t, _value ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+int XMLElement::QueryBoolText( bool* _value ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->ToText()->Value();
+ if ( XMLUtil::ToBool( t, _value ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+int XMLElement::QueryDoubleText( double* _value ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->ToText()->Value();
+ if ( XMLUtil::ToDouble( t, _value ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+int XMLElement::QueryFloatText( float* _value ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->ToText()->Value();
+ if ( XMLUtil::ToFloat( t, _value ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+
+XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
+{
+ XMLAttribute* last = 0;
+ XMLAttribute* attrib = 0;
+ for( attrib = rootAttribute;
+ attrib;
+ last = attrib, attrib = attrib->next )
+ {
+ if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
+ break;
+ }
+ }
+ if ( !attrib ) {
+ attrib = new (document->attributePool.Alloc() ) XMLAttribute();
+ attrib->memPool = &document->attributePool;
+ if ( last ) {
+ last->next = attrib;
+ }
+ else {
+ rootAttribute = attrib;
+ }
+ attrib->SetName( name );
+ }
+ return attrib;
+}
+
+
+void XMLElement::DeleteAttribute( const char* name )
+{
+ XMLAttribute* prev = 0;
+ for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
+ if ( XMLUtil::StringEqual( name, a->Name() ) ) {
+ if ( prev ) {
+ prev->next = a->next;
+ }
+ else {
+ rootAttribute = a->next;
+ }
+ DELETE_ATTRIBUTE( a );
+ break;
+ }
+ prev = a;
+ }
+}
+
+
+char* XMLElement::ParseAttributes( char* p )
+{
+ const char* start = p;
+ XMLAttribute* prevAttribute = 0;
+
+ // Read the attributes.
+ while( p ) {
+ p = XMLUtil::SkipWhiteSpace( p );
+ if ( !p || !(*p) ) {
+ document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
+ return 0;
+ }
+
+ // attribute.
+ if ( XMLUtil::IsAlpha( *p ) ) {
+ XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
+ attrib->memPool = &document->attributePool;
+
+ p = attrib->ParseDeep( p, document->ProcessEntities() );
+ if ( !p || Attribute( attrib->Name() ) ) {
+ DELETE_ATTRIBUTE( attrib );
+ document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
+ return 0;
+ }
+ // There is a minor bug here: if the attribute in the source xml
+ // document is duplicated, it will not be detected and the
+ // attribute will be doubly added. However, tracking the 'prevAttribute'
+ // avoids re-scanning the attribute list. Preferring performance for
+ // now, may reconsider in the future.
+ if ( prevAttribute ) {
+ prevAttribute->next = attrib;
+ }
+ else {
+ rootAttribute = attrib;
+ }
+ prevAttribute = attrib;
+ }
+ // end of the tag
+ else if ( *p == '/' && *(p+1) == '>' ) {
+ closingType = CLOSED;
+ return p+2; // done; sealed element.
+ }
+ // end of the tag
+ else if ( *p == '>' ) {
+ ++p;
+ break;
+ }
+ else {
+ document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
+ return 0;
+ }
+ }
+ return p;
+}
+
+
+//
+// <ele></ele>
+// <ele>foo<b>bar</b></ele>
+//
+char* XMLElement::ParseDeep( char* p, StrPair* strPair )
+{
+ // Read the element name.
+ p = XMLUtil::SkipWhiteSpace( p );
+ if ( !p ) return 0;
+
+ // The closing element is the </element> form. It is
+ // parsed just like a regular element then deleted from
+ // the DOM.
+ if ( *p == '/' ) {
+ closingType = CLOSING;
+ ++p;
+ }
+
+ p = value.ParseName( p );
+ if ( value.Empty() ) return 0;
+
+ p = ParseAttributes( p );
+ if ( !p || !*p || closingType )
+ return p;
+
+ p = XMLNode::ParseDeep( p, strPair );
+ return p;
+}
+
+
+
+XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = document;
+ }
+ XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
+ for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
+ element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
+ }
+ return element;
+}
+
+
+bool XMLElement::ShallowEqual( const XMLNode* compare ) const
+{
+ const XMLElement* other = compare->ToElement();
+ if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
+
+ const XMLAttribute* a=FirstAttribute();
+ const XMLAttribute* b=other->FirstAttribute();
+
+ while ( a && b ) {
+ if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
+ return false;
+ }
+ a = a->Next();
+ b = b->Next();
+ }
+ if ( a || b ) {
+ // different count
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool XMLElement::Accept( XMLVisitor* visitor ) const
+{
+ if ( visitor->VisitEnter( *this, rootAttribute ) )
+ {
+ for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
+ {
+ if ( !node->Accept( visitor ) )
+ break;
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+// --------- XMLDocument ----------- //
+XMLDocument::XMLDocument( bool _processEntities ) :
+ XMLNode( 0 ),
+ writeBOM( false ),
+ processEntities( _processEntities ),
+ errorID( 0 ),
+ errorStr1( 0 ),
+ errorStr2( 0 ),
+ charBuffer( 0 )
+{
+ document = this; // avoid warning about 'this' in initializer list
+}
+
+
+XMLDocument::~XMLDocument()
+{
+ DeleteChildren();
+ delete [] charBuffer;
+
+#if 0
+ textPool.Trace( "text" );
+ elementPool.Trace( "element" );
+ commentPool.Trace( "comment" );
+ attributePool.Trace( "attribute" );
+#endif
+
+ TIXMLASSERT( textPool.CurrentAllocs() == 0 );
+ TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
+ TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
+ TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
+}
+
+
+void XMLDocument::InitDocument()
+{
+ errorID = XML_NO_ERROR;
+ errorStr1 = 0;
+ errorStr2 = 0;
+
+ delete [] charBuffer;
+ charBuffer = 0;
+
+}
+
+
+XMLElement* XMLDocument::NewElement( const char* name )
+{
+ XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
+ ele->memPool = &elementPool;
+ ele->SetName( name );
+ return ele;
+}
+
+
+XMLComment* XMLDocument::NewComment( const char* str )
+{
+ XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
+ comment->memPool = &commentPool;
+ comment->SetValue( str );
+ return comment;
+}
+
+
+XMLText* XMLDocument::NewText( const char* str )
+{
+ XMLText* text = new (textPool.Alloc()) XMLText( this );
+ text->memPool = &textPool;
+ text->SetValue( str );
+ return text;
+}
+
+
+XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
+{
+ XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
+ dec->memPool = &commentPool;
+ dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
+ return dec;
+}
+
+
+XMLUnknown* XMLDocument::NewUnknown( const char* str )
+{
+ XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
+ unk->memPool = &commentPool;
+ unk->SetValue( str );
+ return unk;
+}
+
+
+int XMLDocument::LoadFile( const char* filename )
+{
+ DeleteChildren();
+ InitDocument();
+
+#if defined(_MSC_VER)
+#pragma warning ( push )
+#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
+#endif
+ FILE* fp = fopen( filename, "rb" );
+#if defined(_MSC_VER)
+#pragma warning ( pop )
+#endif
+ if ( !fp ) {
+ SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
+ return errorID;
+ }
+ LoadFile( fp );
+ fclose( fp );
+ return errorID;
+}
+
+
+int XMLDocument::LoadFile( FILE* fp )
+{
+ DeleteChildren();
+ InitDocument();
+
+ fseek( fp, 0, SEEK_END );
+ unsigned size = ftell( fp );
+ fseek( fp, 0, SEEK_SET );
+
+ if ( size == 0 ) {
+ return errorID;
+ }
+
+ charBuffer = new char[size+1];
+ size_t read = fread( charBuffer, 1, size, fp );
+ if ( read != size ) {
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return errorID;
+ }
+
+ charBuffer[size] = 0;
+
+ const char* p = charBuffer;
+ p = XMLUtil::SkipWhiteSpace( p );
+ p = XMLUtil::ReadBOM( p, &writeBOM );
+ if ( !p || !*p ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return errorID;
+ }
+
+ ParseDeep( charBuffer + (p-charBuffer), 0 );
+ return errorID;
+}
+
+
+int XMLDocument::SaveFile( const char* filename )
+{
+#if defined(_MSC_VER)
+#pragma warning ( push )
+#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
+#endif
+ int fd = open(filename, O_RDWR|O_CREAT, 0644);
+ FILE* fp = fdopen(fd, "w");
+ //FILE* fp = fopen( filename, "w" );
+#if defined(_MSC_VER)
+#pragma warning ( pop )
+#endif
+ if ( !fp ) {
+ SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
+ return errorID;
+ }
+ SaveFile(fp);
+ fclose( fp );
+ return errorID;
+}
+
+
+int XMLDocument::SaveFile( FILE* fp )
+{
+ XMLPrinter stream( fp );
+ Print( &stream );
+ return errorID;
+}
+
+
+int XMLDocument::Parse( const char* p )
+{
+ DeleteChildren();
+ InitDocument();
+
+ if ( !p || !*p ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return errorID;
+ }
+ p = XMLUtil::SkipWhiteSpace( p );
+ p = XMLUtil::ReadBOM( p, &writeBOM );
+ if ( !p || !*p ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return errorID;
+ }
+
+ size_t len = strlen( p );
+ charBuffer = new char[ len+1 ];
+ memcpy( charBuffer, p, len+1 );
+
+
+ ParseDeep( charBuffer, 0 );
+ return errorID;
+}
+
+
+void XMLDocument::Print( XMLPrinter* streamer )
+{
+ XMLPrinter stdStreamer( stdout );
+ if ( !streamer )
+ streamer = &stdStreamer;
+ Accept( streamer );
+}
+
+
+void XMLDocument::SetError( int error, const char* str1, const char* str2 )
+{
+ errorID = error;
+ errorStr1 = str1;
+ errorStr2 = str2;
+}
+
+
+void XMLDocument::PrintError() const
+{
+ if ( errorID ) {
+ static const int LEN = 20;
+ char buf1[LEN] = { 0 };
+ char buf2[LEN] = { 0 };
+
+ if ( errorStr1 ) {
+ TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
+ }
+ if ( errorStr2 ) {
+ TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
+ }
+
+ printf( "XMLDocument error id=%d str1=%s str2=%s\n",
+ errorID, buf1, buf2 );
+ }
+}
+
+
+XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
+ elementJustOpened( false ),
+ firstElement( true ),
+ fp( file ),
+ depth( 0 ),
+ textDepth( -1 ),
+ processEntities( true ),
+ compactMode( compact )
+{
+ for( int i=0; i<ENTITY_RANGE; ++i ) {
+ entityFlag[i] = false;
+ restrictedEntityFlag[i] = false;
+ }
+ for( int i=0; i<NUM_ENTITIES; ++i ) {
+ TIXMLASSERT( entities[i].value < ENTITY_RANGE );
+ if ( entities[i].value < ENTITY_RANGE ) {
+ entityFlag[ (int)entities[i].value ] = true;
+ }
+ }
+ restrictedEntityFlag[(int)'&'] = true;
+ restrictedEntityFlag[(int)'<'] = true;
+ restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
+ buffer.Push( 0 );
+}
+
+
+void XMLPrinter::Print( const char* format, ... )
+{
+ va_list va;
+ va_start( va, format );
+
+ if ( fp ) {
+ vfprintf( fp, format, va );
+ }
+ else {
+ // This seems brutally complex. Haven't figured out a better
+ // way on windows.
+ #ifdef _MSC_VER
+ int len = -1;
+ int expand = 1000;
+ while ( len < 0 ) {
+ len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
+ if ( len < 0 ) {
+ expand *= 3/2;
+ accumulator.PushArr( expand );
+ }
+ }
+ char* p = buffer.PushArr( len ) - 1;
+ memcpy( p, accumulator.Mem(), len+1 );
+ #else
+ int len = vsnprintf( 0, 0, format, va );
+ // Close out and re-start the va-args
+ va_end( va );
+ va_start( va, format );
+ char* p = buffer.PushArr( len ) - 1;
+ vsnprintf( p, len+1, format, va );
+ #endif
+ }
+ va_end( va );
+}
+
+
+void XMLPrinter::PrintSpace( int depth )
+{
+ for( int i=0; i<depth; ++i ) {
+ Print( " " );
+ }
+}
+
+
+void XMLPrinter::PrintString( const char* p, bool restricted )
+{
+ // Look for runs of bytes between entities to print.
+ const char* q = p;
+ const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
+
+ if ( processEntities ) {
+ while ( *q ) {
+ // Remember, char is sometimes signed. (How many times has that bitten me?)
+ if ( *q > 0 && *q < ENTITY_RANGE ) {
+ // Check for entities. If one is found, flush
+ // the stream up until the entity, write the
+ // entity, and keep looking.
+ if ( flag[(unsigned)(*q)] ) {
+ while ( p < q ) {
+ Print( "%c", *p );
+ ++p;
+ }
+ for( int i=0; i<NUM_ENTITIES; ++i ) {
+ if ( entities[i].value == *q ) {
+ Print( "&%s;", entities[i].pattern );
+ break;
+ }
+ }
+ ++p;
+ }
+ }
+ ++q;
+ }
+ }
+ // Flush the remaining string. This will be the entire
+ // string if an entity wasn't found.
+ if ( !processEntities || (q-p > 0) ) {
+ Print( "%s", p );
+ }
+}
+
+
+void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
+{
+ static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
+ if ( writeBOM ) {
+ Print( "%s", bom );
+ }
+ if ( writeDec ) {
+ PushDeclaration( "xml version=\"1.0\"" );
+ }
+}
+
+
+void XMLPrinter::OpenElement( const char* name )
+{
+ if ( elementJustOpened ) {
+ SealElement();
+ }
+ stack.Push( name );
+
+ if ( textDepth < 0 && !firstElement && !compactMode ) {
+ Print( "\n" );
+ PrintSpace( depth );
+ }
+
+ Print( "<%s", name );
+ elementJustOpened = true;
+ firstElement = false;
+ ++depth;
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, const char* value )
+{
+ TIXMLASSERT( elementJustOpened );
+ Print( " %s=\"", name );
+ PrintString( value, false );
+ Print( "\"" );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, int v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, unsigned v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, double v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::CloseElement()
+{
+ --depth;
+ const char* name = stack.Pop();
+
+ if ( elementJustOpened ) {
+ Print( "/>" );
+ }
+ else {
+ if ( textDepth < 0 && !compactMode) {
+ Print( "\n" );
+ PrintSpace( depth );
+ }
+ Print( "</%s>", name );
+ }
+
+ if ( textDepth == depth )
+ textDepth = -1;
+ if ( depth == 0 && !compactMode)
+ Print( "\n" );
+ elementJustOpened = false;
+}
+
+
+void XMLPrinter::SealElement()
+{
+ elementJustOpened = false;
+ Print( ">" );
+}
+
+
+void XMLPrinter::PushText( const char* text, bool cdata )
+{
+ textDepth = depth-1;
+
+ if ( elementJustOpened ) {
+ SealElement();
+ }
+ if ( cdata ) {
+ Print( "<![CDATA[" );
+ Print( "%s", text );
+ Print( "]]>" );
+ }
+ else {
+ PrintString( text, true );
+ }
+}
+
+void XMLPrinter::PushText( int value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( unsigned value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( bool value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( float value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( double value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushComment( const char* comment )
+{
+ if ( elementJustOpened ) {
+ SealElement();
+ }
+ if ( textDepth < 0 && !firstElement && !compactMode) {
+ Print( "\n" );
+ PrintSpace( depth );
+ }
+ firstElement = false;
+ Print( "<!--%s-->", comment );
+}
+
+
+void XMLPrinter::PushDeclaration( const char* value )
+{
+ if ( elementJustOpened ) {
+ SealElement();
+ }
+ if ( textDepth < 0 && !firstElement && !compactMode) {
+ Print( "\n" );
+ PrintSpace( depth );
+ }
+ firstElement = false;
+ Print( "<?%s?>", value );
+}
+
+
+void XMLPrinter::PushUnknown( const char* value )
+{
+ if ( elementJustOpened ) {
+ SealElement();
+ }
+ if ( textDepth < 0 && !firstElement && !compactMode) {
+ Print( "\n" );
+ PrintSpace( depth );
+ }
+ firstElement = false;
+ Print( "<!%s>", value );
+}
+
+
+bool XMLPrinter::VisitEnter( const XMLDocument& doc )
+{
+ processEntities = doc.ProcessEntities();
+ if ( doc.HasBOM() ) {
+ PushHeader( true, false );
+ }
+ return true;
+}
+
+
+bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
+{
+ OpenElement( element.Name() );
+ while ( attribute ) {
+ PushAttribute( attribute->Name(), attribute->Value() );
+ attribute = attribute->Next();
+ }
+ return true;
+}
+
+
+bool XMLPrinter::VisitExit( const XMLElement& )
+{
+ CloseElement();
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLText& text )
+{
+ PushText( text.Value(), text.CData() );
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLComment& comment )
+{
+ PushComment( comment.Value() );
+ return true;
+}
+
+bool XMLPrinter::Visit( const XMLDeclaration& declaration )
+{
+ PushDeclaration( declaration.Value() );
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLUnknown& unknown )
+{
+ PushUnknown( unknown.Value() );
+ return true;
+}
diff --git a/src/llvm/xml/tinyxml2.h b/src/llvm/xml/tinyxml2.h
new file mode 100644
index 0000000..80e076d
--- /dev/null
+++ b/src/llvm/xml/tinyxml2.h
@@ -0,0 +1,1480 @@
+/*
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#ifndef TINYXML2_INCLUDED
+#define TINYXML2_INCLUDED
+
+#include <cctype>
+#include <climits>
+#include <cstdio>
+#include <cstring>
+//#include <cstdarg>
+#include <stdarg.h>
+/*
+ TODO: intern strings instead of allocation.
+*/
+/*
+ gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
+*/
+
+#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
+ #ifndef DEBUG
+ #define DEBUG
+ #endif
+#endif
+
+
+#if defined(DEBUG)
+ #if defined(_MSC_VER)
+ #define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
+ #elif defined (ANDROID_NDK)
+ #include <android/log.h>
+ #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
+ #else
+ #include <assert.h>
+ #define TIXMLASSERT assert
+ #endif
+#else
+ #define TIXMLASSERT( x ) {}
+#endif
+
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+ // Microsoft visual studio, version 2005 and higher.
+ /*int _snprintf_s(
+ char *buffer,
+ size_t sizeOfBuffer,
+ size_t count,
+ const char *format [,
+ argument] ...
+ );*/
+ inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) {
+ va_list va;
+ va_start( va, format );
+ int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
+ va_end( va );
+ return result;
+ }
+ #define TIXML_SSCANF sscanf_s
+#else
+ // GCC version 3 and higher
+ //#warning( "Using sn* functions." )
+ #define TIXML_SNPRINTF snprintf
+ #define TIXML_SSCANF sscanf
+#endif
+
+static const int TIXML2_MAJOR_VERSION = 1;
+static const int TIXML2_MINOR_VERSION = 0;
+static const int TIXML2_PATCH_VERSION = 6;
+
+namespace tinyxml2
+{
+class XMLDocument;
+class XMLElement;
+class XMLAttribute;
+class XMLComment;
+class XMLNode;
+class XMLText;
+class XMLDeclaration;
+class XMLUnknown;
+
+class XMLPrinter;
+
+/*
+ A class that wraps strings. Normally stores the start and end
+ pointers into the XML file itself, and will apply normalization
+ and entity translation if actually read. Can also store (and memory
+ manage) a traditional char[]
+*/
+class StrPair
+{
+public:
+ enum {
+ NEEDS_ENTITY_PROCESSING = 0x01,
+ NEEDS_NEWLINE_NORMALIZATION = 0x02,
+
+ TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
+ TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
+ ATTRIBUTE_NAME = 0,
+ ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
+ ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
+ COMMENT = NEEDS_NEWLINE_NORMALIZATION
+ };
+
+ StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
+ ~StrPair();
+
+ void Set( char* _start, char* _end, int _flags ) {
+ Reset();
+ this->start = _start; this->end = _end; this->flags = _flags | NEEDS_FLUSH;
+ }
+ const char* GetStr();
+ bool Empty() const { return start == end; }
+
+ void SetInternedStr( const char* str ) { Reset(); this->start = const_cast<char*>(str); }
+ void SetStr( const char* str, int flags=0 );
+
+ char* ParseText( char* in, const char* endTag, int strFlags );
+ char* ParseName( char* in );
+
+
+private:
+ void Reset();
+
+ enum {
+ NEEDS_FLUSH = 0x100,
+ NEEDS_DELETE = 0x200
+ };
+
+ // After parsing, if *end != 0, it can be set to zero.
+ int flags;
+ char* start;
+ char* end;
+};
+
+
+/*
+ A dynamic array of Plain Old Data. Doesn't support constructors, etc.
+ Has a small initial memory pool, so that low or no usage will not
+ cause a call to new/delete
+*/
+template <class T, int INIT>
+class DynArray
+{
+public:
+ DynArray< T, INIT >()
+ {
+ mem = pool;
+ allocated = INIT;
+ size = 0;
+ }
+ ~DynArray()
+ {
+ if ( mem != pool ) {
+ delete [] mem;
+ }
+ }
+ void Push( T t )
+ {
+ EnsureCapacity( size+1 );
+ mem[size++] = t;
+ }
+
+ T* PushArr( int count )
+ {
+ EnsureCapacity( size+count );
+ T* ret = &mem[size];
+ size += count;
+ return ret;
+ }
+ T Pop() {
+ return mem[--size];
+ }
+ void PopArr( int count )
+ {
+ TIXMLASSERT( size >= count );
+ size -= count;
+ }
+
+ bool Empty() const { return size == 0; }
+ T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
+ const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
+ int Size() const { return size; }
+ int Capacity() const { return allocated; }
+ const T* Mem() const { return mem; }
+ T* Mem() { return mem; }
+
+
+private:
+ void EnsureCapacity( int cap ) {
+ if ( cap > allocated ) {
+ int newAllocated = cap * 2;
+ T* newMem = new T[newAllocated];
+ memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
+ if ( mem != pool ) delete [] mem;
+ mem = newMem;
+ allocated = newAllocated;
+ }
+ }
+
+ T* mem;
+ T pool[INIT];
+ int allocated; // objects allocated
+ int size; // number objects in use
+};
+
+
+/*
+ Parent virtual class of a pool for fast allocation
+ and deallocation of objects.
+*/
+class MemPool
+{
+public:
+ MemPool() {}
+ virtual ~MemPool() {}
+
+ virtual int ItemSize() const = 0;
+ virtual void* Alloc() = 0;
+ virtual void Free( void* ) = 0;
+};
+
+
+/*
+ Template child class to create pools of the correct type.
+*/
+template< int SIZE >
+class MemPoolT : public MemPool
+{
+public:
+ MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
+ ~MemPoolT() {
+ // Delete the blocks.
+ for( int i=0; i<blockPtrs.Size(); ++i ) {
+ delete blockPtrs[i];
+ }
+ }
+
+ virtual int ItemSize() const { return SIZE; }
+ int CurrentAllocs() const { return currentAllocs; }
+
+ virtual void* Alloc() {
+ if ( !root ) {
+ // Need a new block.
+ Block* block = new Block();
+ blockPtrs.Push( block );
+
+ for( int i=0; i<COUNT-1; ++i ) {
+ block->chunk[i].next = &block->chunk[i+1];
+ }
+ block->chunk[COUNT-1].next = 0;
+ root = block->chunk;
+ }
+ void* result = root;
+ root = root->next;
+
+ ++currentAllocs;
+ if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
+ nAllocs++;
+ return result;
+ }
+ virtual void Free( void* mem ) {
+ if ( !mem ) return;
+ --currentAllocs;
+ Chunk* chunk = (Chunk*)mem;
+ memset( chunk, 0xfe, sizeof(Chunk) );
+ chunk->next = root;
+ root = chunk;
+ }
+ void Trace( const char* name ) {
+ printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
+ name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
+ }
+
+private:
+ enum { COUNT = 1024/SIZE };
+ union Chunk {
+ Chunk* next;
+ char mem[SIZE];
+ };
+ struct Block {
+ Chunk chunk[COUNT];
+ };
+ DynArray< Block*, 10 > blockPtrs;
+ Chunk* root;
+
+ int currentAllocs;
+ int nAllocs;
+ int maxAllocs;
+};
+
+
+
+/**
+ Implements the interface to the "Visitor pattern" (see the Accept() method.)
+ If you call the Accept() method, it requires being passed a XMLVisitor
+ class to handle callbacks. For nodes that contain other nodes (Document, Element)
+ you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
+ are simply called with Visit().
+
+ If you return 'true' from a Visit method, recursive parsing will continue. If you return
+ false, <b>no children of this node or its sibilings</b> will be visited.
+
+ All flavors of Visit methods have a default implementation that returns 'true' (continue
+ visiting). You need to only override methods that are interesting to you.
+
+ Generally Accept() is called on the TiXmlDocument, although all nodes support visiting.
+
+ You should never change the document from a callback.
+
+ @sa XMLNode::Accept()
+*/
+class XMLVisitor
+{
+public:
+ virtual ~XMLVisitor() {}
+
+ /// Visit a document.
+ virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
+ /// Visit a document.
+ virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
+
+ /// Visit an element.
+ virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
+ /// Visit an element.
+ virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
+
+ /// Visit a declaration.
+ virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
+ /// Visit a text node.
+ virtual bool Visit( const XMLText& /*text*/ ) { return true; }
+ /// Visit a comment node.
+ virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
+ /// Visit an unknown node.
+ virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
+};
+
+
+/*
+ Utility functionality.
+*/
+class XMLUtil
+{
+public:
+ // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
+ // correct, but simple, and usually works.
+ static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<const unsigned char*>(p) ) ) { ++p; } return p; }
+ static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<unsigned char*>(p) ) ) { ++p; } return p; }
+
+ inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
+ int n = 0;
+ if ( p == q ) {
+ return true;
+ }
+ while( *p && *q && *p == *q && n<nChar ) {
+ ++p; ++q; ++n;
+ }
+ if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
+ return true;
+ }
+ return false;
+ }
+ inline static int IsUTF8Continuation( const char p ) { return p & 0x80; }
+ inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
+ inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
+
+ static const char* ReadBOM( const char* p, bool* hasBOM );
+ // p is the starting location,
+ // the UTF-8 value of the entity will be placed in value, and length filled in.
+ static const char* GetCharacterRef( const char* p, char* value, int* length );
+ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+
+ // converts primitive types to strings
+ static void ToStr( int v, char* buffer, int bufferSize );
+ static void ToStr( unsigned v, char* buffer, int bufferSize );
+ static void ToStr( bool v, char* buffer, int bufferSize );
+ static void ToStr( float v, char* buffer, int bufferSize );
+ static void ToStr( double v, char* buffer, int bufferSize );
+
+ // converts strings to primitive types
+ static bool ToInt( const char* str, int* value );
+ static bool ToUnsigned( const char* str, unsigned* value );
+ static bool ToBool( const char* str, bool* value );
+ static bool ToFloat( const char* str, float* value );
+ static bool ToDouble( const char* str, double* value );
+};
+
+
+/** XMLNode is a base class for every object that is in the
+ XML Document Object Model (DOM), except XMLAttributes.
+ Nodes have siblings, a parent, and children which can
+ be navigated. A node is always in a XMLDocument.
+ The type of a XMLNode can be queried, and it can
+ be cast to its more defined type.
+
+ A XMLDocument allocates memory for all its Nodes.
+ When the XMLDocument gets deleted, all its Nodes
+ will also be deleted.
+
+ @verbatim
+ A Document can contain: Element (container or leaf)
+ Comment (leaf)
+ Unknown (leaf)
+ Declaration( leaf )
+
+ An Element can contain: Element (container or leaf)
+ Text (leaf)
+ Attributes (not on tree)
+ Comment (leaf)
+ Unknown (leaf)
+
+ @endverbatim
+*/
+class XMLNode
+{
+ friend class XMLDocument;
+ friend class XMLElement;
+public:
+
+ /// Get the XMLDocument that owns this XMLNode.
+ const XMLDocument* GetDocument() const { return document; }
+ /// Get the XMLDocument that owns this XMLNode.
+ XMLDocument* GetDocument() { return document; }
+
+ virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
+ virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
+ virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
+ virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
+ virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
+ virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
+
+ virtual const XMLElement* ToElement() const { return 0; }
+ virtual const XMLText* ToText() const { return 0; }
+ virtual const XMLComment* ToComment() const { return 0; }
+ virtual const XMLDocument* ToDocument() const { return 0; }
+ virtual const XMLDeclaration* ToDeclaration() const { return 0; }
+ virtual const XMLUnknown* ToUnknown() const { return 0; }
+
+ /** The meaning of 'value' changes for the specific type.
+ @verbatim
+ Document: empty
+ Element: name of the element
+ Comment: the comment text
+ Unknown: the tag contents
+ Text: the text string
+ @endverbatim
+ */
+ const char* Value() const { return value.GetStr(); }
+ /** Set the Value of an XML node.
+ @sa Value()
+ */
+ void SetValue( const char* val, bool staticMem=false );
+
+ /// Get the parent of this node on the DOM.
+ const XMLNode* Parent() const { return parent; }
+ XMLNode* Parent() { return parent; }
+
+ /// Returns true if this node has no children.
+ bool NoChildren() const { return !firstChild; }
+
+ /// Get the first child node, or null if none exists.
+ const XMLNode* FirstChild() const { return firstChild; }
+ XMLNode* FirstChild() { return firstChild; }
+ /** Get the first child element, or optionally the first child
+ element with the specified name.
+ */
+ const XMLElement* FirstChildElement( const char* value=0 ) const;
+ XMLElement* FirstChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( _value )); }
+
+ /// Get the last child node, or null if none exists.
+ const XMLNode* LastChild() const { return lastChild; }
+ XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
+
+ /** Get the last child element or optionally the last child
+ element with the specified name.
+ */
+ const XMLElement* LastChildElement( const char* value=0 ) const;
+ XMLElement* LastChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(_value) ); }
+
+ /// Get the previous (left) sibling node of this node.
+ const XMLNode* PreviousSibling() const { return prev; }
+ XMLNode* PreviousSibling() { return prev; }
+
+ /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
+ const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
+ XMLElement* PreviousSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( _value ) ); }
+
+ /// Get the next (right) sibling node of this node.
+ const XMLNode* NextSibling() const { return next; }
+ XMLNode* NextSibling() { return next; }
+
+ /// Get the next (right) sibling element of this node, with an opitionally supplied name.
+ const XMLElement* NextSiblingElement( const char* value=0 ) const;
+ XMLElement* NextSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( _value ) ); }
+
+ /**
+ Add a child node as the last (right) child.
+ */
+ XMLNode* InsertEndChild( XMLNode* addThis );
+
+ XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); }
+ /**
+ Add a child node as the first (left) child.
+ */
+ XMLNode* InsertFirstChild( XMLNode* addThis );
+ /**
+ Add a node after the specified child node.
+ */
+ XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
+
+ /**
+ Delete all the children of this node.
+ */
+ void DeleteChildren();
+
+ /**
+ Delete a child of this node.
+ */
+ void DeleteChild( XMLNode* node );
+
+ /**
+ Make a copy of this node, but not its children.
+ You may pass in a Document pointer that will be
+ the owner of the new Node. If the 'document' is
+ null, then the node returned will be allocated
+ from the current Document. (this->GetDocument())
+
+ Note: if called on a XMLDocument, this will return null.
+ */
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
+
+ /**
+ Test if 2 nodes are the same, but don't test children.
+ The 2 nodes do not need to be in the same Document.
+
+ Note: if called on a XMLDocument, this will return false.
+ */
+ virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
+
+ /** Accept a hierarchical visit of the nodes in the TinyXML DOM. Every node in the
+ XML tree will be conditionally visited and the host will be called back
+ via the TiXmlVisitor interface.
+
+ This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
+ the XML for the callbacks, so the performance of TinyXML is unchanged by using this
+ interface versus any other.)
+
+ The interface has been based on ideas from:
+
+ - http://www.saxproject.org/
+ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
+
+ Which are both good references for "visiting".
+
+ An example of using Accept():
+ @verbatim
+ TiXmlPrinter printer;
+ tinyxmlDoc.Accept( &printer );
+ const char* xmlcstr = printer.CStr();
+ @endverbatim
+ */
+ virtual bool Accept( XMLVisitor* visitor ) const = 0;
+
+ // internal
+ virtual char* ParseDeep( char*, StrPair* );
+
+protected:
+ XMLNode( XMLDocument* );
+ virtual ~XMLNode();
+ XMLNode( const XMLNode& ); // not supported
+ XMLNode& operator=( const XMLNode& ); // not supported
+
+ XMLDocument* document;
+ XMLNode* parent;
+ mutable StrPair value;
+
+ XMLNode* firstChild;
+ XMLNode* lastChild;
+
+ XMLNode* prev;
+ XMLNode* next;
+
+private:
+ MemPool* memPool;
+ void Unlink( XMLNode* child );
+};
+
+
+/** XML text.
+
+ Note that a text node can have child element nodes, for example:
+ @verbatim
+ <root>This is <b>bold</b></root>
+ @endverbatim
+
+ A text node can have 2 ways to output the next. "normal" output
+ and CDATA. It will default to the mode it was parsed from the XML file and
+ you generally want to leave it alone, but you can change the output mode with
+ SetCDATA() and query it with CDATA().
+*/
+class XMLText : public XMLNode
+{
+ friend class XMLBase;
+ friend class XMLDocument;
+public:
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ virtual XMLText* ToText() { return this; }
+ virtual const XMLText* ToText() const { return this; }
+
+ /// Declare whether this should be CDATA or standard text.
+ void SetCData( bool _isCData ) { this->isCData = _isCData; }
+ /// Returns true if this is a CDATA text element.
+ bool CData() const { return isCData; }
+
+ char* ParseDeep( char*, StrPair* endTag );
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+
+protected:
+ XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
+ virtual ~XMLText() {}
+ XMLText( const XMLText& ); // not supported
+ XMLText& operator=( const XMLText& ); // not supported
+
+private:
+ bool isCData;
+};
+
+
+/** An XML Comment. */
+class XMLComment : public XMLNode
+{
+ friend class XMLDocument;
+public:
+ virtual XMLComment* ToComment() { return this; }
+ virtual const XMLComment* ToComment() const { return this; }
+
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ char* ParseDeep( char*, StrPair* endTag );
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+ XMLComment( XMLDocument* doc );
+ virtual ~XMLComment();
+ XMLComment( const XMLComment& ); // not supported
+ XMLComment& operator=( const XMLComment& ); // not supported
+
+private:
+};
+
+
+/** In correct XML the declaration is the first entry in the file.
+ @verbatim
+ <?xml version="1.0" standalone="yes"?>
+ @endverbatim
+
+ TinyXML2 will happily read or write files without a declaration,
+ however.
+
+ The text of the declaration isn't interpreted. It is parsed
+ and written as a string.
+*/
+class XMLDeclaration : public XMLNode
+{
+ friend class XMLDocument;
+public:
+ virtual XMLDeclaration* ToDeclaration() { return this; }
+ virtual const XMLDeclaration* ToDeclaration() const { return this; }
+
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ char* ParseDeep( char*, StrPair* endTag );
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+ XMLDeclaration( XMLDocument* doc );
+ virtual ~XMLDeclaration();
+ XMLDeclaration( const XMLDeclaration& ); // not supported
+ XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
+};
+
+
+/** Any tag that tinyXml doesn't recognize is saved as an
+ unknown. It is a tag of text, but should not be modified.
+ It will be written back to the XML, unchanged, when the file
+ is saved.
+
+ DTD tags get thrown into TiXmlUnknowns.
+*/
+class XMLUnknown : public XMLNode
+{
+ friend class XMLDocument;
+public:
+ virtual XMLUnknown* ToUnknown() { return this; }
+ virtual const XMLUnknown* ToUnknown() const { return this; }
+
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ char* ParseDeep( char*, StrPair* endTag );
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+ XMLUnknown( XMLDocument* doc );
+ virtual ~XMLUnknown();
+ XMLUnknown( const XMLUnknown& ); // not supported
+ XMLUnknown& operator=( const XMLUnknown& ); // not supported
+};
+
+
+enum {
+ XML_NO_ERROR = 0,
+ XML_SUCCESS = 0,
+
+ XML_NO_ATTRIBUTE,
+ XML_WRONG_ATTRIBUTE_TYPE,
+
+ XML_ERROR_FILE_NOT_FOUND,
+ XML_ERROR_FILE_COULD_NOT_BE_OPENED,
+ XML_ERROR_FILE_READ_ERROR,
+ XML_ERROR_ELEMENT_MISMATCH,
+ XML_ERROR_PARSING_ELEMENT,
+ XML_ERROR_PARSING_ATTRIBUTE,
+ XML_ERROR_IDENTIFYING_TAG,
+ XML_ERROR_PARSING_TEXT,
+ XML_ERROR_PARSING_CDATA,
+ XML_ERROR_PARSING_COMMENT,
+ XML_ERROR_PARSING_DECLARATION,
+ XML_ERROR_PARSING_UNKNOWN,
+ XML_ERROR_EMPTY_DOCUMENT,
+ XML_ERROR_MISMATCHED_ELEMENT,
+ XML_ERROR_PARSING,
+
+ XML_CAN_NOT_CONVERT_TEXT,
+ XML_NO_TEXT_NODE
+};
+
+
+/** An attribute is a name-value pair. Elements have an arbitrary
+ number of attributes, each with a unique name.
+
+ @note The attributes are not XMLNodes. You may only query the
+ Next() attribute in a list.
+*/
+class XMLAttribute
+{
+ friend class XMLElement;
+public:
+ const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
+ const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
+ const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
+
+ /** IntAttribute interprets the attribute as an integer, and returns the value.
+ If the value isn't an integer, 0 will be returned. There is no error checking;
+ use QueryIntAttribute() if you need error checking.
+ */
+ int IntValue() const { int i=0; QueryIntValue( &i ); return i; }
+ /// Query as an unsigned integer. See IntAttribute()
+ unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; }
+ /// Query as a boolean. See IntAttribute()
+ bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; }
+ /// Query as a double. See IntAttribute()
+ double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; }
+ /// Query as a float. See IntAttribute()
+ float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; }
+
+ /** QueryIntAttribute interprets the attribute as an integer, and returns the value
+ in the provided paremeter. The function will return XML_NO_ERROR on success,
+ and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
+ */
+ int QueryIntValue( int* value ) const;
+ /// See QueryIntAttribute
+ int QueryUnsignedValue( unsigned int* value ) const;
+ /// See QueryIntAttribute
+ int QueryBoolValue( bool* value ) const;
+ /// See QueryIntAttribute
+ int QueryDoubleValue( double* value ) const;
+ /// See QueryIntAttribute
+ int QueryFloatValue( float* value ) const;
+
+ /// Set the attribute to a string value.
+ void SetAttribute( const char* value );
+ /// Set the attribute to value.
+ void SetAttribute( int value );
+ /// Set the attribute to value.
+ void SetAttribute( unsigned value );
+ /// Set the attribute to value.
+ void SetAttribute( bool value );
+ /// Set the attribute to value.
+ void SetAttribute( double value );
+ /// Set the attribute to value.
+ void SetAttribute( float value );
+
+private:
+ enum { BUF_SIZE = 200 };
+
+ XMLAttribute() : next( 0 ) {}
+ virtual ~XMLAttribute() {}
+ XMLAttribute( const XMLAttribute& ); // not supported
+ void operator=( const XMLAttribute& ); // not supported
+ void SetName( const char* name );
+
+ char* ParseDeep( char* p, bool processEntities );
+
+ mutable StrPair name;
+ mutable StrPair value;
+ XMLAttribute* next;
+ MemPool* memPool;
+};
+
+
+/** The element is a container class. It has a value, the element name,
+ and can contain other elements, text, comments, and unknowns.
+ Elements also contain an arbitrary number of attributes.
+*/
+class XMLElement : public XMLNode
+{
+ friend class XMLBase;
+ friend class XMLDocument;
+public:
+ /// Get the name of an element (which is the Value() of the node.)
+ const char* Name() const { return Value(); }
+ /// Set the name of the element.
+ void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
+
+ virtual XMLElement* ToElement() { return this; }
+ virtual const XMLElement* ToElement() const { return this; }
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ /** Given an attribute name, Attribute() returns the value
+ for the attribute of that name, or null if none
+ exists. For example:
+
+ @verbatim
+ const char* value = ele->Attribute( "foo" );
+ @endverbatim
+
+ The 'value' parameter is normally null. However, if specified,
+ the attribute will only be returned if the 'name' and 'value'
+ match. This allow you to write code:
+
+ @verbatim
+ if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
+ @endverbatim
+
+ rather than:
+ @verbatim
+ if ( ele->Attribute( "foo" ) ) {
+ if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
+ }
+ @endverbatim
+ */
+ const char* Attribute( const char* name, const char* value=0 ) const;
+
+ /** Given an attribute name, IntAttribute() returns the value
+ of the attribute interpreted as an integer. 0 will be
+ returned if there is an error. For a method with error
+ checking, see QueryIntAttribute()
+ */
+ int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
+ /// See IntAttribute()
+ unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
+ /// See IntAttribute()
+ bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
+ /// See IntAttribute()
+ double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
+ /// See IntAttribute()
+ float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
+
+ /** Given an attribute name, QueryIntAttribute() returns
+ XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
+ can't be performed, or XML_NO_ATTRIBUTE if the attribute
+ doesn't exist. If successful, the result of the conversion
+ will be written to 'value'. If not successful, nothing will
+ be written to 'value'. This allows you to provide default
+ value:
+
+ @verbatim
+ int value = 10;
+ QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
+ @endverbatim
+ */
+ int QueryIntAttribute( const char* name, int* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryIntValue( _value ); }
+ /// See QueryIntAttribute()
+ int QueryUnsignedAttribute( const char* name, unsigned int* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryUnsignedValue( _value ); }
+ /// See QueryIntAttribute()
+ int QueryBoolAttribute( const char* name, bool* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryBoolValue( _value ); }
+ /// See QueryIntAttribute()
+ int QueryDoubleAttribute( const char* name, double* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryDoubleValue( _value ); }
+ /// See QueryIntAttribute()
+ int QueryFloatAttribute( const char* name, float* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryFloatValue( _value ); }
+
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, const char* _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, int _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, unsigned _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, bool _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, double _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
+
+ /**
+ Delete an attribute.
+ */
+ void DeleteAttribute( const char* name );
+
+ /// Return the first attribute in the list.
+ const XMLAttribute* FirstAttribute() const { return rootAttribute; }
+ /// Query a specific attribute in the list.
+ const XMLAttribute* FindAttribute( const char* name ) const;
+
+ /** Convenience function for easy access to the text inside an element. Although easy
+ and concise, GetText() is limited compared to getting the TiXmlText child
+ and accessing it directly.
+
+ If the first child of 'this' is a TiXmlText, the GetText()
+ returns the character string of the Text node, else null is returned.
+
+ This is a convenient method for getting the text of simple contained text:
+ @verbatim
+ <foo>This is text</foo>
+ const char* str = fooElement->GetText();
+ @endverbatim
+
+ 'str' will be a pointer to "This is text".
+
+ Note that this function can be misleading. If the element foo was created from
+ this XML:
+ @verbatim
+ <foo><b>This is text</b></foo>
+ @endverbatim
+
+ then the value of str would be null. The first child node isn't a text node, it is
+ another element. From this XML:
+ @verbatim
+ <foo>This is <b>text</b></foo>
+ @endverbatim
+ GetText() will return "This is ".
+ */
+ const char* GetText() const;
+
+ /**
+ Convenience method to query the value of a child text node. This is probably best
+ shown by example. Given you have a document is this form:
+ @verbatim
+ <point>
+ <x>1</x>
+ <y>1.4</y>
+ </point>
+ @endverbatim
+
+ The QueryIntText() and similar functions provide a safe and easier way to get to the
+ "value" of x and y.
+
+ @verbatim
+ int x = 0;
+ float y = 0; // types of x and y are contrived for example
+ const XMLElement* xElement = pointElement->FirstChildElement( "x" );
+ const XMLElement* yElement = pointElement->FirstChildElement( "y" );
+ xElement->QueryIntText( &x );
+ yElement->QueryFloatText( &y );
+ @endverbatim
+
+ @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
+ to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
+
+ */
+ int QueryIntText( int* _value ) const;
+ /// See QueryIntText()
+ int QueryUnsignedText( unsigned* _value ) const;
+ /// See QueryIntText()
+ int QueryBoolText( bool* _value ) const;
+ /// See QueryIntText()
+ int QueryDoubleText( double* _value ) const;
+ /// See QueryIntText()
+ int QueryFloatText( float* _value ) const;
+
+ // internal:
+ enum {
+ OPEN, // <foo>
+ CLOSED, // <foo/>
+ CLOSING // </foo>
+ };
+ int ClosingType() const { return closingType; }
+ char* ParseDeep( char* p, StrPair* endTag );
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+private:
+ XMLElement( XMLDocument* doc );
+ virtual ~XMLElement();
+ XMLElement( const XMLElement& ); // not supported
+ void operator=( const XMLElement& ); // not supported
+
+ XMLAttribute* FindAttribute( const char* name );
+ XMLAttribute* FindOrCreateAttribute( const char* name );
+ //void LinkAttribute( XMLAttribute* attrib );
+ char* ParseAttributes( char* p );
+
+ int closingType;
+ // The attribute list is ordered; there is no 'lastAttribute'
+ // because the list needs to be scanned for dupes before adding
+ // a new attribute.
+ XMLAttribute* rootAttribute;
+};
+
+
+/** A Document binds together all the functionality.
+ It can be saved, loaded, and printed to the screen.
+ All Nodes are connected and allocated to a Document.
+ If the Document is deleted, all its Nodes are also deleted.
+*/
+class XMLDocument : public XMLNode
+{
+ friend class XMLElement;
+public:
+ /// constructor
+ XMLDocument( bool processEntities = true );
+ ~XMLDocument();
+
+ virtual XMLDocument* ToDocument() { return this; }
+ virtual const XMLDocument* ToDocument() const { return this; }
+
+ /**
+ Parse an XML file from a character string.
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ int Parse( const char* xml );
+
+ /**
+ Load an XML file from disk.
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ int LoadFile( const char* filename );
+
+ /**
+ Load an XML file from disk. You are responsible
+ for providing and closing the FILE*.
+
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ int LoadFile( FILE* );
+
+ /**
+ Save the XML file to disk.
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ int SaveFile( const char* filename );
+
+ /**
+ Save the XML file to disk. You are responsible
+ for providing and closing the FILE*.
+
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ int SaveFile( FILE* );
+
+ bool ProcessEntities() const { return processEntities; }
+
+ /**
+ Returns true if this document has a leading Byte Order Mark of UTF8.
+ */
+ bool HasBOM() const { return writeBOM; }
+ /** Sets whether to write the BOM when writing the file.
+ */
+ void SetBOM( bool useBOM ) { writeBOM = useBOM; }
+
+ /** Return the root element of DOM. Equivalent to FirstChildElement().
+ To get the first node, use FirstChild().
+ */
+ XMLElement* RootElement() { return FirstChildElement(); }
+ const XMLElement* RootElement() const { return FirstChildElement(); }
+
+ /** Print the Document. If the Printer is not provided, it will
+ print to stdout. If you provide Printer, this can print to a file:
+ @verbatim
+ XMLPrinter printer( fp );
+ doc.Print( &printer );
+ @endverbatim
+
+ Or you can use a printer to print to memory:
+ @verbatim
+ XMLPrinter printer;
+ doc->Print( &printer );
+ // printer.CStr() has a const char* to the XML
+ @endverbatim
+ */
+ void Print( XMLPrinter* streamer=0 );
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ /**
+ Create a new Element associated with
+ this Document. The memory for the Element
+ is managed by the Document.
+ */
+ XMLElement* NewElement( const char* name );
+ /**
+ Create a new Comment associated with
+ this Document. The memory for the Comment
+ is managed by the Document.
+ */
+ XMLComment* NewComment( const char* comment );
+ /**
+ Create a new Text associated with
+ this Document. The memory for the Text
+ is managed by the Document.
+ */
+ XMLText* NewText( const char* text );
+ /**
+ Create a new Declaration associated with
+ this Document. The memory for the object
+ is managed by the Document.
+
+ If the 'text' param is null, the standard
+ declaration is used.:
+ @verbatim
+ <?xml version="1.0" encoding="UTF-8"?>
+ @endverbatim
+ */
+ XMLDeclaration* NewDeclaration( const char* text=0 );
+ /**
+ Create a new Unknown associated with
+ this Document. The memory for the object
+ is managed by the Document.
+ */
+ XMLUnknown* NewUnknown( const char* text );
+
+ /**
+ Delete a node associated with this document.
+ It will be unlinked from the DOM.
+ */
+ void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
+
+ void SetError( int error, const char* str1, const char* str2 );
+
+ /// Return true if there was an error parsing the document.
+ bool Error() const { return errorID != XML_NO_ERROR; }
+ /// Return the errorID.
+ int ErrorID() const { return errorID; }
+ /// Return a possibly helpful diagnostic location or string.
+ const char* GetErrorStr1() const { return errorStr1; }
+ /// Return a possibly helpful secondary diagnostic location or string.
+ const char* GetErrorStr2() const { return errorStr2; }
+ /// If there is an error, print it to stdout.
+ void PrintError() const;
+
+ // internal
+ char* Identify( char* p, XMLNode** node );
+
+ virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
+ virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
+
+private:
+ XMLDocument( const XMLDocument& ); // not supported
+ void operator=( const XMLDocument& ); // not supported
+ void InitDocument();
+
+ bool writeBOM;
+ bool processEntities;
+ int errorID;
+ const char* errorStr1;
+ const char* errorStr2;
+ char* charBuffer;
+
+ MemPoolT< sizeof(XMLElement) > elementPool;
+ MemPoolT< sizeof(XMLAttribute) > attributePool;
+ MemPoolT< sizeof(XMLText) > textPool;
+ MemPoolT< sizeof(XMLComment) > commentPool;
+};
+
+
+/**
+ A XMLHandle is a class that wraps a node pointer with null checks; this is
+ an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
+ DOM structure. It is a separate utility class.
+
+ Take an example:
+ @verbatim
+ <Document>
+ <Element attributeA = "valueA">
+ <Child attributeB = "value1" />
+ <Child attributeB = "value2" />
+ </Element>
+ </Document>
+ @endverbatim
+
+ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
+ easy to write a *lot* of code that looks like:
+
+ @verbatim
+ XMLElement* root = document.FirstChildElement( "Document" );
+ if ( root )
+ {
+ XMLElement* element = root->FirstChildElement( "Element" );
+ if ( element )
+ {
+ XMLElement* child = element->FirstChildElement( "Child" );
+ if ( child )
+ {
+ XMLElement* child2 = child->NextSiblingElement( "Child" );
+ if ( child2 )
+ {
+ // Finally do something useful.
+ @endverbatim
+
+ And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
+ of such code. A XMLHandle checks for null pointers so it is perfectly safe
+ and correct to use:
+
+ @verbatim
+ XMLHandle docHandle( &document );
+ XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
+ if ( child2 )
+ {
+ // do something useful
+ @endverbatim
+
+ Which is MUCH more concise and useful.
+
+ It is also safe to copy handles - internally they are nothing more than node pointers.
+ @verbatim
+ XMLHandle handleCopy = handle;
+ @endverbatim
+
+ See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
+*/
+class XMLHandle
+{
+public:
+ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+ XMLHandle( XMLNode* _node ) { node = _node; }
+ /// Create a handle from a node.
+ XMLHandle( XMLNode& _node ) { node = &_node; }
+ /// Copy constructor
+ XMLHandle( const XMLHandle& ref ) { node = ref.node; }
+ /// Assignment
+ XMLHandle& operator=( const XMLHandle& ref ) { node = ref.node; return *this; }
+
+ /// Get the first child of this handle.
+ XMLHandle FirstChild() { return XMLHandle( node ? node->FirstChild() : 0 ); }
+ /// Get the first child element of this handle.
+ XMLHandle FirstChildElement( const char* value=0 ) { return XMLHandle( node ? node->FirstChildElement( value ) : 0 ); }
+ /// Get the last child of this handle.
+ XMLHandle LastChild() { return XMLHandle( node ? node->LastChild() : 0 ); }
+ /// Get the last child element of this handle.
+ XMLHandle LastChildElement( const char* _value=0 ) { return XMLHandle( node ? node->LastChildElement( _value ) : 0 ); }
+ /// Get the previous sibling of this handle.
+ XMLHandle PreviousSibling() { return XMLHandle( node ? node->PreviousSibling() : 0 ); }
+ /// Get the previous sibling element of this handle.
+ XMLHandle PreviousSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
+ /// Get the next sibling of this handle.
+ XMLHandle NextSibling() { return XMLHandle( node ? node->NextSibling() : 0 ); }
+ /// Get the next sibling element of this handle.
+ XMLHandle NextSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
+
+ /// Safe cast to XMLNode. This can return null.
+ XMLNode* ToNode() { return node; }
+ /// Safe cast to XMLElement. This can return null.
+ XMLElement* ToElement() { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+ /// Safe cast to XMLText. This can return null.
+ XMLText* ToText() { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+ /// Safe cast to XMLUnknown. This can return null.
+ XMLUnknown* ToUnknown() { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+ /// Safe cast to XMLDeclaration. This can return null.
+ XMLDeclaration* ToDeclaration() { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
+
+private:
+ XMLNode* node;
+};
+
+
+/**
+ A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
+ same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
+*/
+class XMLConstHandle
+{
+public:
+ XMLConstHandle( const XMLNode* _node ) { node = _node; }
+ XMLConstHandle( const XMLNode& _node ) { node = &_node; }
+ XMLConstHandle( const XMLConstHandle& ref ) { node = ref.node; }
+
+ XMLConstHandle& operator=( const XMLConstHandle& ref ) { node = ref.node; return *this; }
+
+ const XMLConstHandle FirstChild() const { return XMLConstHandle( node ? node->FirstChild() : 0 ); }
+ const XMLConstHandle FirstChildElement( const char* value=0 ) const { return XMLConstHandle( node ? node->FirstChildElement( value ) : 0 ); }
+ const XMLConstHandle LastChild() const { return XMLConstHandle( node ? node->LastChild() : 0 ); }
+ const XMLConstHandle LastChildElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->LastChildElement( _value ) : 0 ); }
+ const XMLConstHandle PreviousSibling() const { return XMLConstHandle( node ? node->PreviousSibling() : 0 ); }
+ const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
+ const XMLConstHandle NextSibling() const { return XMLConstHandle( node ? node->NextSibling() : 0 ); }
+ const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
+
+
+ const XMLNode* ToNode() const { return node; }
+ const XMLElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+ const XMLText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+ const XMLUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+ const XMLDeclaration* ToDeclaration() const { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
+
+private:
+ const XMLNode* node;
+};
+
+
+/**
+ Printing functionality. The XMLPrinter gives you more
+ options than the XMLDocument::Print() method.
+
+ It can:
+ -# Print to memory.
+ -# Print to a file you provide.
+ -# Print XML without a XMLDocument.
+
+ Print to Memory
+
+ @verbatim
+ XMLPrinter printer;
+ doc->Print( &printer );
+ SomeFunction( printer.CStr() );
+ @endverbatim
+
+ Print to a File
+
+ You provide the file pointer.
+ @verbatim
+ XMLPrinter printer( fp );
+ doc.Print( &printer );
+ @endverbatim
+
+ Print without a XMLDocument
+
+ When loading, an XML parser is very useful. However, sometimes
+ when saving, it just gets in the way. The code is often set up
+ for streaming, and constructing the DOM is just overhead.
+
+ The Printer supports the streaming case. The following code
+ prints out a trivially simple XML file without ever creating
+ an XML document.
+
+ @verbatim
+ XMLPrinter printer( fp );
+ printer.OpenElement( "foo" );
+ printer.PushAttribute( "foo", "bar" );
+ printer.CloseElement();
+ @endverbatim
+*/
+class XMLPrinter : public XMLVisitor
+{
+public:
+ /** Construct the printer. If the FILE* is specified,
+ this will print to the FILE. Else it will print
+ to memory, and the result is available in CStr().
+ If 'compact' is set to true, then output is created
+ with only required whitespace and newlines.
+ */
+ XMLPrinter( FILE* file=0, bool compact = false );
+ ~XMLPrinter() {}
+
+ /** If streaming, write the BOM and declaration. */
+ void PushHeader( bool writeBOM, bool writeDeclaration );
+ /** If streaming, start writing an element.
+ The element must be closed with CloseElement()
+ */
+ void OpenElement( const char* name );
+ /// If streaming, add an attribute to an open element.
+ void PushAttribute( const char* name, const char* value );
+ void PushAttribute( const char* name, int value );
+ void PushAttribute( const char* name, unsigned value );
+ void PushAttribute( const char* name, bool value );
+ void PushAttribute( const char* name, double value );
+ /// If streaming, close the Element.
+ void CloseElement();
+
+ /// Add a text node.
+ void PushText( const char* text, bool cdata=false );
+ /// Add a text node from an integer.
+ void PushText( int value );
+ /// Add a text node from an unsigned.
+ void PushText( unsigned value );
+ /// Add a text node from a bool.
+ void PushText( bool value );
+ /// Add a text node from a float.
+ void PushText( float value );
+ /// Add a text node from a double.
+ void PushText( double value );
+
+ /// Add a comment
+ void PushComment( const char* comment );
+
+ void PushDeclaration( const char* value );
+ void PushUnknown( const char* value );
+
+ virtual bool VisitEnter( const XMLDocument& /*doc*/ );
+ virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
+
+ virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
+ virtual bool VisitExit( const XMLElement& element );
+
+ virtual bool Visit( const XMLText& text );
+ virtual bool Visit( const XMLComment& comment );
+ virtual bool Visit( const XMLDeclaration& declaration );
+ virtual bool Visit( const XMLUnknown& unknown );
+
+ /**
+ If in print to memory mode, return a pointer to
+ the XML file in memory.
+ */
+ const char* CStr() const { return buffer.Mem(); }
+ /**
+ If in print to memory mode, return the size
+ of the XML file in memory. (Note the size returned
+ includes the terminating null.)
+ */
+ int CStrSize() const { return buffer.Size(); }
+
+private:
+ void SealElement();
+ void PrintSpace( int depth );
+ void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
+ void Print( const char* format, ... );
+
+ bool elementJustOpened;
+ bool firstElement;
+ FILE* fp;
+ int depth;
+ int textDepth;
+ bool processEntities;
+ bool compactMode;
+
+ enum {
+ ENTITY_RANGE = 64,
+ BUF_SIZE = 200
+ };
+ bool entityFlag[ENTITY_RANGE];
+ bool restrictedEntityFlag[ENTITY_RANGE];
+
+ DynArray< const char*, 10 > stack;
+ DynArray< char, 20 > buffer;
+#ifdef _MSC_VER
+ DynArray< char, 20 > accumulator;
+#endif
+};
+
+
+} // tinyxml2
+
+
+#endif // TINYXML2_INCLUDED
OpenPOWER on IntegriCloud