Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
//===-- SystemZOperands.td - SystemZ instruction operands ----*- tblgen-*--===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// Class definitions
//===----------------------------------------------------------------------===//

class ImmediateAsmOperand<string name>
  : AsmOperandClass {
  let Name = name;
  let RenderMethod = "addImmOperands";
}
class ImmediateTLSAsmOperand<string name>
  : AsmOperandClass {
  let Name = name;
  let RenderMethod = "addImmTLSOperands";
}

class ImmediateOp<ValueType vt, string asmop> : Operand<vt> {
  let PrintMethod = "print"#asmop#"Operand";
  let DecoderMethod = "decode"#asmop#"Operand";
  let ParserMatchClass = !cast<AsmOperandClass>(asmop);
  let OperandType = "OPERAND_IMMEDIATE";
}

class ImmOpWithPattern<ValueType vt, string asmop, code pred, SDNodeXForm xform,
      SDNode ImmNode = imm> :
  ImmediateOp<vt, asmop>, PatLeaf<(vt ImmNode), pred, xform>;

// class ImmediatePatLeaf<ValueType vt, code pred,
//       SDNodeXForm xform, SDNode ImmNode>
//   : PatLeaf<(vt ImmNode), pred, xform>;


// Constructs both a DAG pattern and instruction operand for an immediate
// of type VT.  PRED returns true if a node is acceptable and XFORM returns
// the operand value associated with the node.  ASMOP is the name of the
// associated asm operand, and also forms the basis of the asm print method.
multiclass Immediate<ValueType vt, code pred, SDNodeXForm xform, string asmop> {
  // def "" : ImmediateOp<vt, asmop>,
  //          PatLeaf<(vt imm), pred, xform>;
  def "" : ImmOpWithPattern<vt, asmop, pred, xform>;

//  def _timm : PatLeaf<(vt timm), pred, xform>;
  def _timm : ImmOpWithPattern<vt, asmop, pred, xform, timm>;
}

// Constructs an asm operand for a PC-relative address.  SIZE says how
// many bits there are.
class PCRelAsmOperand<string size> : ImmediateAsmOperand<"PCRel"#size> {
  let PredicateMethod = "isImm";
  let ParserMethod = "parsePCRel"#size;
}
class PCRelTLSAsmOperand<string size>
  : ImmediateTLSAsmOperand<"PCRelTLS"#size> {
  let PredicateMethod = "isImmTLS";
  let ParserMethod = "parsePCRelTLS"#size;
}

// Constructs an operand for a PC-relative address with address type VT.
// ASMOP is the associated asm operand.
let OperandType = "OPERAND_PCREL" in {
  class PCRelOperand<ValueType vt, AsmOperandClass asmop> : Operand<vt> {
    let PrintMethod = "printPCRelOperand";
    let ParserMatchClass = asmop;
  }
  class PCRelTLSOperand<ValueType vt, AsmOperandClass asmop> : Operand<vt> {
    let PrintMethod = "printPCRelTLSOperand";
    let ParserMatchClass = asmop;
  }
}

// Constructs both a DAG pattern and instruction operand for a PC-relative
// address with address size VT.  SELF is the name of the operand and
// ASMOP is the associated asm operand.
class PCRelAddress<ValueType vt, string self, AsmOperandClass asmop>
  : ComplexPattern<vt, 1, "selectPCRelAddress",
                   [z_pcrel_wrapper, z_pcrel_offset]>,
    PCRelOperand<vt, asmop> {
  let MIOperandInfo = (ops !cast<Operand>(self));
}

// Constructs an AsmOperandClass for addressing mode FORMAT, treating the
// registers as having BITSIZE bits and displacements as having DISPSIZE bits.
// LENGTH is "LenN" for addresses with an N-bit length field, otherwise it
// is "".
class AddressAsmOperand<string format, string bitsize, string dispsize,
                        string length = "">
  : AsmOperandClass {
  let Name = format#bitsize#"Disp"#dispsize#length;
  let ParserMethod = "parse"#format#bitsize;
  let RenderMethod = "add"#format#"Operands";
}

// Constructs an instruction operand for an addressing mode.  FORMAT,
// BITSIZE, DISPSIZE and LENGTH are the parameters to an associated
// AddressAsmOperand.  OPERANDS is a list of individual operands
// (base register, displacement, etc.).
class AddressOperand<string bitsize, string dispsize, string length,
                     string format, dag operands>
  : Operand<!cast<ValueType>("i"#bitsize)> {
  let PrintMethod = "print"#format#"Operand";
  let EncoderMethod = "get"#format#dispsize#length#"Encoding";
  let DecoderMethod =
    "decode"#format#bitsize#"Disp"#dispsize#length#"Operand";
  let OperandType = "OPERAND_MEMORY";
  let MIOperandInfo = operands;
  let ParserMatchClass =
    !cast<AddressAsmOperand>(format#bitsize#"Disp"#dispsize#length);
}

// Constructs both a DAG pattern and instruction operand for an addressing mode.
// FORMAT, BITSIZE, DISPSIZE and LENGTH are the parameters to an associated
// AddressAsmOperand.  OPERANDS is a list of NUMOPS individual operands
// (base register, displacement, etc.).  SELTYPE is the type of the memory
// operand for selection purposes; sometimes we want different selection
// choices for the same underlying addressing mode.  SUFFIX is similarly
// a suffix appended to the displacement for selection purposes;
// e.g. we want to reject small 20-bit displacements if a 12-bit form
// also exists, but we want to accept them otherwise.
class AddressingMode<string seltype, string bitsize, string dispsize,
                     string suffix, string length, int numops, string format,
                     dag operands>
  : ComplexPattern<!cast<ValueType>("i"#bitsize), numops,
                   "select"#seltype#dispsize#suffix#length,
                   [add, sub, or, frameindex, z_adjdynalloc]>,
    AddressOperand<bitsize, dispsize, length, format, operands>;

// An addressing mode with a base and displacement but no index.
class BDMode<string type, string bitsize, string dispsize, string suffix>
  : AddressingMode<type, bitsize, dispsize, suffix, "", 2, "BDAddr",
                   (ops !cast<RegisterOperand>("ADDR"#bitsize),
                        !cast<Operand>("disp"#dispsize#"imm"#bitsize))>;

// An addressing mode with a base, displacement and index.
class BDXMode<string type, string bitsize, string dispsize, string suffix>
  : AddressingMode<type, bitsize, dispsize, suffix, "", 3, "BDXAddr",
                   (ops !cast<RegisterOperand>("ADDR"#bitsize),
                        !cast<Operand>("disp"#dispsize#"imm"#bitsize),
                        !cast<RegisterOperand>("ADDR"#bitsize))>;

// A BDMode paired with an immediate length operand of LENSIZE bits.
class BDLMode<string type, string bitsize, string dispsize, string suffix,
              string lensize>
  : AddressingMode<type, bitsize, dispsize, suffix, "Len"#lensize, 3,
                   "BDLAddr",
                   (ops !cast<RegisterOperand>("ADDR"#bitsize),
                        !cast<Operand>("disp"#dispsize#"imm"#bitsize),
                        !cast<Operand>("imm"#bitsize))>;

// A BDMode paired with a register length operand.
class BDRMode<string type, string bitsize, string dispsize, string suffix>
  : AddressingMode<type, bitsize, dispsize, suffix, "", 3, "BDRAddr",
                   (ops !cast<RegisterOperand>("ADDR"#bitsize),
                        !cast<Operand>("disp"#dispsize#"imm"#bitsize),
                        !cast<RegisterOperand>("GR"#bitsize))>;

// An addressing mode with a base, displacement and a vector index.
class BDVMode<string bitsize, string dispsize>
  : AddressOperand<bitsize, dispsize, "", "BDVAddr",
                   (ops !cast<RegisterOperand>("ADDR"#bitsize),
                        !cast<Operand>("disp"#dispsize#"imm"#bitsize),
                        !cast<RegisterOperand>("VR128"))>;

//===----------------------------------------------------------------------===//
// Extracting immediate operands from nodes
// These all create MVT::i64 nodes to ensure the value is not sign-extended
// when converted from an SDNode to a MachineOperand later on.
//===----------------------------------------------------------------------===//

// Bits 0-15 (counting from the lsb).
def LL16 : SDNodeXForm<imm, [{
  uint64_t Value = N->getZExtValue() & 0x000000000000FFFFULL;
  return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i64);
}]>;

// Bits 16-31 (counting from the lsb).
def LH16 : SDNodeXForm<imm, [{
  uint64_t Value = (N->getZExtValue() & 0x00000000FFFF0000ULL) >> 16;
  return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i64);
}]>;

// Bits 32-47 (counting from the lsb).
def HL16 : SDNodeXForm<imm, [{
  uint64_t Value = (N->getZExtValue() & 0x0000FFFF00000000ULL) >> 32;
  return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i64);
}]>;

// Bits 48-63 (counting from the lsb).
def HH16 : SDNodeXForm<imm, [{
  uint64_t Value = (N->getZExtValue() & 0xFFFF000000000000ULL) >> 48;
  return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i64);
}]>;

// Low 32 bits.
def LF32 : SDNodeXForm<imm, [{
  uint64_t Value = N->getZExtValue() & 0x00000000FFFFFFFFULL;
  return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i64);
}]>;

// High 32 bits.
def HF32 : SDNodeXForm<imm, [{
  uint64_t Value = N->getZExtValue() >> 32;
  return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i64);
}]>;

// Negated variants.
def NEGLH16 : SDNodeXForm<imm, [{
  uint64_t Value = (-N->getZExtValue() & 0x00000000FFFF0000ULL) >> 16;
  return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i64);
}]>;

def NEGLF32 : SDNodeXForm<imm, [{
  uint64_t Value = -N->getZExtValue() & 0x00000000FFFFFFFFULL;
  return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i64);
}]>;

// Truncate an immediate to a 8-bit signed quantity.
def SIMM8 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(int8_t(N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Truncate an immediate to a 8-bit unsigned quantity.
def UIMM8 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(uint8_t(N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Truncate an immediate to a 8-bit unsigned quantity and mask off low bit.
def UIMM8EVEN : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(N->getZExtValue() & 0xfe, SDLoc(N),
                                   MVT::i64);
}]>;

// Truncate an immediate to a 12-bit unsigned quantity.
def UIMM12 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(N->getZExtValue() & 0xfff, SDLoc(N),
                                   MVT::i64);
}]>;

// Truncate an immediate to a 16-bit signed quantity.
def SIMM16 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(int16_t(N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Negate and then truncate an immediate to a 16-bit signed quantity.
def NEGSIMM16 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(int16_t(-N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Truncate an immediate to a 16-bit unsigned quantity.
def UIMM16 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(uint16_t(N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Truncate an immediate to a 32-bit signed quantity.
def SIMM32 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(int32_t(N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Negate and then truncate an immediate to a 32-bit unsigned quantity.
def NEGSIMM32 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(int32_t(-N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Truncate an immediate to a 32-bit unsigned quantity.
def UIMM32 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(uint32_t(N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Negate and then truncate an immediate to a 32-bit unsigned quantity.
def NEGUIMM32 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(uint32_t(-N->getZExtValue()), SDLoc(N),
                                   MVT::i64);
}]>;

// Truncate an immediate to a 48-bit unsigned quantity.
def UIMM48 : SDNodeXForm<imm, [{
  return CurDAG->getTargetConstant(uint64_t(N->getZExtValue()) & 0xffffffffffff,
                                   SDLoc(N), MVT::i64);
}]>;

//===----------------------------------------------------------------------===//
// Immediate asm operands.
//===----------------------------------------------------------------------===//

def U1Imm  : ImmediateAsmOperand<"U1Imm">;
def U2Imm  : ImmediateAsmOperand<"U2Imm">;
def U3Imm  : ImmediateAsmOperand<"U3Imm">;
def U4Imm  : ImmediateAsmOperand<"U4Imm">;
def U6Imm  : ImmediateAsmOperand<"U6Imm">;
def S8Imm  : ImmediateAsmOperand<"S8Imm">;
def U8Imm  : ImmediateAsmOperand<"U8Imm">;
def U12Imm : ImmediateAsmOperand<"U12Imm">;
def S16Imm : ImmediateAsmOperand<"S16Imm">;
def U16Imm : ImmediateAsmOperand<"U16Imm">;
def S32Imm : ImmediateAsmOperand<"S32Imm">;
def U32Imm : ImmediateAsmOperand<"U32Imm">;
def U48Imm : ImmediateAsmOperand<"U48Imm">;

//===----------------------------------------------------------------------===//
// i32 immediates
//===----------------------------------------------------------------------===//

// Immediates for the lower and upper 16 bits of an i32, with the other
// bits of the i32 being zero.
defm imm32ll16 : Immediate<i32, [{
  return SystemZ::isImmLL(N->getZExtValue());
}], LL16, "U16Imm">;

defm imm32lh16 : Immediate<i32, [{
  return SystemZ::isImmLH(N->getZExtValue());
}], LH16, "U16Imm">;

// Immediates for the lower and upper 16 bits of an i32, with the other
// bits of the i32 being one.
defm imm32ll16c : Immediate<i32, [{
  return SystemZ::isImmLL(uint32_t(~N->getZExtValue()));
}], LL16, "U16Imm">;

defm imm32lh16c : Immediate<i32, [{
  return SystemZ::isImmLH(uint32_t(~N->getZExtValue()));
}], LH16, "U16Imm">;

// Short immediates
defm imm32zx1 : Immediate<i32, [{
  return isUInt<1>(N->getZExtValue());
}], NOOP_SDNodeXForm, "U1Imm">;

defm imm32zx2 : Immediate<i32, [{
  return isUInt<2>(N->getZExtValue());
}], NOOP_SDNodeXForm, "U2Imm">;

defm imm32zx3 : Immediate<i32, [{
  return isUInt<3>(N->getZExtValue());
}], NOOP_SDNodeXForm, "U3Imm">;

defm imm32zx4 : Immediate<i32, [{
  return isUInt<4>(N->getZExtValue());
}], NOOP_SDNodeXForm, "U4Imm">;

// Note: this enforces an even value during code generation only.
// When used from the assembler, any 4-bit value is allowed.
defm imm32zx4even : Immediate<i32, [{
  return isUInt<4>(N->getZExtValue());
}], UIMM8EVEN, "U4Imm">;

defm imm32zx6 : Immediate<i32, [{
  return isUInt<6>(N->getZExtValue());
}], NOOP_SDNodeXForm, "U6Imm">;

defm imm32sx8 : Immediate<i32, [{
  return isInt<8>(N->getSExtValue());
}], SIMM8, "S8Imm">;

defm imm32zx8 : Immediate<i32, [{
  return isUInt<8>(N->getZExtValue());
}], UIMM8, "U8Imm">;

defm imm32zx8trunc : Immediate<i32, [{}], UIMM8, "U8Imm">;

defm imm32zx12 : Immediate<i32, [{
  return isUInt<12>(N->getZExtValue());
}], UIMM12, "U12Imm">;

defm imm32sx16 : Immediate<i32, [{
  return isInt<16>(N->getSExtValue());
}], SIMM16, "S16Imm">;

defm imm32sx16n : Immediate<i32, [{
  return isInt<16>(-N->getSExtValue());
}], NEGSIMM16, "S16Imm">;

defm imm32zx16 : Immediate<i32, [{
  return isUInt<16>(N->getZExtValue());
}], UIMM16, "U16Imm">;

defm imm32sx16trunc : Immediate<i32, [{}], SIMM16, "S16Imm">;
defm imm32zx16trunc : Immediate<i32, [{}], UIMM16, "U16Imm">;

// Full 32-bit immediates.  we need both signed and unsigned versions
// because the assembler is picky.  E.g. AFI requires signed operands
// while NILF requires unsigned ones.
defm simm32 : Immediate<i32, [{}], SIMM32, "S32Imm">;
defm uimm32 : Immediate<i32, [{}], UIMM32, "U32Imm">;

defm simm32n : Immediate<i32, [{
  return isInt<32>(-N->getSExtValue());
}], NEGSIMM32, "S32Imm">;

def imm32 : ImmLeaf<i32, [{}]>;

//===----------------------------------------------------------------------===//
// 64-bit immediates
//===----------------------------------------------------------------------===//

// Immediates for 16-bit chunks of an i64, with the other bits of the
// i32 being zero.
defm imm64ll16 : Immediate<i64, [{
  return SystemZ::isImmLL(N->getZExtValue());
}], LL16, "U16Imm">;

defm imm64lh16 : Immediate<i64, [{
  return SystemZ::isImmLH(N->getZExtValue());
}], LH16, "U16Imm">;

defm imm64hl16 : Immediate<i64, [{
  return SystemZ::isImmHL(N->getZExtValue());
}], HL16, "U16Imm">;

defm imm64hh16 : Immediate<i64, [{
  return SystemZ::isImmHH(N->getZExtValue());
}], HH16, "U16Imm">;

// Immediates for 16-bit chunks of an i64, with the other bits of the
// i32 being one.
defm imm64ll16c : Immediate<i64, [{
  return SystemZ::isImmLL(uint64_t(~N->getZExtValue()));
}], LL16, "U16Imm">;

defm imm64lh16c : Immediate<i64, [{
  return SystemZ::isImmLH(uint64_t(~N->getZExtValue()));
}], LH16, "U16Imm">;

defm imm64hl16c : Immediate<i64, [{
  return SystemZ::isImmHL(uint64_t(~N->getZExtValue()));
}], HL16, "U16Imm">;

defm imm64hh16c : Immediate<i64, [{
  return SystemZ::isImmHH(uint64_t(~N->getZExtValue()));
}], HH16, "U16Imm">;

// Immediates for the lower and upper 32 bits of an i64, with the other
// bits of the i32 being zero.
defm imm64lf32 : Immediate<i64, [{
  return SystemZ::isImmLF(N->getZExtValue());
}], LF32, "U32Imm">;

defm imm64hf32 : Immediate<i64, [{
  return SystemZ::isImmHF(N->getZExtValue());
}], HF32, "U32Imm">;

// Immediates for the lower and upper 32 bits of an i64, with the other
// bits of the i32 being one.
defm imm64lf32c : Immediate<i64, [{
  return SystemZ::isImmLF(uint64_t(~N->getZExtValue()));
}], LF32, "U32Imm">;

defm imm64hf32c : Immediate<i64, [{
  return SystemZ::isImmHF(uint64_t(~N->getZExtValue()));
}], HF32, "U32Imm">;

// Negated immediates that fit LF32 or LH16.
defm imm64lh16n : Immediate<i64, [{
  return SystemZ::isImmLH(uint64_t(-N->getZExtValue()));
}], NEGLH16, "U16Imm">;

defm imm64lf32n : Immediate<i64, [{
  return SystemZ::isImmLF(uint64_t(-N->getZExtValue()));
}], NEGLF32, "U32Imm">;

// Short immediates.
defm imm64sx8 : Immediate<i64, [{
  return isInt<8>(N->getSExtValue());
}], SIMM8, "S8Imm">;

defm imm64zx8 : Immediate<i64, [{
  return isUInt<8>(N->getSExtValue());
}], UIMM8, "U8Imm">;

defm imm64sx16 : Immediate<i64, [{
  return isInt<16>(N->getSExtValue());
}], SIMM16, "S16Imm">;

defm imm64sx16n : Immediate<i64, [{
  return isInt<16>(-N->getSExtValue());
}], NEGSIMM16, "S16Imm">;

defm imm64zx16 : Immediate<i64, [{
  return isUInt<16>(N->getZExtValue());
}], UIMM16, "U16Imm">;

defm imm64sx32 : Immediate<i64, [{
  return isInt<32>(N->getSExtValue());
}], SIMM32, "S32Imm">;

defm imm64sx32n : Immediate<i64, [{
  return isInt<32>(-N->getSExtValue());
}], NEGSIMM32, "S32Imm">;

defm imm64zx32 : Immediate<i64, [{
  return isUInt<32>(N->getZExtValue());
}], UIMM32, "U32Imm">;

defm imm64zx32n : Immediate<i64, [{
  return isUInt<32>(-N->getSExtValue());
}], NEGUIMM32, "U32Imm">;

defm imm64zx48 : Immediate<i64, [{
  return isUInt<64>(N->getZExtValue());
}], UIMM48, "U48Imm">;

let OperandType = "OPERAND_IMMEDIATE" in
  def imm64 : ImmLeaf<i64, [{}]>, Operand<i64>;

//===----------------------------------------------------------------------===//
// Floating-point immediates
//===----------------------------------------------------------------------===//

// Floating-point zero.
def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>;

// Floating point negative zero.
def fpimmneg0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(-0.0); }]>;

//===----------------------------------------------------------------------===//
// Symbolic address operands
//===----------------------------------------------------------------------===//

// PC-relative asm operands.
def PCRel12 : PCRelAsmOperand<"12">;
def PCRel16 : PCRelAsmOperand<"16">;
def PCRel24 : PCRelAsmOperand<"24">;
def PCRel32 : PCRelAsmOperand<"32">;
def PCRelTLS16 : PCRelTLSAsmOperand<"16">;
def PCRelTLS32 : PCRelTLSAsmOperand<"32">;

// PC-relative offsets of a basic block.  The offset is sign-extended
// and multiplied by 2.
def brtarget16 : PCRelOperand<OtherVT, PCRel16> {
  let EncoderMethod = "getPC16DBLEncoding";
  let DecoderMethod = "decodePC16DBLBranchOperand";
}
def brtarget32 : PCRelOperand<OtherVT, PCRel32> {
  let EncoderMethod = "getPC32DBLEncoding";
  let DecoderMethod = "decodePC32DBLBranchOperand";
}

// Variants of brtarget for use with branch prediction preload.
def brtarget12bpp : PCRelOperand<OtherVT, PCRel12> {
  let EncoderMethod = "getPC12DBLBPPEncoding";
  let DecoderMethod = "decodePC12DBLBranchOperand";
}
def brtarget16bpp : PCRelOperand<OtherVT, PCRel16> {
  let EncoderMethod = "getPC16DBLBPPEncoding";
  let DecoderMethod = "decodePC16DBLBranchOperand";
}
def brtarget24bpp : PCRelOperand<OtherVT, PCRel24> {
  let EncoderMethod = "getPC24DBLBPPEncoding";
  let DecoderMethod = "decodePC24DBLBranchOperand";
}

// Variants of brtarget16/32 with an optional additional TLS symbol.
// These are used to annotate calls to __tls_get_offset.
def tlssym : Operand<i64> { }
def brtarget16tls : PCRelTLSOperand<OtherVT, PCRelTLS16> {
  let MIOperandInfo = (ops brtarget16:$func, tlssym:$sym);
  let EncoderMethod = "getPC16DBLTLSEncoding";
  let DecoderMethod = "decodePC16DBLBranchOperand";
}
def brtarget32tls : PCRelTLSOperand<OtherVT, PCRelTLS32> {
  let MIOperandInfo = (ops brtarget32:$func, tlssym:$sym);
  let EncoderMethod = "getPC32DBLTLSEncoding";
  let DecoderMethod = "decodePC32DBLBranchOperand";
}

// A PC-relative offset of a global value.  The offset is sign-extended
// and multiplied by 2.
def pcrel32 : PCRelAddress<i64, "pcrel32", PCRel32> {
  let EncoderMethod = "getPC32DBLEncoding";
  let DecoderMethod = "decodePC32DBLOperand";
}

//===----------------------------------------------------------------------===//
// Addressing modes
//===----------------------------------------------------------------------===//

// 12-bit displacement operands.
def disp12imm32 : Operand<i32>;
def disp12imm64 : Operand<i64>;

// 20-bit displacement operands.
def disp20imm32 : Operand<i32>;
def disp20imm64 : Operand<i64>;

def BDAddr32Disp12      : AddressAsmOperand<"BDAddr",   "32", "12">;
def BDAddr32Disp20      : AddressAsmOperand<"BDAddr",   "32", "20">;
def BDAddr64Disp12      : AddressAsmOperand<"BDAddr",   "64", "12">;
def BDAddr64Disp20      : AddressAsmOperand<"BDAddr",   "64", "20">;
def BDXAddr64Disp12     : AddressAsmOperand<"BDXAddr",  "64", "12">;
def BDXAddr64Disp20     : AddressAsmOperand<"BDXAddr",  "64", "20">;
def BDLAddr64Disp12Len4 : AddressAsmOperand<"BDLAddr",  "64", "12", "Len4">;
def BDLAddr64Disp12Len8 : AddressAsmOperand<"BDLAddr",  "64", "12", "Len8">;
def BDRAddr64Disp12     : AddressAsmOperand<"BDRAddr",  "64", "12">;
def BDVAddr64Disp12     : AddressAsmOperand<"BDVAddr",  "64", "12">;

// DAG patterns and operands for addressing modes.  Each mode has
// the form <type><range><group>[<len>] where:
//
// <type> is one of:
//   shift    : base + displacement (32-bit)
//   bdaddr   : base + displacement
//   mviaddr  : like bdaddr, but reject cases with a natural index
//   bdxaddr  : base + displacement + index
//   laaddr   : like bdxaddr, but used for Load Address operations
//   dynalloc : base + displacement + index + ADJDYNALLOC
//   bdladdr  : base + displacement with a length field
//   bdvaddr  : base + displacement with a vector index
//
// <range> is one of:
//   12       : the displacement is an unsigned 12-bit value
//   20       : the displacement is a signed 20-bit value
//
// <group> is one of:
//   pair     : used when there is an equivalent instruction with the opposite
//              range value (12 or 20)
//   only     : used when there is no equivalent instruction with the opposite
//              range value
//
// <len> is one of:
//
//   <empty>  : there is no length field
//   len8     : the length field is 8 bits, with a range of [1, 0x100].
def shift12only       : BDMode <"BDAddr",   "32", "12", "Only">;
def shift20only       : BDMode <"BDAddr",   "32", "20", "Only">;
def bdaddr12only      : BDMode <"BDAddr",   "64", "12", "Only">;
def bdaddr12pair      : BDMode <"BDAddr",   "64", "12", "Pair">;
def bdaddr20only      : BDMode <"BDAddr",   "64", "20", "Only">;
def bdaddr20pair      : BDMode <"BDAddr",   "64", "20", "Pair">;
def mviaddr12pair     : BDMode <"MVIAddr",  "64", "12", "Pair">;
def mviaddr20pair     : BDMode <"MVIAddr",  "64", "20", "Pair">;
def bdxaddr12only     : BDXMode<"BDXAddr",  "64", "12", "Only">;
def bdxaddr12pair     : BDXMode<"BDXAddr",  "64", "12", "Pair">;
def bdxaddr20only     : BDXMode<"BDXAddr",  "64", "20", "Only">;
def bdxaddr20only128  : BDXMode<"BDXAddr",  "64", "20", "Only128">;
def bdxaddr20pair     : BDXMode<"BDXAddr",  "64", "20", "Pair">;
def dynalloc12only    : BDXMode<"DynAlloc", "64", "12", "Only">;
def laaddr12pair      : BDXMode<"LAAddr",   "64", "12", "Pair">;
def laaddr20pair      : BDXMode<"LAAddr",   "64", "20", "Pair">;
def bdladdr12onlylen4 : BDLMode<"BDLAddr",  "64", "12", "Only", "4">;
def bdladdr12onlylen8 : BDLMode<"BDLAddr",  "64", "12", "Only", "8">;
def bdraddr12only     : BDRMode<"BDRAddr",  "64", "12", "Only">;
def bdvaddr12only     : BDVMode<            "64", "12">;

//===----------------------------------------------------------------------===//
// Miscellaneous
//===----------------------------------------------------------------------===//

// A 4-bit condition-code mask.
def cond4 : PatLeaf<(i32 timm), [{ return (N->getZExtValue() < 16); }]>,
            Operand<i32> {
  let PrintMethod = "printCond4Operand";
  let OperandType = "OPERAND_IMMEDIATE";
}