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
22namespace art {
23
24enum RegisterClass {
25  kInvalidRegClass,
26  kCoreReg,
27  kFPReg,
28  kRefReg,
29  kAnyReg,
30};
31std::ostream& operator<<(std::ostream& os, const RegisterClass& rhs);
32
33enum BitsUsed {
34  kSize32Bits,
35  kSize64Bits,
36  kSize128Bits,
37  kSize256Bits,
38  kSize512Bits,
39  kSize1024Bits,
40};
41std::ostream& operator<<(std::ostream& os, const BitsUsed& rhs);
42
43enum 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};
80std::ostream& operator<<(std::ostream& os, const SpecialTargetRegister& code);
81
82enum RegLocationType {
83  kLocDalvikFrame = 0,  // Normal Dalvik register
84  kLocPhysReg,
85  kLocCompilerTemp,
86  kLocInvalid
87};
88std::ostream& operator<<(std::ostream& os, const RegLocationType& rhs);
89
90enum BBType {
91  kNullBlock,
92  kEntryBlock,
93  kDalvikByteCode,
94  kExitBlock,
95  kExceptionHandling,
96  kDead,
97};
98std::ostream& operator<<(std::ostream& os, const BBType& code);
99
100// Shared pseudo opcodes - must be < 0.
101enum 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};
121std::ostream& operator<<(std::ostream& os, const LIRPseudoOpcode& rhs);
122
123enum 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
346enum 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.
366enum BlockListType {
367  kNotUsed = 0,
368  kCatch,
369  kPackedSwitch,
370  kSparseSwitch,
371};
372std::ostream& operator<<(std::ostream& os, const BlockListType& rhs);
373
374enum AssemblerStatus {
375  kSuccess,
376  kRetryAll,
377};
378std::ostream& operator<<(std::ostream& os, const AssemblerStatus& rhs);
379
380enum 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};
392std::ostream& operator<<(std::ostream& os, const OpSize& kind);
393
394enum 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};
433std::ostream& operator<<(std::ostream& os, const OpKind& rhs);
434
435enum 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};
450std::ostream& operator<<(std::ostream& os, const MoveType& kind);
451
452enum 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};
472std::ostream& operator<<(std::ostream& os, const ConditionCode& kind);
473
474// Target specific condition encodings
475enum 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};
493std::ostream& operator<<(std::ostream& os, const ArmConditionCode& kind);
494
495enum 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};
540std::ostream& operator<<(std::ostream& os, const X86ConditionCode& kind);
541
542enum DividePattern {
543  DivideNone,
544  Divide3,
545  Divide5,
546  Divide7,
547};
548std::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 */
566enum MemBarrierKind {
567  kAnyStore,
568  kLoadAny,
569  kStoreStore,
570  kAnyAny,
571  kNTStoreStore,
572  kLastBarrierKind = kNTStoreStore
573};
574std::ostream& operator<<(std::ostream& os, const MemBarrierKind& kind);
575
576enum 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};
630std::ostream& operator<<(std::ostream& os, const OpFeatureFlags& rhs);
631
632enum SelectInstructionKind {
633  kSelectNone,
634  kSelectConst,
635  kSelectMove,
636  kSelectGoto
637};
638std::ostream& operator<<(std::ostream& os, const SelectInstructionKind& kind);
639
640// LIR fixup kinds for Arm and X86.
641enum 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};
660std::ostream& operator<<(std::ostream& os, const FixupKind& kind);
661
662enum VolatileKind {
663  kNotVolatile,      // Load/Store is not volatile
664  kVolatile          // Load/Store is volatile
665};
666std::ostream& operator<<(std::ostream& os, const VolatileKind& kind);
667
668enum WideKind {
669  kNotWide,      // Non-wide view
670  kWide,         // Wide view
671  kRef           // Ref width
672};
673std::ostream& operator<<(std::ostream& os, const WideKind& kind);
674
675}  // namespace art
676
677#endif  // ART_COMPILER_DEX_COMPILER_ENUMS_H_
678