/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_
#define DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_

#include "Dalvik.h"
#include "compiler/CompilerInternals.h"

/*
 * For both JIT & interpreter:
 *     esi is Dalvik FP
 *     ebp is native FP
 *     esp is native SP
 *
 * For interpreter:
 *     edi is Dalvik PC (rPC)
 *     ebx is rINST
 *
 * For JIT:
 *     eax, edx, ecx are scratch & caller-save
 *     ebx, edi are scratch & callee-save
 *
 * Calling conventions:
 *     32-bit return in eax
 *     64-bit return in edx:eax
 *     fp on top of fp stack st(0)
 *     Parameters passed on stack, pushed left to right
 *     On entry to target, first parm is at 4(%esp).
 *     For performance, we'll maintain 16-byte stack alignment
 *
 * When transitioning from code cache to interp:
 *       materialize Dalvik PC of target in rPC/%edx
 *       Preload rINST/%ebx such that high 24 bits are zero and
 *           bl contains the non-opcode 8-bits of the 16-bit Dalvik
 *           instruction at (rPC)
 */

/* Keys for target-specific scheduling and other optimizations here */
typedef enum X86TargetOptHints {
   kMaxHoistDistance,
} X86TargetOptHints;

 /*
 * Data structure tracking the mapping between a Dalvik register (pair) and a
 * native register (pair). The idea is to reuse the previously loaded value
 * if possible, otherwise to keep the value in a native register as long as
 * possible.
 */
typedef struct RegisterInfo {
    int reg;                    // Reg number
    bool inUse;                 // Has it been allocated?
    bool pair;                  // Part of a register pair?
    int partner;                // If pair, other reg of pair
    bool live;                  // Is there an associated SSA name?
    bool dirty;                 // If live, is it dirty?
    int sReg;                   // Name of live value
    struct LIR *defStart;       // Starting inst in last def sequence
    struct LIR *defEnd;         // Ending inst in last def sequence
} RegisterInfo;

typedef struct RegisterPool {
    BitVector *nullCheckedRegs; // Track which registers have been null-checked
    int numCoreTemps;
    RegisterInfo *coreTemps;
    int nextCoreTemp;
    int numFPTemps;
    RegisterInfo *FPTemps;
    int nextFPTemp;
} RegisterPool;

typedef enum OpSize {
    kWord,
    kLong,
    kSingle,
    kDouble,
    kUnsignedHalf,
    kSignedHalf,
    kUnsignedByte,
    kSignedByte,
} OpSize;

typedef enum OpKind {
    kOpMov,
    kOpCmp,
    kOpLsl,
    kOpLsr,
    kOpAsr,
    kOpRor,
    kOpNot,
    kOpAnd,
    kOpOr,
    kOpXor,
    kOpNeg,
    kOpAdd,
    kOpAdc,
    kOpSub,
    kOpSbc,
    kOpMul,
    kOpDiv,
    kOpRem,
    kOpTst,
    kOpCall,
    kOpPush,
    kOpPop,
    kOp2Char,
    kOp2Short,
    kOp2Byte,
    kOpCondBr,
    kOpUncondBr,
} OpKind;

#define FP_REG_OFFSET 8

typedef enum NativeRegisterPool {
    rEAX = 0,
    rECX = 1,
    rEDX = 2,
    rEBX = 3,
    rESP = 4,
    rEBP = 5,
    rESI = 6,
    rEDI = 7,
    rXMM0 = 0 + FP_REG_OFFSET,
    rXMM1 = 1 + FP_REG_OFFSET,
    rXMM2 = 2 + FP_REG_OFFSET,
    rXMM3 = 3 + FP_REG_OFFSET,
    rXMM4 = 4 + FP_REG_OFFSET,
    rXMM5 = 5 + FP_REG_OFFSET,
    rXMM6 = 6 + FP_REG_OFFSET,
    rXMM7 = 7 + FP_REG_OFFSET,
} NativeRegisterPool;

#define rPC rEDI
#define rFP rESI
#define rINST rEBX

#define OUT_ARG0 0
#define OUT_ARG1 4
#define OUT_ARG2 8
#define OUT_ARG3 12
#define OUT_ARG4 16

typedef struct X86LIR {
    LIR generic;
    //X86Opcode opcode;
    int operands[4];    // [0..3] = [dest, src1, src2, extra]
    bool isNop;         // LIR is optimized away
    bool branchInsertSV;// mark for insertion of branch before this instruction,
                        // used to identify mem ops for self verification mode
    int age;            // default is 0, set lazily by the optimizer
    int aliasInfo;      // For Dalvik register access & litpool disambiguation
    u8 useMask;         // Resource mask for use
    u8 defMask;         // Resource mask for def
} X86LIR;

/* Utility macros to traverse the LIR/X86LIR list */
#define NEXT_LIR(lir) ((X86LIR *) lir->generic.next)
#define PREV_LIR(lir) ((X86LIR *) lir->generic.prev)

#define NEXT_LIR_LVALUE(lir) (lir)->generic.next
#define PREV_LIR_LVALUE(lir) (lir)->generic.prev

#define CHAIN_CELL_OFFSET_TAG   0xcdab

#define CHAIN_CELL_NORMAL_SIZE 12
#define CHAIN_CELL_PREDICTED_SIZE 16

#endif  // DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_