Home | History | Annotate | Download | only in arm
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef DALVIK_VM_COMPILER_CODEGEN_ARM_ARMLIR_H_
     18 #define DALVIK_VM_COMPILER_CODEGEN_ARM_ARMLIR_H_
     19 
     20 #include "Dalvik.h"
     21 #include "compiler/CompilerInternals.h"
     22 
     23 /*
     24  * r0, r1, r2, r3 are always scratch
     25  * r4 (rPC) is scratch for Jit, but most be restored when resuming interp
     26  * r5 (rFP) is reserved [holds Dalvik frame pointer]
     27  * r6 (rSELF) is reserved [holds current &Thread]
     28  * r7 (rINST) is scratch for Jit
     29  * r8 (rIBASE) is scratch for Jit, but must be restored when resuming interp
     30  * r9 is reserved
     31  * r10 is always scratch
     32  * r11 (fp) used by gcc unless -fomit-frame-pointer set [available for jit?]
     33  * r12 is always scratch
     34  * r13 (sp) is reserved
     35  * r14 (lr) is scratch for Jit
     36  * r15 (pc) is reserved
     37  *
     38  * Preserved across C calls: r4, r5, r6, r7, r8, r10, r11
     39  * Trashed across C calls: r0, r1, r2, r3, r12, r14
     40  *
     41  * Floating pointer registers
     42  * s0-s31
     43  * d0-d15, where d0={s0,s1}, d1={s2,s3}, ... , d15={s30,s31}
     44  *
     45  * s16-s31 (d8-d15) preserved across C calls
     46  * s0-s15 (d0-d7) trashed across C calls
     47  *
     48  * For Thumb code use:
     49  *       r0, r1, r2, r3 to hold operands/results
     50  *       r4, r7 for temps
     51  *
     52  * For Thumb2 code use:
     53  *       r0, r1, r2, r3, r8, r9, r10, r11, r12, r14 for operands/results
     54  *       r4, r7 for temps
     55  *       s16-s31/d8-d15 for operands/results
     56  *       s0-s15/d0-d7 for temps
     57  *
     58  * When transitioning from code cache to interp:
     59  *       restore rIBASE
     60  *       restore rPC
     61  *       restore r11?
     62  */
     63 
     64 /* Offset to distingish FP regs */
     65 #define FP_REG_OFFSET 32
     66 /* Offset to distinguish DP FP regs */
     67 #define FP_DOUBLE 64
     68 /* Reg types */
     69 #define REGTYPE(x) (x & (FP_REG_OFFSET | FP_DOUBLE))
     70 #define FPREG(x) ((x & FP_REG_OFFSET) == FP_REG_OFFSET)
     71 #define LOWREG(x) ((x & 0x7) == x)
     72 #define DOUBLEREG(x) ((x & FP_DOUBLE) == FP_DOUBLE)
     73 #define SINGLEREG(x) (FPREG(x) && !DOUBLEREG(x))
     74 /*
     75  * Note: the low register of a floating point pair is sufficient to
     76  * create the name of a double, but require both names to be passed to
     77  * allow for asserts to verify that the pair is consecutive if significant
     78  * rework is done in this area.  Also, it is a good reminder in the calling
     79  * code that reg locations always describe doubles as a pair of singles.
     80  */
     81 #define S2D(x,y) ((x) | FP_DOUBLE)
     82 /* Mask to strip off fp flags */
     83 #define FP_REG_MASK (FP_REG_OFFSET-1)
     84 /* non-existent Dalvik register */
     85 #define vNone   (-1)
     86 /* non-existant physical register */
     87 #define rNone   (-1)
     88 
     89 /* RegisterLocation templates return values (r0, or r0/r1) */
     90 #define LOC_C_RETURN {kLocPhysReg, 0, 0, r0, 0, -1}
     91 #define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, r0, r1, -1}
     92 /* RegisterLocation templates for interpState->retVal; */
     93 #define LOC_DALVIK_RETURN_VAL {kLocRetval, 0, 0, 0, 0, -1}
     94 #define LOC_DALVIK_RETURN_VAL_WIDE {kLocRetval, 1, 0, 0, 0, -1}
     95 
     96  /*
     97  * Data structure tracking the mapping between a Dalvik register (pair) and a
     98  * native register (pair). The idea is to reuse the previously loaded value
     99  * if possible, otherwise to keep the value in a native register as long as
    100  * possible.
    101  */
    102 typedef struct RegisterInfo {
    103     int reg;                    // Reg number
    104     bool inUse;                 // Has it been allocated?
    105     bool pair;                  // Part of a register pair?
    106     int partner;                // If pair, other reg of pair
    107     bool live;                  // Is there an associated SSA name?
    108     bool dirty;                 // If live, is it dirty?
    109     int sReg;                   // Name of live value
    110     struct LIR *defStart;       // Starting inst in last def sequence
    111     struct LIR *defEnd;         // Ending inst in last def sequence
    112 } RegisterInfo;
    113 
    114 typedef struct RegisterPool {
    115     BitVector *nullCheckedRegs; // Track which registers have been null-checked
    116     int numCoreTemps;
    117     RegisterInfo *coreTemps;
    118     int nextCoreTemp;
    119     int numFPTemps;
    120     RegisterInfo *FPTemps;
    121     int nextFPTemp;
    122 } RegisterPool;
    123 
    124 typedef enum ResourceEncodingPos {
    125     kGPReg0     = 0,
    126     kRegSP      = 13,
    127     kRegLR      = 14,
    128     kRegPC      = 15,
    129     kFPReg0     = 16,
    130     kRegEnd     = 48,
    131     kCCode      = kRegEnd,
    132     kFPStatus,          // FP status word
    133     // The following four bits are for memory disambiguation
    134     kDalvikReg,         // 1 Dalvik Frame (can be fully disambiguated)
    135     kLiteral,           // 2 Literal pool (can be fully disambiguated)
    136     kHeapRef,           // 3 Somewhere on the heap (alias with any other heap)
    137     kMustNotAlias,      // 4 Guaranteed to be non-alias (eg *(r6+x))
    138 } ResourceEncodingPos;
    139 
    140 #define ENCODE_REG_LIST(N)      ((u8) N)
    141 #define ENCODE_REG_SP           (1ULL << kRegSP)
    142 #define ENCODE_REG_LR           (1ULL << kRegLR)
    143 #define ENCODE_REG_PC           (1ULL << kRegPC)
    144 #define ENCODE_CCODE            (1ULL << kCCode)
    145 #define ENCODE_FP_STATUS        (1ULL << kFPStatus)
    146 
    147 /* Abstract memory locations */
    148 #define ENCODE_DALVIK_REG       (1ULL << kDalvikReg)
    149 #define ENCODE_LITERAL          (1ULL << kLiteral)
    150 #define ENCODE_HEAP_REF         (1ULL << kHeapRef)
    151 #define ENCODE_MUST_NOT_ALIAS   (1ULL << kMustNotAlias)
    152 
    153 #define ENCODE_ALL              (~0ULL)
    154 #define ENCODE_MEM              (ENCODE_DALVIK_REG | ENCODE_LITERAL | \
    155                                  ENCODE_HEAP_REF | ENCODE_MUST_NOT_ALIAS)
    156 
    157 #define DECODE_ALIAS_INFO_REG(X)        (X & 0xffff)
    158 #define DECODE_ALIAS_INFO_WIDE(X)       ((X & 0x80000000) ? 1 : 0)
    159 
    160 typedef enum OpSize {
    161     kWord,
    162     kLong,
    163     kSingle,
    164     kDouble,
    165     kUnsignedHalf,
    166     kSignedHalf,
    167     kUnsignedByte,
    168     kSignedByte,
    169 } OpSize;
    170 
    171 typedef enum OpKind {
    172     kOpMov,
    173     kOpMvn,
    174     kOpCmp,
    175     kOpLsl,
    176     kOpLsr,
    177     kOpAsr,
    178     kOpRor,
    179     kOpNot,
    180     kOpAnd,
    181     kOpOr,
    182     kOpXor,
    183     kOpNeg,
    184     kOpAdd,
    185     kOpAdc,
    186     kOpSub,
    187     kOpSbc,
    188     kOpRsub,
    189     kOpMul,
    190     kOpDiv,
    191     kOpRem,
    192     kOpBic,
    193     kOpCmn,
    194     kOpTst,
    195     kOpBkpt,
    196     kOpBlx,
    197     kOpPush,
    198     kOpPop,
    199     kOp2Char,
    200     kOp2Short,
    201     kOp2Byte,
    202     kOpCondBr,
    203     kOpUncondBr,
    204 } OpKind;
    205 
    206 /*
    207  * Annotate special-purpose core registers:
    208  *   - VM: r4PC, r5FP, and r6SELF
    209  *   - ARM architecture: r13sp, r14lr, and r15pc
    210  *
    211  * rPC, rFP, and rSELF are for architecture-independent code to use.
    212  */
    213 typedef enum NativeRegisterPool {
    214     r0     = 0,
    215     r1     = 1,
    216     r2     = 2,
    217     r3     = 3,
    218     rPC    = 4,
    219     r4PC   = rPC,
    220     rFP    = 5,
    221     r5FP   = rFP,
    222     rSELF  = 6,
    223     r6SELF = rSELF,
    224     r7     = 7,
    225     r8     = 8,
    226     r9     = 9,
    227     r10    = 10,
    228     r11    = 11,
    229     r12    = 12,
    230     r13sp  = 13,
    231     r14lr  = 14,
    232     r15pc  = 15,
    233     fr0  =  0 + FP_REG_OFFSET,
    234     fr1  =  1 + FP_REG_OFFSET,
    235     fr2  =  2 + FP_REG_OFFSET,
    236     fr3  =  3 + FP_REG_OFFSET,
    237     fr4  =  4 + FP_REG_OFFSET,
    238     fr5  =  5 + FP_REG_OFFSET,
    239     fr6  =  6 + FP_REG_OFFSET,
    240     fr7  =  7 + FP_REG_OFFSET,
    241     fr8  =  8 + FP_REG_OFFSET,
    242     fr9  =  9 + FP_REG_OFFSET,
    243     fr10 = 10 + FP_REG_OFFSET,
    244     fr11 = 11 + FP_REG_OFFSET,
    245     fr12 = 12 + FP_REG_OFFSET,
    246     fr13 = 13 + FP_REG_OFFSET,
    247     fr14 = 14 + FP_REG_OFFSET,
    248     fr15 = 15 + FP_REG_OFFSET,
    249     fr16 = 16 + FP_REG_OFFSET,
    250     fr17 = 17 + FP_REG_OFFSET,
    251     fr18 = 18 + FP_REG_OFFSET,
    252     fr19 = 19 + FP_REG_OFFSET,
    253     fr20 = 20 + FP_REG_OFFSET,
    254     fr21 = 21 + FP_REG_OFFSET,
    255     fr22 = 22 + FP_REG_OFFSET,
    256     fr23 = 23 + FP_REG_OFFSET,
    257     fr24 = 24 + FP_REG_OFFSET,
    258     fr25 = 25 + FP_REG_OFFSET,
    259     fr26 = 26 + FP_REG_OFFSET,
    260     fr27 = 27 + FP_REG_OFFSET,
    261     fr28 = 28 + FP_REG_OFFSET,
    262     fr29 = 29 + FP_REG_OFFSET,
    263     fr30 = 30 + FP_REG_OFFSET,
    264     fr31 = 31 + FP_REG_OFFSET,
    265     dr0 = fr0 + FP_DOUBLE,
    266     dr1 = fr2 + FP_DOUBLE,
    267     dr2 = fr4 + FP_DOUBLE,
    268     dr3 = fr6 + FP_DOUBLE,
    269     dr4 = fr8 + FP_DOUBLE,
    270     dr5 = fr10 + FP_DOUBLE,
    271     dr6 = fr12 + FP_DOUBLE,
    272     dr7 = fr14 + FP_DOUBLE,
    273     dr8 = fr16 + FP_DOUBLE,
    274     dr9 = fr18 + FP_DOUBLE,
    275     dr10 = fr20 + FP_DOUBLE,
    276     dr11 = fr22 + FP_DOUBLE,
    277     dr12 = fr24 + FP_DOUBLE,
    278     dr13 = fr26 + FP_DOUBLE,
    279     dr14 = fr28 + FP_DOUBLE,
    280     dr15 = fr30 + FP_DOUBLE,
    281 } NativeRegisterPool;
    282 
    283 /* Shift encodings */
    284 typedef enum ArmShiftEncodings {
    285     kArmLsl = 0x0,
    286     kArmLsr = 0x1,
    287     kArmAsr = 0x2,
    288     kArmRor = 0x3
    289 } ArmShiftEncodings;
    290 
    291 /* Thumb condition encodings */
    292 typedef enum ArmConditionCode {
    293     kArmCondEq = 0x0,    /* 0000 */
    294     kArmCondNe = 0x1,    /* 0001 */
    295     kArmCondCs = 0x2,    /* 0010 */
    296     kArmCondCc = 0x3,    /* 0011 */
    297     kArmCondMi = 0x4,    /* 0100 */
    298     kArmCondPl = 0x5,    /* 0101 */
    299     kArmCondVs = 0x6,    /* 0110 */
    300     kArmCondVc = 0x7,    /* 0111 */
    301     kArmCondHi = 0x8,    /* 1000 */
    302     kArmCondLs = 0x9,    /* 1001 */
    303     kArmCondGe = 0xa,    /* 1010 */
    304     kArmCondLt = 0xb,    /* 1011 */
    305     kArmCondGt = 0xc,    /* 1100 */
    306     kArmCondLe = 0xd,    /* 1101 */
    307     kArmCondAl = 0xe,    /* 1110 */
    308     kArmCondNv = 0xf,    /* 1111 */
    309 } ArmConditionCode;
    310 
    311 #define isPseudoOpcode(opcode) ((int)(opcode) < 0)
    312 
    313 /*
    314  * The following enum defines the list of supported Thumb instructions by the
    315  * assembler. Their corresponding snippet positions will be defined in
    316  * Assemble.c.
    317  */
    318 typedef enum ArmOpcode {
    319     kArmChainingCellBottom = -18,
    320     kArmPseudoBarrier = -17,
    321     kArmPseudoExtended = -16,
    322     kArmPseudoSSARep = -15,
    323     kArmPseudoEntryBlock = -14,
    324     kArmPseudoExitBlock = -13,
    325     kArmPseudoTargetLabel = -12,
    326     kArmPseudoChainingCellBackwardBranch = -11,
    327     kArmPseudoChainingCellHot = -10,
    328     kArmPseudoChainingCellInvokePredicted = -9,
    329     kArmPseudoChainingCellInvokeSingleton = -8,
    330     kArmPseudoChainingCellNormal = -7,
    331     kArmPseudoDalvikByteCodeBoundary = -6,
    332     kArmPseudoPseudoAlign4 = -5,
    333     kArmPseudoPCReconstructionCell = -4,
    334     kArmPseudoPCReconstructionBlockLabel = -3,
    335     kArmPseudoEHBlockLabel = -2,
    336     kArmPseudoNormalBlockLabel = -1,
    337     /************************************************************************/
    338     kArm16BitData,       /* DATA   [0] rd[15..0] */
    339     kThumbAdcRR,         /* adc     [0100000101] rm[5..3] rd[2..0] */
    340     kThumbAddRRI3,       /* add(1)  [0001110] imm_3[8..6] rn[5..3] rd[2..0]*/
    341     kThumbAddRI8,        /* add(2)  [00110] rd[10..8] imm_8[7..0] */
    342     kThumbAddRRR,        /* add(3)  [0001100] rm[8..6] rn[5..3] rd[2..0] */
    343     kThumbAddRRLH,       /* add(4)  [01000100] H12[01] rm[5..3] rd[2..0] */
    344     kThumbAddRRHL,       /* add(4)  [01001000] H12[10] rm[5..3] rd[2..0] */
    345     kThumbAddRRHH,       /* add(4)  [01001100] H12[11] rm[5..3] rd[2..0] */
    346     kThumbAddPcRel,      /* add(5)  [10100] rd[10..8] imm_8[7..0] */
    347     kThumbAddSpRel,      /* add(6)  [10101] rd[10..8] imm_8[7..0] */
    348     kThumbAddSpI7,       /* add(7)  [101100000] imm_7[6..0] */
    349     kThumbAndRR,         /* and     [0100000000] rm[5..3] rd[2..0] */
    350     kThumbAsrRRI5,       /* asr(1)  [00010] imm_5[10..6] rm[5..3] rd[2..0] */
    351     kThumbAsrRR,         /* asr(2)  [0100000100] rs[5..3] rd[2..0] */
    352     kThumbBCond,         /* b(1)    [1101] cond[11..8] offset_8[7..0] */
    353     kThumbBUncond,       /* b(2)    [11100] offset_11[10..0] */
    354     kThumbBicRR,         /* bic     [0100001110] rm[5..3] rd[2..0] */
    355     kThumbBkpt,          /* bkpt    [10111110] imm_8[7..0] */
    356     kThumbBlx1,          /* blx(1)  [111] H[10] offset_11[10..0] */
    357     kThumbBlx2,          /* blx(1)  [111] H[01] offset_11[10..0] */
    358     kThumbBl1,           /* blx(1)  [111] H[10] offset_11[10..0] */
    359     kThumbBl2,           /* blx(1)  [111] H[11] offset_11[10..0] */
    360     kThumbBlxR,          /* blx(2)  [010001111] rm[6..3] [000] */
    361     kThumbBx,            /* bx      [010001110] H2[6..6] rm[5..3] SBZ[000] */
    362     kThumbCmnRR,         /* cmn     [0100001011] rm[5..3] rd[2..0] */
    363     kThumbCmpRI8,        /* cmp(1)  [00101] rn[10..8] imm_8[7..0] */
    364     kThumbCmpRR,         /* cmp(2)  [0100001010] rm[5..3] rd[2..0] */
    365     kThumbCmpLH,         /* cmp(3)  [01000101] H12[01] rm[5..3] rd[2..0] */
    366     kThumbCmpHL,         /* cmp(3)  [01000110] H12[10] rm[5..3] rd[2..0] */
    367     kThumbCmpHH,         /* cmp(3)  [01000111] H12[11] rm[5..3] rd[2..0] */
    368     kThumbEorRR,         /* eor     [0100000001] rm[5..3] rd[2..0] */
    369     kThumbLdmia,         /* ldmia   [11001] rn[10..8] reglist [7..0] */
    370     kThumbLdrRRI5,       /* ldr(1)  [01101] imm_5[10..6] rn[5..3] rd[2..0] */
    371     kThumbLdrRRR,        /* ldr(2)  [0101100] rm[8..6] rn[5..3] rd[2..0] */
    372     kThumbLdrPcRel,      /* ldr(3)  [01001] rd[10..8] imm_8[7..0] */
    373     kThumbLdrSpRel,      /* ldr(4)  [10011] rd[10..8] imm_8[7..0] */
    374     kThumbLdrbRRI5,      /* ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0] */
    375     kThumbLdrbRRR,       /* ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0] */
    376     kThumbLdrhRRI5,      /* ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0] */
    377     kThumbLdrhRRR,       /* ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0] */
    378     kThumbLdrsbRRR,      /* ldrsb   [0101011] rm[8..6] rn[5..3] rd[2..0] */
    379     kThumbLdrshRRR,      /* ldrsh   [0101111] rm[8..6] rn[5..3] rd[2..0] */
    380     kThumbLslRRI5,       /* lsl(1)  [00000] imm_5[10..6] rm[5..3] rd[2..0] */
    381     kThumbLslRR,         /* lsl(2)  [0100000010] rs[5..3] rd[2..0] */
    382     kThumbLsrRRI5,       /* lsr(1)  [00001] imm_5[10..6] rm[5..3] rd[2..0] */
    383     kThumbLsrRR,         /* lsr(2)  [0100000011] rs[5..3] rd[2..0] */
    384     kThumbMovImm,        /* mov(1)  [00100] rd[10..8] imm_8[7..0] */
    385     kThumbMovRR,         /* mov(2)  [0001110000] rn[5..3] rd[2..0] */
    386     kThumbMovRR_H2H,     /* mov(3)  [01000111] H12[11] rm[5..3] rd[2..0] */
    387     kThumbMovRR_H2L,     /* mov(3)  [01000110] H12[01] rm[5..3] rd[2..0] */
    388     kThumbMovRR_L2H,     /* mov(3)  [01000101] H12[10] rm[5..3] rd[2..0] */
    389     kThumbMul,           /* mul     [0100001101] rm[5..3] rd[2..0] */
    390     kThumbMvn,           /* mvn     [0100001111] rm[5..3] rd[2..0] */
    391     kThumbNeg,           /* neg     [0100001001] rm[5..3] rd[2..0] */
    392     kThumbOrr,           /* orr     [0100001100] rm[5..3] rd[2..0] */
    393     kThumbPop,           /* pop     [1011110] r[8..8] rl[7..0] */
    394     kThumbPush,          /* push    [1011010] r[8..8] rl[7..0] */
    395     kThumbRorRR,         /* ror     [0100000111] rs[5..3] rd[2..0] */
    396     kThumbSbc,           /* sbc     [0100000110] rm[5..3] rd[2..0] */
    397     kThumbStmia,         /* stmia   [11000] rn[10..8] reglist [7.. 0] */
    398     kThumbStrRRI5,       /* str(1)  [01100] imm_5[10..6] rn[5..3] rd[2..0] */
    399     kThumbStrRRR,        /* str(2)  [0101000] rm[8..6] rn[5..3] rd[2..0] */
    400     kThumbStrSpRel,      /* str(3)  [10010] rd[10..8] imm_8[7..0] */
    401     kThumbStrbRRI5,      /* strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0] */
    402     kThumbStrbRRR,       /* strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0] */
    403     kThumbStrhRRI5,      /* strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0] */
    404     kThumbStrhRRR,       /* strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0] */
    405     kThumbSubRRI3,       /* sub(1)  [0001111] imm_3[8..6] rn[5..3] rd[2..0]*/
    406     kThumbSubRI8,        /* sub(2)  [00111] rd[10..8] imm_8[7..0] */
    407     kThumbSubRRR,        /* sub(3)  [0001101] rm[8..6] rn[5..3] rd[2..0] */
    408     kThumbSubSpI7,       /* sub(4)  [101100001] imm_7[6..0] */
    409     kThumbSwi,           /* swi     [11011111] imm_8[7..0] */
    410     kThumbTst,           /* tst     [0100001000] rm[5..3] rn[2..0] */
    411     kThumb2Vldrs,        /* vldr low  sx [111011011001] rn[19..16] rd[15-12]
    412                                     [1010] imm_8[7..0] */
    413     kThumb2Vldrd,        /* vldr low  dx [111011011001] rn[19..16] rd[15-12]
    414                                     [1011] imm_8[7..0] */
    415     kThumb2Vmuls,        /* vmul vd, vn, vm [111011100010] rn[19..16]
    416                                     rd[15-12] [10100000] rm[3..0] */
    417     kThumb2Vmuld,        /* vmul vd, vn, vm [111011100010] rn[19..16]
    418                                     rd[15-12] [10110000] rm[3..0] */
    419     kThumb2Vstrs,        /* vstr low  sx [111011011000] rn[19..16] rd[15-12]
    420                                     [1010] imm_8[7..0] */
    421     kThumb2Vstrd,        /* vstr low  dx [111011011000] rn[19..16] rd[15-12]
    422                                     [1011] imm_8[7..0] */
    423     kThumb2Vsubs,        /* vsub vd, vn, vm [111011100011] rn[19..16]
    424                                     rd[15-12] [10100040] rm[3..0] */
    425     kThumb2Vsubd,        /* vsub vd, vn, vm [111011100011] rn[19..16]
    426                                     rd[15-12] [10110040] rm[3..0] */
    427     kThumb2Vadds,        /* vadd vd, vn, vm [111011100011] rn[19..16]
    428                                     rd[15-12] [10100000] rm[3..0] */
    429     kThumb2Vaddd,        /* vadd vd, vn, vm [111011100011] rn[19..16]
    430                                     rd[15-12] [10110000] rm[3..0] */
    431     kThumb2Vdivs,        /* vdiv vd, vn, vm [111011101000] rn[19..16]
    432                                     rd[15-12] [10100000] rm[3..0] */
    433     kThumb2Vdivd,        /* vdiv vd, vn, vm [111011101000] rn[19..16]
    434                                     rd[15-12] [10110000] rm[3..0] */
    435     kThumb2VcvtIF,       /* vcvt.F32 vd, vm [1110111010111000] vd[15..12]
    436                                     [10101100] vm[3..0] */
    437     kThumb2VcvtID,       /* vcvt.F64 vd, vm [1110111010111000] vd[15..12]
    438                                        [10111100] vm[3..0] */
    439     kThumb2VcvtFI,       /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12]
    440                                        [10101100] vm[3..0] */
    441     kThumb2VcvtDI,       /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12]
    442                                        [10111100] vm[3..0] */
    443     kThumb2VcvtFd,       /* vcvt.F64.F32 vd, vm [1110111010110111] vd[15..12]
    444                                        [10101100] vm[3..0] */
    445     kThumb2VcvtDF,       /* vcvt.F32.F64 vd, vm [1110111010110111] vd[15..12]
    446                                        [10111100] vm[3..0] */
    447     kThumb2Vsqrts,       /* vsqrt.f32 vd, vm [1110111010110001] vd[15..12]
    448                                        [10101100] vm[3..0] */
    449     kThumb2Vsqrtd,       /* vsqrt.f64 vd, vm [1110111010110001] vd[15..12]
    450                                        [10111100] vm[3..0] */
    451     kThumb2MovImmShift,  /* mov(T2) rd, #<const> [11110] i [00001001111]
    452                                        imm3 rd[11..8] imm8 */
    453     kThumb2MovImm16,     /* mov(T3) rd, #<const> [11110] i [0010100] imm4 [0]
    454                                        imm3 rd[11..8] imm8 */
    455     kThumb2StrRRI12,     /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
    456                                        rn[19..16] rt[15..12] imm12[11..0] */
    457     kThumb2LdrRRI12,     /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
    458                                        rn[19..16] rt[15..12] imm12[11..0] */
    459     kThumb2StrRRI8Predec, /* str(Imm,T4) rd,[rn,#-imm8] [111110000100]
    460                                        rn[19..16] rt[15..12] [1100] imm[7..0]*/
    461     kThumb2LdrRRI8Predec, /* ldr(Imm,T4) rd,[rn,#-imm8] [111110000101]
    462                                        rn[19..16] rt[15..12] [1100] imm[7..0]*/
    463     kThumb2Cbnz,         /* cbnz rd,<label> [101110] i [1] imm5[7..3]
    464                                        rn[2..0] */
    465     kThumb2Cbz,          /* cbn rd,<label> [101100] i [1] imm5[7..3]
    466                                        rn[2..0] */
    467     kThumb2AddRRI12,     /* add rd, rn, #imm12 [11110] i [100000] rn[19..16]
    468                                        [0] imm3[14..12] rd[11..8] imm8[7..0] */
    469     kThumb2MovRR,        /* mov rd, rm [11101010010011110000] rd[11..8]
    470                                        [0000] rm[3..0] */
    471     kThumb2Vmovs,        /* vmov.f32 vd, vm [111011101] D [110000]
    472                                        vd[15..12] 101001] M [0] vm[3..0] */
    473     kThumb2Vmovd,        /* vmov.f64 vd, vm [111011101] D [110000]
    474                                        vd[15..12] 101101] M [0] vm[3..0] */
    475     kThumb2Ldmia,        /* ldmia  [111010001001[ rn[19..16] mask[15..0] */
    476     kThumb2Stmia,        /* stmia  [111010001000[ rn[19..16] mask[15..0] */
    477     kThumb2AddRRR,       /* add [111010110000] rn[19..16] [0000] rd[11..8]
    478                                    [0000] rm[3..0] */
    479     kThumb2SubRRR,       /* sub [111010111010] rn[19..16] [0000] rd[11..8]
    480                                    [0000] rm[3..0] */
    481     kThumb2SbcRRR,       /* sbc [111010110110] rn[19..16] [0000] rd[11..8]
    482                                    [0000] rm[3..0] */
    483     kThumb2CmpRR,        /* cmp [111010111011] rn[19..16] [0000] [1111]
    484                                    [0000] rm[3..0] */
    485     kThumb2SubRRI12,     /* sub rd, rn, #imm12 [11110] i [01010] rn[19..16]
    486                                        [0] imm3[14..12] rd[11..8] imm8[7..0] */
    487     kThumb2MvnImmShift,  /* mov(T2) rd, #<const> [11110] i [00011011110]
    488                                        imm3 rd[11..8] imm8 */
    489     kThumb2Sel,          /* sel rd, rn, rm [111110101010] rn[19-16] rd[11-8]
    490                                        rm[3-0] */
    491     kThumb2Ubfx,         /* ubfx rd,rn,#lsb,#width [111100111100] rn[19..16]
    492                                        [0] imm3[14-12] rd[11-8] w[4-0] */
    493     kThumb2Sbfx,         /* ubfx rd,rn,#lsb,#width [111100110100] rn[19..16]
    494                                        [0] imm3[14-12] rd[11-8] w[4-0] */
    495     kThumb2LdrRRR,       /* ldr rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
    496                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
    497     kThumb2LdrhRRR,      /* ldrh rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
    498                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
    499     kThumb2LdrshRRR,     /* ldrsh rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
    500                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
    501     kThumb2LdrbRRR,      /* ldrb rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
    502                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
    503     kThumb2LdrsbRRR,     /* ldrsb rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
    504                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
    505     kThumb2StrRRR,       /* str rt,[rn,rm,LSL #imm] [111110000100] rn[19-16]
    506                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
    507     kThumb2StrhRRR,      /* str rt,[rn,rm,LSL #imm] [111110000010] rn[19-16]
    508                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
    509     kThumb2StrbRRR,      /* str rt,[rn,rm,LSL #imm] [111110000000] rn[19-16]
    510                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
    511     kThumb2LdrhRRI12,    /* ldrh rt,[rn,#imm12] [111110001011]
    512                                        rt[15..12] rn[19..16] imm12[11..0] */
    513     kThumb2LdrshRRI12,   /* ldrsh rt,[rn,#imm12] [111110011011]
    514                                        rt[15..12] rn[19..16] imm12[11..0] */
    515     kThumb2LdrbRRI12,    /* ldrb rt,[rn,#imm12] [111110001001]
    516                                        rt[15..12] rn[19..16] imm12[11..0] */
    517     kThumb2LdrsbRRI12,   /* ldrsb rt,[rn,#imm12] [111110011001]
    518                                        rt[15..12] rn[19..16] imm12[11..0] */
    519     kThumb2StrhRRI12,    /* strh rt,[rn,#imm12] [111110001010]
    520                                        rt[15..12] rn[19..16] imm12[11..0] */
    521     kThumb2StrbRRI12,    /* strb rt,[rn,#imm12] [111110001000]
    522                                        rt[15..12] rn[19..16] imm12[11..0] */
    523     kThumb2Pop,          /* pop     [1110100010111101] list[15-0]*/
    524     kThumb2Push,         /* push    [1110100100101101] list[15-0]*/
    525     kThumb2CmpRI8,       /* cmp rn, #<const> [11110] i [011011] rn[19-16] [0]
    526                                        imm3 [1111] imm8[7..0] */
    527     kThumb2AdcRRR,       /* adc [111010110101] rn[19..16] [0000] rd[11..8]
    528                                    [0000] rm[3..0] */
    529     kThumb2AndRRR,       /* and [111010100000] rn[19..16] [0000] rd[11..8]
    530                                    [0000] rm[3..0] */
    531     kThumb2BicRRR,       /* bic [111010100010] rn[19..16] [0000] rd[11..8]
    532                                    [0000] rm[3..0] */
    533     kThumb2CmnRR,        /* cmn [111010110001] rn[19..16] [0000] [1111]
    534                                    [0000] rm[3..0] */
    535     kThumb2EorRRR,       /* eor [111010101000] rn[19..16] [0000] rd[11..8]
    536                                    [0000] rm[3..0] */
    537     kThumb2MulRRR,       /* mul [111110110000] rn[19..16] [1111] rd[11..8]
    538                                    [0000] rm[3..0] */
    539     kThumb2MnvRR,        /* mvn [11101010011011110] rd[11-8] [0000]
    540                                    rm[3..0] */
    541     kThumb2RsubRRI8,     /* rsub [111100011100] rn[19..16] [0000] rd[11..8]
    542                                    imm8[7..0] */
    543     kThumb2NegRR,        /* actually rsub rd, rn, #0 */
    544     kThumb2OrrRRR,       /* orr [111010100100] rn[19..16] [0000] rd[11..8]
    545                                    [0000] rm[3..0] */
    546     kThumb2TstRR,        /* tst [111010100001] rn[19..16] [0000] [1111]
    547                                    [0000] rm[3..0] */
    548     kThumb2LslRRR,       /* lsl [111110100000] rn[19..16] [1111] rd[11..8]
    549                                    [0000] rm[3..0] */
    550     kThumb2LsrRRR,       /* lsr [111110100010] rn[19..16] [1111] rd[11..8]
    551                                    [0000] rm[3..0] */
    552     kThumb2AsrRRR,       /* asr [111110100100] rn[19..16] [1111] rd[11..8]
    553                                    [0000] rm[3..0] */
    554     kThumb2RorRRR,       /* ror [111110100110] rn[19..16] [1111] rd[11..8]
    555                                    [0000] rm[3..0] */
    556     kThumb2LslRRI5,      /* lsl [11101010010011110] imm[14.12] rd[11..8]
    557                                    [00] rm[3..0] */
    558     kThumb2LsrRRI5,      /* lsr [11101010010011110] imm[14.12] rd[11..8]
    559                                    [01] rm[3..0] */
    560     kThumb2AsrRRI5,      /* asr [11101010010011110] imm[14.12] rd[11..8]
    561                                    [10] rm[3..0] */
    562     kThumb2RorRRI5,      /* ror [11101010010011110] imm[14.12] rd[11..8]
    563                                    [11] rm[3..0] */
    564     kThumb2BicRRI8,      /* bic [111100000010] rn[19..16] [0] imm3
    565                                    rd[11..8] imm8 */
    566     kThumb2AndRRI8,      /* bic [111100000000] rn[19..16] [0] imm3
    567                                    rd[11..8] imm8 */
    568     kThumb2OrrRRI8,      /* orr [111100000100] rn[19..16] [0] imm3
    569                                    rd[11..8] imm8 */
    570     kThumb2EorRRI8,      /* eor [111100001000] rn[19..16] [0] imm3
    571                                    rd[11..8] imm8 */
    572     kThumb2AddRRI8,      /* add [111100001000] rn[19..16] [0] imm3
    573                                    rd[11..8] imm8 */
    574     kThumb2AdcRRI8,      /* adc [111100010101] rn[19..16] [0] imm3
    575                                    rd[11..8] imm8 */
    576     kThumb2SubRRI8,      /* sub [111100011011] rn[19..16] [0] imm3
    577                                    rd[11..8] imm8 */
    578     kThumb2SbcRRI8,      /* sbc [111100010111] rn[19..16] [0] imm3
    579                                    rd[11..8] imm8 */
    580     kThumb2It,           /* it [10111111] firstcond[7-4] mask[3-0] */
    581     kThumb2Fmstat,       /* fmstat [11101110111100011111101000010000] */
    582     kThumb2Vcmpd,        /* vcmp [111011101] D [11011] rd[15-12] [1011]
    583                                    E [1] M [0] rm[3-0] */
    584     kThumb2Vcmps,        /* vcmp [111011101] D [11010] rd[15-12] [1011]
    585                                    E [1] M [0] rm[3-0] */
    586     kThumb2LdrPcRel12,   /* ldr rd,[pc,#imm12] [1111100011011111] rt[15-12]
    587                                   imm12[11-0] */
    588     kThumb2BCond,        /* b<c> [1110] S cond[25-22] imm6[21-16] [10]
    589                                   J1 [0] J2 imm11[10..0] */
    590     kThumb2Vmovd_RR,     /* vmov [111011101] D [110000] vd[15-12 [101101]
    591                                   M [0] vm[3-0] */
    592     kThumb2Vmovs_RR,     /* vmov [111011101] D [110000] vd[15-12 [101001]
    593                                   M [0] vm[3-0] */
    594     kThumb2Fmrs,         /* vmov [111011100000] vn[19-16] rt[15-12] [1010]
    595                                   N [0010000] */
    596     kThumb2Fmsr,         /* vmov [111011100001] vn[19-16] rt[15-12] [1010]
    597                                   N [0010000] */
    598     kThumb2Fmrrd,        /* vmov [111011000100] rt2[19-16] rt[15-12]
    599                                   [101100] M [1] vm[3-0] */
    600     kThumb2Fmdrr,        /* vmov [111011000101] rt2[19-16] rt[15-12]
    601                                   [101100] M [1] vm[3-0] */
    602     kThumb2Vabsd,        /* vabs.f64 [111011101] D [110000] rd[15-12]
    603                                   [1011110] M [0] vm[3-0] */
    604     kThumb2Vabss,        /* vabs.f32 [111011101] D [110000] rd[15-12]
    605                                   [1010110] M [0] vm[3-0] */
    606     kThumb2Vnegd,        /* vneg.f64 [111011101] D [110000] rd[15-12]
    607                                   [1011110] M [0] vm[3-0] */
    608     kThumb2Vnegs,        /* vneg.f32 [111011101] D [110000] rd[15-12]
    609                                  [1010110] M [0] vm[3-0] */
    610     kThumb2Vmovs_IMM8,   /* vmov.f32 [111011101] D [11] imm4h[19-16] vd[15-12]
    611                                   [10100000] imm4l[3-0] */
    612     kThumb2Vmovd_IMM8,   /* vmov.f64 [111011101] D [11] imm4h[19-16] vd[15-12]
    613                                   [10110000] imm4l[3-0] */
    614     kThumb2Mla,          /* mla [111110110000] rn[19-16] ra[15-12] rd[7-4]
    615                                   [0000] rm[3-0] */
    616     kThumb2Umull,        /* umull [111110111010] rn[19-16], rdlo[15-12]
    617                                   rdhi[11-8] [0000] rm[3-0] */
    618     kThumb2Ldrex,        /* ldrex [111010000101] rn[19-16] rt[11-8] [1111]
    619                                   imm8[7-0] */
    620     kThumb2Strex,        /* strex [111010000100] rn[19-16] rt[11-8] rd[11-8]
    621                                   imm8[7-0] */
    622     kThumb2Clrex,        /* clrex [111100111011111110000111100101111] */
    623     kThumb2Bfi,          /* bfi [111100110110] rn[19-16] [0] imm3[14-12]
    624                                   rd[11-8] imm2[7-6] [0] msb[4-0] */
    625     kThumb2Bfc,          /* bfc [11110011011011110] [0] imm3[14-12]
    626                                   rd[11-8] imm2[7-6] [0] msb[4-0] */
    627     kThumb2Dmb,          /* dmb [1111001110111111100011110101] option[3-0] */
    628     kThumb2LdrPcReln12,  /* ldr rd,[pc,-#imm12] [1111100011011111] rt[15-12]
    629                                   imm12[11-0] */
    630     kThumbUndefined,     /* undefined [11011110xxxxxxxx] */
    631     kArmLast,
    632 } ArmOpcode;
    633 
    634 /* DMB option encodings */
    635 typedef enum ArmOpDmbOptions {
    636     kSY = 0xf,
    637     kST = 0xe,
    638     kISH = 0xb,
    639     kISHST = 0xa,
    640     kNSH = 0x7,
    641     kNSHST = 0x6
    642 } ArmOpDmbOptions;
    643 
    644 /* Bit flags describing the behavior of each native opcode */
    645 typedef enum ArmOpFeatureFlags {
    646     kIsBranch = 0,
    647     kRegDef0,
    648     kRegDef1,
    649     kRegDefSP,
    650     kRegDefLR,
    651     kRegDefList0,
    652     kRegDefList1,
    653     kRegUse0,
    654     kRegUse1,
    655     kRegUse2,
    656     kRegUse3,
    657     kRegUseSP,
    658     kRegUsePC,
    659     kRegUseList0,
    660     kRegUseList1,
    661     kNoOperand,
    662     kIsUnaryOp,
    663     kIsBinaryOp,
    664     kIsTertiaryOp,
    665     kIsQuadOp,
    666     kIsIT,
    667     kSetsCCodes,
    668     kUsesCCodes,
    669     kMemLoad,
    670     kMemStore,
    671 } ArmOpFeatureFlags;
    672 
    673 #define IS_LOAD         (1 << kMemLoad)
    674 #define IS_STORE        (1 << kMemStore)
    675 #define IS_BRANCH       (1 << kIsBranch)
    676 #define REG_DEF0        (1 << kRegDef0)
    677 #define REG_DEF1        (1 << kRegDef1)
    678 #define REG_DEF_SP      (1 << kRegDefSP)
    679 #define REG_DEF_LR      (1 << kRegDefLR)
    680 #define REG_DEF_LIST0   (1 << kRegDefList0)
    681 #define REG_DEF_LIST1   (1 << kRegDefList1)
    682 #define REG_USE0        (1 << kRegUse0)
    683 #define REG_USE1        (1 << kRegUse1)
    684 #define REG_USE2        (1 << kRegUse2)
    685 #define REG_USE3        (1 << kRegUse3)
    686 #define REG_USE_SP      (1 << kRegUseSP)
    687 #define REG_USE_PC      (1 << kRegUsePC)
    688 #define REG_USE_LIST0   (1 << kRegUseList0)
    689 #define REG_USE_LIST1   (1 << kRegUseList1)
    690 #define NO_OPERAND      (1 << kNoOperand)
    691 #define IS_UNARY_OP     (1 << kIsUnaryOp)
    692 #define IS_BINARY_OP    (1 << kIsBinaryOp)
    693 #define IS_TERTIARY_OP  (1 << kIsTertiaryOp)
    694 #define IS_QUAD_OP      (1 << kIsQuadOp)
    695 #define IS_IT           (1 << kIsIT)
    696 #define SETS_CCODES     (1 << kSetsCCodes)
    697 #define USES_CCODES     (1 << kUsesCCodes)
    698 
    699 /* Common combo register usage patterns */
    700 #define REG_USE01       (REG_USE0 | REG_USE1)
    701 #define REG_USE012      (REG_USE01 | REG_USE2)
    702 #define REG_USE12       (REG_USE1 | REG_USE2)
    703 #define REG_DEF0_USE0   (REG_DEF0 | REG_USE0)
    704 #define REG_DEF0_USE1   (REG_DEF0 | REG_USE1)
    705 #define REG_DEF0_USE01  (REG_DEF0 | REG_USE01)
    706 #define REG_DEF0_USE12  (REG_DEF0 | REG_USE12)
    707 #define REG_DEF01_USE2  (REG_DEF0 | REG_DEF1 | REG_USE2)
    708 
    709 /* Instruction assembly fieldLoc kind */
    710 typedef enum ArmEncodingKind {
    711     kFmtUnused,
    712     kFmtBitBlt,        /* Bit string using end/start */
    713     kFmtDfp,           /* Double FP reg */
    714     kFmtSfp,           /* Single FP reg */
    715     kFmtModImm,        /* Shifted 8-bit immed using [26,14..12,7..0] */
    716     kFmtImm16,         /* Zero-extended immed using [26,19..16,14..12,7..0] */
    717     kFmtImm6,          /* Encoded branch target using [9,7..3]0 */
    718     kFmtImm12,         /* Zero-extended immediate using [26,14..12,7..0] */
    719     kFmtShift,         /* Shift descriptor, [14..12,7..4] */
    720     kFmtLsb,           /* least significant bit using [14..12][7..6] */
    721     kFmtBWidth,        /* bit-field width, encoded as width-1 */
    722     kFmtShift5,        /* Shift count, [14..12,7..6] */
    723     kFmtBrOffset,      /* Signed extended [26,11,13,21-16,10-0]:0 */
    724     kFmtFPImm,         /* Encoded floating point immediate */
    725 } ArmEncodingKind;
    726 
    727 /* Struct used to define the snippet positions for each Thumb opcode */
    728 typedef struct ArmEncodingMap {
    729     u4 skeleton;
    730     struct {
    731         ArmEncodingKind kind;
    732         int end;   /* end for kFmtBitBlt, 1-bit slice end for FP regs */
    733         int start; /* start for kFmtBitBlt, 4-bit slice end for FP regs */
    734     } fieldLoc[4];
    735     ArmOpcode opcode;
    736     int flags;
    737     const char* name;
    738     const char* fmt;
    739     int size;
    740 } ArmEncodingMap;
    741 
    742 /* Keys for target-specific scheduling and other optimization hints */
    743 typedef enum ArmTargetOptHints {
    744     kMaxHoistDistance,
    745 } ArmTargetOptHints;
    746 
    747 extern ArmEncodingMap EncodingMap[kArmLast];
    748 
    749 /*
    750  * Each instance of this struct holds a pseudo or real LIR instruction:
    751  * - pseudo ones (eg labels and marks) and will be discarded by the assembler.
    752  * - real ones will be assembled into Thumb instructions.
    753  *
    754  * Machine resources are encoded into a 64-bit vector, where the encodings are
    755  * as following:
    756  * - [ 0..15]: general purpose registers including PC, SP, and LR
    757  * - [16..47]: floating-point registers where d0 is expanded to s[01] and s0
    758  *   starts at bit 16
    759  * - [48]: IT block
    760  * - [49]: integer condition code
    761  * - [50]: floatint-point status word
    762  */
    763 typedef struct ArmLIR {
    764     LIR generic;
    765     ArmOpcode opcode;
    766     int operands[4];            // [0..3] = [dest, src1, src2, extra]
    767     struct {
    768         bool isNop:1;           // LIR is optimized away
    769         bool insertWrapper:1;   // insert branch to emulate memory accesses
    770         unsigned int age:4;     // default is 0, set lazily by the optimizer
    771         unsigned int size:3;    // bytes (2 for thumb, 2/4 for thumb2)
    772         unsigned int unused:23;
    773     } flags;
    774     int aliasInfo;              // For Dalvik register & litpool disambiguation
    775     u8 useMask;                 // Resource mask for use
    776     u8 defMask;                 // Resource mask for def
    777 } ArmLIR;
    778 
    779 /* Init values when a predicted chain is initially assembled */
    780 /* E7FE is branch to self */
    781 #define PREDICTED_CHAIN_BX_PAIR_INIT     0xe7fe
    782 
    783 /* Utility macros to traverse the LIR/ArmLIR list */
    784 #define NEXT_LIR(lir) ((ArmLIR *) lir->generic.next)
    785 #define PREV_LIR(lir) ((ArmLIR *) lir->generic.prev)
    786 
    787 #define NEXT_LIR_LVALUE(lir) (lir)->generic.next
    788 #define PREV_LIR_LVALUE(lir) (lir)->generic.prev
    789 
    790 #define CHAIN_CELL_OFFSET_TAG   0xcdab
    791 
    792 #define CHAIN_CELL_NORMAL_SIZE 12
    793 #define CHAIN_CELL_PREDICTED_SIZE 16
    794 
    795 #endif  // DALVIK_VM_COMPILER_CODEGEN_ARM_ARMLIR_H_
    796