1 /* 2 * Copyright (C) 2012 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 ART_COMPILER_DEX_COMPILER_ENUMS_H_ 18 #define ART_COMPILER_DEX_COMPILER_ENUMS_H_ 19 20 #include "dex_instruction.h" 21 22 namespace art { 23 24 enum RegisterClass { 25 kInvalidRegClass, 26 kCoreReg, 27 kFPReg, 28 kRefReg, 29 kAnyReg, 30 }; 31 std::ostream& operator<<(std::ostream& os, const RegisterClass& rhs); 32 33 enum BitsUsed { 34 kSize32Bits, 35 kSize64Bits, 36 kSize128Bits, 37 kSize256Bits, 38 kSize512Bits, 39 kSize1024Bits, 40 }; 41 std::ostream& operator<<(std::ostream& os, const BitsUsed& rhs); 42 43 enum SpecialTargetRegister { 44 kSelf, // Thread pointer. 45 kSuspend, // Used to reduce suspend checks for some targets. 46 kLr, 47 kPc, 48 kSp, 49 kArg0, 50 kArg1, 51 kArg2, 52 kArg3, 53 kArg4, 54 kArg5, 55 kArg6, 56 kArg7, 57 kFArg0, 58 kFArg1, 59 kFArg2, 60 kFArg3, 61 kFArg4, 62 kFArg5, 63 kFArg6, 64 kFArg7, 65 kFArg8, 66 kFArg9, 67 kFArg10, 68 kFArg11, 69 kFArg12, 70 kFArg13, 71 kFArg14, 72 kFArg15, 73 kRet0, 74 kRet1, 75 kInvokeTgt, 76 kHiddenArg, 77 kHiddenFpArg, 78 kCount 79 }; 80 std::ostream& operator<<(std::ostream& os, const SpecialTargetRegister& code); 81 82 enum RegLocationType { 83 kLocDalvikFrame = 0, // Normal Dalvik register 84 kLocPhysReg, 85 kLocCompilerTemp, 86 kLocInvalid 87 }; 88 std::ostream& operator<<(std::ostream& os, const RegLocationType& rhs); 89 90 enum BBType { 91 kNullBlock, 92 kEntryBlock, 93 kDalvikByteCode, 94 kExitBlock, 95 kExceptionHandling, 96 kDead, 97 }; 98 std::ostream& operator<<(std::ostream& os, const BBType& code); 99 100 // Shared pseudo opcodes - must be < 0. 101 enum LIRPseudoOpcode { 102 kPseudoPrologueBegin = -18, 103 kPseudoPrologueEnd = -17, 104 kPseudoEpilogueBegin = -16, 105 kPseudoEpilogueEnd = -15, 106 kPseudoExportedPC = -14, 107 kPseudoSafepointPC = -13, 108 kPseudoIntrinsicRetry = -12, 109 kPseudoSuspendTarget = -11, 110 kPseudoThrowTarget = -10, 111 kPseudoCaseLabel = -9, 112 kPseudoBarrier = -8, 113 kPseudoEntryBlock = -7, 114 kPseudoExitBlock = -6, 115 kPseudoTargetLabel = -5, 116 kPseudoDalvikByteCodeBoundary = -4, 117 kPseudoPseudoAlign4 = -3, 118 kPseudoEHBlockLabel = -2, 119 kPseudoNormalBlockLabel = -1, 120 }; 121 std::ostream& operator<<(std::ostream& os, const LIRPseudoOpcode& rhs); 122 123 enum ExtendedMIROpcode { 124 kMirOpFirst = kNumPackedOpcodes, 125 kMirOpPhi = kMirOpFirst, 126 127 // @brief Copy from one VR to another. 128 // @details 129 // vA: destination VR 130 // vB: source VR 131 kMirOpCopy, 132 133 // @brief Used to do float comparison with less-than bias. 134 // @details Unlike cmpl-float, this does not store result of comparison in VR. 135 // vA: left-hand side VR for comparison. 136 // vB: right-hand side VR for comparison. 137 kMirOpFusedCmplFloat, 138 139 // @brief Used to do float comparison with greater-than bias. 140 // @details Unlike cmpg-float, this does not store result of comparison in VR. 141 // vA: left-hand side VR for comparison. 142 // vB: right-hand side VR for comparison. 143 kMirOpFusedCmpgFloat, 144 145 // @brief Used to do double comparison with less-than bias. 146 // @details Unlike cmpl-double, this does not store result of comparison in VR. 147 // vA: left-hand side wide VR for comparison. 148 // vB: right-hand side wide VR for comparison. 149 kMirOpFusedCmplDouble, 150 151 // @brief Used to do double comparison with greater-than bias. 152 // @details Unlike cmpl-double, this does not store result of comparison in VR. 153 // vA: left-hand side wide VR for comparison. 154 // vB: right-hand side wide VR for comparison. 155 kMirOpFusedCmpgDouble, 156 157 // @brief Used to do comparison of 64-bit long integers. 158 // @details Unlike cmp-long, this does not store result of comparison in VR. 159 // vA: left-hand side wide VR for comparison. 160 // vB: right-hand side wide VR for comparison. 161 kMirOpFusedCmpLong, 162 163 // @brief This represents no-op. 164 kMirOpNop, 165 166 // @brief Do a null check on the object register. 167 // @details The backends may implement this implicitly or explicitly. This MIR is guaranteed 168 // to have the correct offset as an exception thrower. 169 // vA: object register 170 kMirOpNullCheck, 171 172 kMirOpRangeCheck, 173 kMirOpDivZeroCheck, 174 kMirOpCheck, 175 kMirOpSelect, 176 177 // Vector opcodes: 178 // TypeSize is an encoded field giving the element type and the vector size. 179 // It is encoded as OpSize << 16 | (number of bits in vector) 180 // 181 // Destination and source are integers that will be interpreted by the 182 // backend that supports Vector operations. Backends are permitted to support only 183 // certain vector register sizes. 184 // 185 // At this point, only two operand instructions are supported. Three operand instructions 186 // could be supported by using a bit in TypeSize and arg[0] where needed. 187 188 // @brief MIR to move constant data to a vector register 189 // vA: destination 190 // vB: number of bits in register 191 // args[0]~args[3]: up to 128 bits of data for initialization 192 kMirOpConstVector, 193 194 // @brief MIR to move a vectorized register to another 195 // vA: destination 196 // vB: source 197 // vC: TypeSize 198 kMirOpMoveVector, 199 200 // @brief Packed multiply of units in two vector registers: vB = vB .* vC using vA to know the type of the vector. 201 // vA: destination and source 202 // vB: source 203 // vC: TypeSize 204 kMirOpPackedMultiply, 205 206 // @brief Packed addition of units in two vector registers: vB = vB .+ vC using vA to know the type of the vector. 207 // vA: destination and source 208 // vB: source 209 // vC: TypeSize 210 kMirOpPackedAddition, 211 212 // @brief Packed subtraction of units in two vector registers: vB = vB .- vC using vA to know the type of the vector. 213 // vA: destination and source 214 // vB: source 215 // vC: TypeSize 216 kMirOpPackedSubtract, 217 218 // @brief Packed shift left of units in two vector registers: vB = vB .<< vC using vA to know the type of the vector. 219 // vA: destination and source 220 // vB: amount to shift 221 // vC: TypeSize 222 kMirOpPackedShiftLeft, 223 224 // @brief Packed signed shift right of units in two vector registers: vB = vB .>> vC using vA to know the type of the vector. 225 // vA: destination and source 226 // vB: amount to shift 227 // vC: TypeSize 228 kMirOpPackedSignedShiftRight, 229 230 // @brief Packed unsigned shift right of units in two vector registers: vB = vB .>>> vC using vA to know the type of the vector. 231 // vA: destination and source 232 // vB: amount to shift 233 // vC: TypeSize 234 kMirOpPackedUnsignedShiftRight, 235 236 // @brief Packed bitwise and of units in two vector registers: vB = vB .& vC using vA to know the type of the vector. 237 // vA: destination and source 238 // vB: source 239 // vC: TypeSize 240 kMirOpPackedAnd, 241 242 // @brief Packed bitwise or of units in two vector registers: vB = vB .| vC using vA to know the type of the vector. 243 // vA: destination and source 244 // vB: source 245 // vC: TypeSize 246 kMirOpPackedOr, 247 248 // @brief Packed bitwise xor of units in two vector registers: vB = vB .^ vC using vA to know the type of the vector. 249 // vA: destination and source 250 // vB: source 251 // vC: TypeSize 252 kMirOpPackedXor, 253 254 // @brief Reduce a 128-bit packed element into a single VR by taking lower bits 255 // @details Instruction does a horizontal addition of the packed elements and then adds it to VR 256 // vA: destination and source VR (not vector register) 257 // vB: source (vector register) 258 // vC: TypeSize 259 kMirOpPackedAddReduce, 260 261 // @brief Extract a packed element into a single VR. 262 // vA: destination VR (not vector register) 263 // vB: source (vector register) 264 // vC: TypeSize 265 // arg[0]: The index to use for extraction from vector register (which packed element) 266 kMirOpPackedReduce, 267 268 // @brief Create a vector value, with all TypeSize values equal to vC 269 // vA: destination vector register 270 // vB: source VR (not vector register) 271 // vC: TypeSize 272 kMirOpPackedSet, 273 274 // @brief Reserve a range of vector registers. 275 // vA: Start vector register to reserve. 276 // vB: Inclusive end vector register to reserve. 277 // @note: The backend may choose to map vector numbers used in vector opcodes. 278 // Reserved registers are removed from the list of backend temporary pool. 279 kMirOpReserveVectorRegisters, 280 281 // @brief Free a range of reserved vector registers 282 // vA: Start vector register to unreserve. 283 // vB: Inclusive end vector register to unreserve. 284 // @note: All currently reserved vector registers are returned to the temporary pool. 285 kMirOpReturnVectorRegisters, 286 287 // @brief Create a memory barrier. 288 // vA: a constant defined by enum MemBarrierKind. 289 kMirOpMemBarrier, 290 291 // @brief Used to fill a vector register with array values. 292 // @details Just as with normal arrays, access on null object register must ensure NullPointerException 293 // and invalid index must ensure ArrayIndexOutOfBoundsException. Exception behavior must be the same 294 // as the aget it replaced and must happen at same index. Therefore, it is generally recommended that 295 // before using this MIR, it is proven that exception is guaranteed to not be thrown and marked with 296 // MIR_IGNORE_NULL_CHECK and MIR_IGNORE_RANGE_CHECK. 297 // vA: destination vector register 298 // vB: array register 299 // vC: index register 300 // arg[0]: TypeSize (most other vector opcodes have this in vC) 301 kMirOpPackedArrayGet, 302 303 // @brief Used to store a vector register into array. 304 // @details Just as with normal arrays, access on null object register must ensure NullPointerException 305 // and invalid index must ensure ArrayIndexOutOfBoundsException. Exception behavior must be the same 306 // as the aget it replaced and must happen at same index. Therefore, it is generally recommended that 307 // before using this MIR, it is proven that exception is guaranteed to not be thrown and marked with 308 // MIR_IGNORE_NULL_CHECK and MIR_IGNORE_RANGE_CHECK. 309 // vA: source vector register 310 // vB: array register 311 // vC: index register 312 // arg[0]: TypeSize (most other vector opcodes have this in vC) 313 kMirOpPackedArrayPut, 314 315 // @brief Multiply-add integer. 316 // vA: destination 317 // vB: multiplicand 318 // vC: multiplier 319 // arg[0]: addend 320 kMirOpMaddInt, 321 322 // @brief Multiply-subtract integer. 323 // vA: destination 324 // vB: multiplicand 325 // vC: multiplier 326 // arg[0]: minuend 327 kMirOpMsubInt, 328 329 // @brief Multiply-add long. 330 // vA: destination 331 // vB: multiplicand 332 // vC: multiplier 333 // arg[0]: addend 334 kMirOpMaddLong, 335 336 // @brief Multiply-subtract long. 337 // vA: destination 338 // vB: multiplicand 339 // vC: multiplier 340 // arg[0]: minuend 341 kMirOpMsubLong, 342 343 kMirOpLast, 344 }; 345 346 enum MIROptimizationFlagPositions { 347 kMIRIgnoreNullCheck = 0, 348 kMIRIgnoreRangeCheck, 349 kMIRIgnoreCheckCast, 350 kMIRStoreNonNullValue, // Storing non-null value, always mark GC card. 351 kMIRClassIsInitialized, 352 kMIRClassIsInDexCache, 353 kMirIgnoreDivZeroCheck, 354 kMIRInlined, // Invoke is inlined (ie dead). 355 kMIRInlinedPred, // Invoke is inlined via prediction. 356 kMIRCallee, // Instruction is inlined from callee. 357 kMIRIgnoreSuspendCheck, 358 kMIRDup, 359 kMIRMark, // Temporary node mark can be used by 360 // opt passes for their private needs. 361 kMIRStoreNonTemporal, 362 kMIRLastMIRFlag, 363 }; 364 365 // For successor_block_list. 366 enum BlockListType { 367 kNotUsed = 0, 368 kCatch, 369 kPackedSwitch, 370 kSparseSwitch, 371 }; 372 std::ostream& operator<<(std::ostream& os, const BlockListType& rhs); 373 374 enum AssemblerStatus { 375 kSuccess, 376 kRetryAll, 377 }; 378 std::ostream& operator<<(std::ostream& os, const AssemblerStatus& rhs); 379 380 enum OpSize { 381 kWord, // Natural word size of target (32/64). 382 k32, 383 k64, 384 kReference, // Object reference; compressed on 64-bit targets. 385 kSingle, 386 kDouble, 387 kUnsignedHalf, 388 kSignedHalf, 389 kUnsignedByte, 390 kSignedByte, 391 }; 392 std::ostream& operator<<(std::ostream& os, const OpSize& kind); 393 394 enum OpKind { 395 kOpMov, 396 kOpCmov, 397 kOpMvn, 398 kOpCmp, 399 kOpLsl, 400 kOpLsr, 401 kOpAsr, 402 kOpRor, 403 kOpNot, 404 kOpAnd, 405 kOpOr, 406 kOpXor, 407 kOpNeg, 408 kOpAdd, 409 kOpAdc, 410 kOpSub, 411 kOpSbc, 412 kOpRsub, 413 kOpMul, 414 kOpDiv, 415 kOpRem, 416 kOpBic, 417 kOpCmn, 418 kOpTst, 419 kOpRev, 420 kOpRevsh, 421 kOpBkpt, 422 kOpBlx, 423 kOpPush, 424 kOpPop, 425 kOp2Char, 426 kOp2Short, 427 kOp2Byte, 428 kOpCondBr, 429 kOpUncondBr, 430 kOpBx, 431 kOpInvalid, 432 }; 433 std::ostream& operator<<(std::ostream& os, const OpKind& rhs); 434 435 enum MoveType { 436 kMov8GP, // Move 8-bit general purpose register. 437 kMov16GP, // Move 16-bit general purpose register. 438 kMov32GP, // Move 32-bit general purpose register. 439 kMov64GP, // Move 64-bit general purpose register. 440 kMov32FP, // Move 32-bit FP register. 441 kMov64FP, // Move 64-bit FP register. 442 kMovLo64FP, // Move low 32-bits of 64-bit FP register. 443 kMovHi64FP, // Move high 32-bits of 64-bit FP register. 444 kMovU128FP, // Move 128-bit FP register to/from possibly unaligned region. 445 kMov128FP = kMovU128FP, 446 kMovA128FP, // Move 128-bit FP register to/from region surely aligned to 16-bytes. 447 kMovLo128FP, // Move low 64-bits of 128-bit FP register. 448 kMovHi128FP, // Move high 64-bits of 128-bit FP register. 449 }; 450 std::ostream& operator<<(std::ostream& os, const MoveType& kind); 451 452 enum ConditionCode { 453 kCondEq, // equal 454 kCondNe, // not equal 455 kCondCs, // carry set 456 kCondCc, // carry clear 457 kCondUlt, // unsigned less than 458 kCondUge, // unsigned greater than or same 459 kCondMi, // minus 460 kCondPl, // plus, positive or zero 461 kCondVs, // overflow 462 kCondVc, // no overflow 463 kCondHi, // unsigned greater than 464 kCondLs, // unsigned lower or same 465 kCondGe, // signed greater than or equal 466 kCondLt, // signed less than 467 kCondGt, // signed greater than 468 kCondLe, // signed less than or equal 469 kCondAl, // always 470 kCondNv, // never 471 }; 472 std::ostream& operator<<(std::ostream& os, const ConditionCode& kind); 473 474 // Target specific condition encodings 475 enum ArmConditionCode { 476 kArmCondEq = 0x0, // 0000 477 kArmCondNe = 0x1, // 0001 478 kArmCondCs = 0x2, // 0010 479 kArmCondCc = 0x3, // 0011 480 kArmCondMi = 0x4, // 0100 481 kArmCondPl = 0x5, // 0101 482 kArmCondVs = 0x6, // 0110 483 kArmCondVc = 0x7, // 0111 484 kArmCondHi = 0x8, // 1000 485 kArmCondLs = 0x9, // 1001 486 kArmCondGe = 0xa, // 1010 487 kArmCondLt = 0xb, // 1011 488 kArmCondGt = 0xc, // 1100 489 kArmCondLe = 0xd, // 1101 490 kArmCondAl = 0xe, // 1110 491 kArmCondNv = 0xf, // 1111 492 }; 493 std::ostream& operator<<(std::ostream& os, const ArmConditionCode& kind); 494 495 enum X86ConditionCode { 496 kX86CondO = 0x0, // overflow 497 kX86CondNo = 0x1, // not overflow 498 499 kX86CondB = 0x2, // below 500 kX86CondNae = kX86CondB, // not-above-equal 501 kX86CondC = kX86CondB, // carry 502 503 kX86CondNb = 0x3, // not-below 504 kX86CondAe = kX86CondNb, // above-equal 505 kX86CondNc = kX86CondNb, // not-carry 506 507 kX86CondZ = 0x4, // zero 508 kX86CondEq = kX86CondZ, // equal 509 510 kX86CondNz = 0x5, // not-zero 511 kX86CondNe = kX86CondNz, // not-equal 512 513 kX86CondBe = 0x6, // below-equal 514 kX86CondNa = kX86CondBe, // not-above 515 516 kX86CondNbe = 0x7, // not-below-equal 517 kX86CondA = kX86CondNbe, // above 518 519 kX86CondS = 0x8, // sign 520 kX86CondNs = 0x9, // not-sign 521 522 kX86CondP = 0xa, // 8-bit parity even 523 kX86CondPE = kX86CondP, 524 525 kX86CondNp = 0xb, // 8-bit parity odd 526 kX86CondPo = kX86CondNp, 527 528 kX86CondL = 0xc, // less-than 529 kX86CondNge = kX86CondL, // not-greater-equal 530 531 kX86CondNl = 0xd, // not-less-than 532 kX86CondGe = kX86CondNl, // not-greater-equal 533 534 kX86CondLe = 0xe, // less-than-equal 535 kX86CondNg = kX86CondLe, // not-greater 536 537 kX86CondNle = 0xf, // not-less-than 538 kX86CondG = kX86CondNle, // greater 539 }; 540 std::ostream& operator<<(std::ostream& os, const X86ConditionCode& kind); 541 542 enum DividePattern { 543 DivideNone, 544 Divide3, 545 Divide5, 546 Divide7, 547 }; 548 std::ostream& operator<<(std::ostream& os, const DividePattern& pattern); 549 550 /** 551 * @brief Memory barrier types (see "The JSR-133 Cookbook for Compiler Writers"). 552 * @details We define the combined barrier types that are actually required 553 * by the Java Memory Model, rather than using exactly the terminology from 554 * the JSR-133 cookbook. These should, in many cases, be replaced by acquire/release 555 * primitives. Note that the JSR-133 cookbook generally does not deal with 556 * store atomicity issues, and the recipes there are not always entirely sufficient. 557 * The current recipe is as follows: 558 * -# Use AnyStore ~= (LoadStore | StoreStore) ~= release barrier before volatile store. 559 * -# Use AnyAny barrier after volatile store. (StoreLoad is as expensive.) 560 * -# Use LoadAny barrier ~= (LoadLoad | LoadStore) ~= acquire barrier after each volatile load. 561 * -# Use StoreStore barrier after all stores but before return from any constructor whose 562 * class has final fields. 563 * -# Use NTStoreStore to order non-temporal stores with respect to all later 564 * store-to-memory instructions. Only generated together with non-temporal stores. 565 */ 566 enum MemBarrierKind { 567 kAnyStore, 568 kLoadAny, 569 kStoreStore, 570 kAnyAny, 571 kNTStoreStore, 572 kLastBarrierKind = kNTStoreStore 573 }; 574 std::ostream& operator<<(std::ostream& os, const MemBarrierKind& kind); 575 576 enum OpFeatureFlags { 577 kIsBranch = 0, 578 kNoOperand, 579 kIsUnaryOp, 580 kIsBinaryOp, 581 kIsTertiaryOp, 582 kIsQuadOp, 583 kIsQuinOp, 584 kIsSextupleOp, 585 kIsIT, 586 kIsMoveOp, 587 kMemLoad, 588 kMemStore, 589 kMemVolatile, 590 kMemScaledx0, 591 kMemScaledx2, 592 kMemScaledx4, 593 kPCRelFixup, // x86 FIXME: add NEEDS_FIXUP to instruction attributes. 594 kRegDef0, 595 kRegDef1, 596 kRegDef2, 597 kRegDefA, 598 kRegDefD, 599 kRegDefFPCSList0, 600 kRegDefFPCSList2, 601 kRegDefList0, 602 kRegDefList1, 603 kRegDefList2, 604 kRegDefLR, 605 kRegDefSP, 606 kRegUse0, 607 kRegUse1, 608 kRegUse2, 609 kRegUse3, 610 kRegUse4, 611 kRegUseA, 612 kRegUseC, 613 kRegUseD, 614 kRegUseB, 615 kRegUseFPCSList0, 616 kRegUseFPCSList2, 617 kRegUseList0, 618 kRegUseList1, 619 kRegUseLR, 620 kRegUsePC, 621 kRegUseSP, 622 kSetsCCodes, 623 kUsesCCodes, 624 kUseFpStack, 625 kUseHi, 626 kUseLo, 627 kDefHi, 628 kDefLo 629 }; 630 std::ostream& operator<<(std::ostream& os, const OpFeatureFlags& rhs); 631 632 enum SelectInstructionKind { 633 kSelectNone, 634 kSelectConst, 635 kSelectMove, 636 kSelectGoto 637 }; 638 std::ostream& operator<<(std::ostream& os, const SelectInstructionKind& kind); 639 640 // LIR fixup kinds for Arm and X86. 641 enum FixupKind { 642 kFixupNone, 643 kFixupLabel, // For labels we just adjust the offset. 644 kFixupLoad, // Mostly for immediates. 645 kFixupVLoad, // FP load which *may* be pc-relative. 646 kFixupCBxZ, // Cbz, Cbnz. 647 kFixupTBxZ, // Tbz, Tbnz. 648 kFixupCondBranch, // Conditional branch 649 kFixupT1Branch, // Thumb1 Unconditional branch 650 kFixupT2Branch, // Thumb2 Unconditional branch 651 kFixupBlx1, // Blx1 (start of Blx1/Blx2 pair). 652 kFixupBl1, // Bl1 (start of Bl1/Bl2 pair). 653 kFixupAdr, // Adr. 654 kFixupMovImmLST, // kThumb2MovImm16LST. 655 kFixupMovImmHST, // kThumb2MovImm16HST. 656 kFixupAlign4, // Align to 4-byte boundary. 657 kFixupA53Erratum835769, // Cortex A53 Erratum 835769. 658 kFixupSwitchTable, // X86_64 packed switch table. 659 }; 660 std::ostream& operator<<(std::ostream& os, const FixupKind& kind); 661 662 enum VolatileKind { 663 kNotVolatile, // Load/Store is not volatile 664 kVolatile // Load/Store is volatile 665 }; 666 std::ostream& operator<<(std::ostream& os, const VolatileKind& kind); 667 668 enum WideKind { 669 kNotWide, // Non-wide view 670 kWide, // Wide view 671 kRef // Ref width 672 }; 673 std::ostream& operator<<(std::ostream& os, const WideKind& kind); 674 675 } // namespace art 676 677 #endif // ART_COMPILER_DEX_COMPILER_ENUMS_H_ 678