aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/IA64/IA64InstrInfo.td
blob: 8801a728f74ef907a908efcc06fe750fccea8079 (plain)
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
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
//===- IA64InstrInfo.td - Describe the IA64 Instruction Set -----*- C++ -*-===//
// 
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Duraid Madina and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
//
// This file describes the IA64 instruction set, defining the instructions, and
// properties of the instructions which are needed for code generation, machine
// code emission, and analysis.
//
//===----------------------------------------------------------------------===//

include "IA64InstrFormats.td"

//===----------------------------------------------------------------------===//
// IA-64 specific DAG Nodes.
//

def IA64getfd : SDNode<"IA64ISD::GETFD", SDTFPToIntOp, []>;

def SDT_IA64RetFlag : SDTypeProfile<0, 0, []>;
def retflag         : SDNode<"IA64ISD::RET_FLAG", SDT_IA64RetFlag,
	                   [SDNPHasChain, SDNPOptInFlag]>;

//===---------
// Instruction types

class isA { bit A=1; } // I or M unit
class isM { bit M=1; } // M unit
class isI { bit I=1; } // I unit
class isB { bit B=1; } // B unit
class isF { bit F=1; } // F unit
class isLX { bit LX=1; } // I/B

//===---------

def u2imm : Operand<i8>;
def u6imm : Operand<i8>;
def s8imm : Operand<i8> {
  let PrintMethod = "printS8ImmOperand";
}
def s14imm  : Operand<i64> {
  let PrintMethod = "printS14ImmOperand";
}
def s22imm  : Operand<i64> {
  let PrintMethod = "printS22ImmOperand";
}
def u64imm  : Operand<i64> {
  let PrintMethod = "printU64ImmOperand";
}
def s64imm  : Operand<i64> {
  let PrintMethod = "printS64ImmOperand";
}

let PrintMethod = "printGlobalOperand" in
  def globaladdress : Operand<i64>;

// the asmprinter needs to know about calls
let PrintMethod = "printCallOperand" in
  def calltarget : Operand<i64>;
  
/* new daggy action!!! */

def is32ones : PatLeaf<(i64 imm), [{
  // is32ones predicate - True if the immediate is 0x00000000FFFFFFFF 
  // Used to create ZXT4s appropriately 
  uint64_t v = (uint64_t)N->getValue();
  return (v == 0x00000000FFFFFFFFLL);
}]>;

// isMIXable predicates - True if the immediate is
// 0xFF00FF00FF00FF00, 0x00FF00FF00FF00FF
// etc, through 0x00000000FFFFFFFF
// Used to test for the suitability of mix* 
def isMIX1Lable: PatLeaf<(i64 imm), [{
  return((uint64_t)N->getValue()==0xFF00FF00FF00FF00LL);
}]>;
def isMIX1Rable: PatLeaf<(i64 imm), [{
  return((uint64_t)N->getValue()==0x00FF00FF00FF00FFLL);
}]>;
def isMIX2Lable: PatLeaf<(i64 imm), [{
  return((uint64_t)N->getValue()==0xFFFF0000FFFF0000LL);
}]>;
def isMIX2Rable: PatLeaf<(i64 imm), [{
  return((uint64_t)N->getValue()==0x0000FFFF0000FFFFLL);
}]>;
def isMIX4Lable: PatLeaf<(i64 imm), [{
  return((uint64_t)N->getValue()==0xFFFFFFFF00000000LL);
}]>;
def isMIX4Rable: PatLeaf<(i64 imm), [{
  return((uint64_t)N->getValue()==0x00000000FFFFFFFFLL);
}]>;

def isSHLADDimm: PatLeaf<(i64 imm), [{
  // isSHLADDimm predicate - True if the immediate is exactly 1, 2, 3 or 4
  // - 0 is *not* okay.
  // Used to create shladd instructions appropriately
  int64_t v = (int64_t)N->getValue();
  return (v >= 1 && v <= 4);
}]>;

def immSExt14  : PatLeaf<(i64 imm), [{
  // immSExt14 predicate - True if the immediate fits in a 14-bit sign extended
  // field.  Used by instructions like 'adds'.
  int64_t v = (int64_t)N->getValue();
  return (v <= 8191 && v >= -8192);
}]>;

// imm64 predicate - True if the immediate fits in a 64-bit 
// field - i.e., true. used to keep movl happy
def imm64  : PatLeaf<(i64 imm)>; 

def ADD  : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
           "add $dst = $src1, $src2",
	   [(set GR:$dst, (add GR:$src1, GR:$src2))]>, isA;

def ADD1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
           "add $dst = $src1, $src2, 1",
	   [(set GR:$dst, (add (add GR:$src1, GR:$src2), 1))]>, isA;

def ADDS : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm),
           "adds $dst = $imm, $src1",
	   [(set GR:$dst, (add GR:$src1, immSExt14:$imm))]>, isA;
 
def MOVL : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins s64imm:$imm),
           "movl $dst = $imm",
	   [(set GR:$dst, imm64:$imm)]>, isLX;

def ADDL_GA : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, globaladdress:$imm),
           "addl $dst = $imm, $src1",
	   []>, isA;

// hmm 
def ADDL_EA : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, calltarget:$imm),
           "addl $dst = $imm, $src1",
	   []>, isA;
 
def SUB  : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
           "sub $dst = $src1, $src2",
	   [(set GR:$dst, (sub GR:$src1, GR:$src2))]>, isA;

def SUB1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
           "sub $dst = $src1, $src2, 1",
	   [(set GR:$dst, (add (sub GR: $src1, GR:$src2), -1))]>, isA;

let isTwoAddress = 1 in {
def TPCADDIMM22 : AForm<0x03, 0x0b,
  (outs GR:$dst), (ins GR:$src1, s22imm:$imm, PR:$qp),
    "($qp) add $dst = $imm, $dst">, isA;
def TPCADDS : AForm_DAG<0x03, 0x0b,
  (outs GR:$dst), (ins GR:$src1, s14imm:$imm, PR:$qp),
    "($qp) adds $dst = $imm, $dst",
    []>, isA;
def TPCMPIMM8NE : AForm<0x03, 0x0b,
  (outs PR:$dst), (ins PR:$src1, s22imm:$imm, GR:$src2, PR:$qp),
    "($qp) cmp.ne $dst , p0 = $imm, $src2">, isA;
}

// zero extend a bool (predicate reg) into an integer reg
def ZXTb : Pat<(zext PR:$src),
          (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src)>;
def AXTb : Pat<(anyext PR:$src),
          (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src)>; 

// normal sign/zero-extends
def SXT1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt1 $dst = $src",
           [(set GR:$dst, (sext_inreg GR:$src, i8))]>, isI;
def ZXT1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt1 $dst = $src",
           [(set GR:$dst, (and GR:$src, 255))]>, isI;
def SXT2 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt2 $dst = $src",
           [(set GR:$dst, (sext_inreg GR:$src, i16))]>, isI;
def ZXT2 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt2 $dst = $src",
           [(set GR:$dst, (and GR:$src, 65535))]>, isI;
def SXT4 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt4 $dst = $src",
           [(set GR:$dst, (sext_inreg GR:$src, i32))]>, isI;
def ZXT4 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt4 $dst = $src",
           [(set GR:$dst, (and GR:$src, is32ones))]>, isI;

// fixme: shrs vs shru?
def MIX1L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "mix1.l $dst = $src1, $src2",
	  [(set GR:$dst, (or (and GR:$src1, isMIX1Lable),
	                     (and (srl GR:$src2, (i64 8)), isMIX1Lable)))]>, isI;

def MIX2L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "mix2.l $dst = $src1, $src2",
	  [(set GR:$dst, (or (and GR:$src1, isMIX2Lable),
	                     (and (srl GR:$src2, (i64 16)), isMIX2Lable)))]>, isI;

def MIX4L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "mix4.l $dst = $src1, $src2",
	  [(set GR:$dst, (or (and GR:$src1, isMIX4Lable),
	                     (and (srl GR:$src2, (i64 32)), isMIX4Lable)))]>, isI;

def MIX1R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "mix1.r $dst = $src1, $src2",
	  [(set GR:$dst, (or (and (shl GR:$src1, (i64 8)), isMIX1Rable),
	                     (and GR:$src2, isMIX1Rable)))]>, isI;

def MIX2R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "mix2.r $dst = $src1, $src2",
	  [(set GR:$dst, (or (and (shl GR:$src1, (i64 16)), isMIX2Rable),
	                     (and GR:$src2, isMIX2Rable)))]>, isI;

def MIX4R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "mix4.r $dst = $src1, $src2",
	  [(set GR:$dst, (or (and (shl GR:$src1, (i64 32)), isMIX4Rable),
	                     (and GR:$src2, isMIX4Rable)))]>, isI;

def GETFSIGD : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins FP:$src),
  "getf.sig $dst = $src",
  []>, isM;

def SETFSIGD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins GR:$src),
  "setf.sig $dst = $src",
  []>, isM;

def XMALD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
  "xma.l $dst = $src1, $src2, $src3",
  []>, isF;
def XMAHD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
  "xma.h $dst = $src1, $src2, $src3",
  []>, isF;
def XMAHUD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
  "xma.hu $dst = $src1, $src2, $src3",
  []>, isF;

// pseudocode for integer multiplication 
def : Pat<(mul GR:$src1, GR:$src2),
           (GETFSIGD (XMALD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>;
def : Pat<(mulhs GR:$src1, GR:$src2),
           (GETFSIGD (XMAHD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>;
def : Pat<(mulhu GR:$src1, GR:$src2),
           (GETFSIGD (XMAHUD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>;

// TODO: addp4 (addp4 dst = src, r0 is a 32-bit add)
// has imm form, too

// def ADDS : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm),
//   "adds $dst = $imm, $src1">;

def AND   : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "and $dst = $src1, $src2",
	  [(set GR:$dst, (and GR:$src1, GR:$src2))]>, isA;
def ANDCM : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "andcm $dst = $src1, $src2",
	  [(set GR:$dst, (and GR:$src1, (not GR:$src2)))]>, isA;
// TODO: and/andcm/or/xor/add/sub/shift immediate forms
def OR    : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "or $dst = $src1, $src2",
	  [(set GR:$dst, (or GR:$src1, GR:$src2))]>, isA;

def pOR   : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2, PR:$qp),
          "($qp) or $dst = $src1, $src2">, isA;

// the following are all a bit unfortunate: we throw away the complement
// of the compare!
def CMPEQ : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.eq $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (seteq GR:$src1, GR:$src2))]>, isA;
def CMPGT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.gt $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setgt GR:$src1, GR:$src2))]>, isA;
def CMPGE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.ge $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setge GR:$src1, GR:$src2))]>, isA;
def CMPLT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.lt $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setlt GR:$src1, GR:$src2))]>, isA;
def CMPLE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.le $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setle GR:$src1, GR:$src2))]>, isA;
def CMPNE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.ne $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setne GR:$src1, GR:$src2))]>, isA;
def CMPLTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.ltu $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setult GR:$src1, GR:$src2))]>, isA;
def CMPGTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.gtu $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setugt GR:$src1, GR:$src2))]>, isA;
def CMPLEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.leu $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setule GR:$src1, GR:$src2))]>, isA;
def CMPGEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
          "cmp.geu $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setuge GR:$src1, GR:$src2))]>, isA;

// and we do the whole thing again for FP compares!
def FCMPEQ : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.eq $dst, p0 = $src1, $src2",
          [(set PR:$dst, (seteq FP:$src1, FP:$src2))]>, isF;
def FCMPGT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.gt $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setgt FP:$src1, FP:$src2))]>, isF;
def FCMPGE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.ge $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setge FP:$src1, FP:$src2))]>, isF;
def FCMPLT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.lt $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setlt FP:$src1, FP:$src2))]>, isF;
def FCMPLE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.le $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setle FP:$src1, FP:$src2))]>, isF;
def FCMPNE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.neq $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setne FP:$src1, FP:$src2))]>, isF;
def FCMPLTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.lt $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setult FP:$src1, FP:$src2))]>, isF;
def FCMPGTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.gt $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setugt FP:$src1, FP:$src2))]>, isF;
def FCMPLEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.le $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setule FP:$src1, FP:$src2))]>, isF;
def FCMPGEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
          "fcmp.ge $dst, p0 = $src1, $src2",
	  [(set PR:$dst, (setuge FP:$src1, FP:$src2))]>, isF;

def PCMPEQUNCR0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$qp),
    "($qp) cmp.eq.unc $dst, p0 = r0, r0">, isA;

def : Pat<(trunc GR:$src),  // truncate i64 to i1
          (CMPNE GR:$src, r0)>; // $src!=0? If so, PR:$dst=true
	  
let isTwoAddress=1 in {
  def TPCMPEQR0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$bogus, PR:$qp),
    "($qp) cmp.eq $dst, p0 = r0, r0">, isA;
  def TPCMPNER0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$bogus, PR:$qp),
    "($qp) cmp.ne $dst, p0 = r0, r0">, isA;
}

/* our pseudocode for OR on predicates is:
pC = pA OR pB
-------------
(pA) cmp.eq.unc pC,p0 = r0,r0  // pC = pA
 ;;
(pB) cmp.eq pC,p0 = r0,r0 // if (pB) pC = 1 */

def bOR   : Pat<(or PR:$src1, PR:$src2),
          (TPCMPEQR0R0 (PCMPEQUNCR0R0 PR:$src1), PR:$src2)>;

/* our pseudocode for AND on predicates is:
 *
(pA) cmp.eq.unc pC,p0 = r0,r0   // pC = pA
     cmp.eq pTemp,p0 = r0,r0    // pTemp = NOT pB
     ;;
(pB) cmp.ne pTemp,p0 = r0,r0
     ;;
(pTemp)cmp.ne pC,p0 = r0,r0    // if (NOT pB) pC = 0  */

def bAND  : Pat<(and PR:$src1, PR:$src2),
          ( TPCMPNER0R0 (PCMPEQUNCR0R0 PR:$src1),
	    (TPCMPNER0R0 (CMPEQ r0, r0), PR:$src2) )>;

/* one possible routine for XOR on predicates is:

      // Compute px = py ^ pz
        // using sum of products: px = (py & !pz) | (pz & !py)
        // Uses 5 instructions in 3 cycles.
        // cycle 1
(pz)    cmp.eq.unc      px = r0, r0     // px = pz
(py)    cmp.eq.unc      pt = r0, r0     // pt = py
        ;;
        // cycle 2
(pt)    cmp.ne.and      px = r0, r0     // px = px & !pt (px = pz & !pt)
(pz)    cmp.ne.and      pt = r0, r0     // pt = pt & !pz
        ;;
        } { .mmi
        // cycle 3
(pt)    cmp.eq.or       px = r0, r0     // px = px | pt

*** Another, which we use here, requires one scratch GR. it is:

        mov             rt = 0          // initialize rt off critical path
        ;;

        // cycle 1
(pz)    cmp.eq.unc      px = r0, r0     // px = pz
(pz)    mov             rt = 1          // rt = pz
        ;;
        // cycle 2
(py)    cmp.ne          px = 1, rt      // if (py) px = !pz

.. these routines kindly provided by Jim Hull
*/
  
def bXOR  : Pat<(xor PR:$src1, PR:$src2),
          (TPCMPIMM8NE (PCMPEQUNCR0R0 PR:$src2), 1,
	               (TPCADDS (ADDS r0, 0), 1, PR:$src2),
                        PR:$src1)>;

def XOR   : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "xor $dst = $src1, $src2",
	  [(set GR:$dst, (xor GR:$src1, GR:$src2))]>, isA;

def SHLADD: AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1,s64imm:$imm,GR:$src2),
          "shladd $dst = $src1, $imm, $src2",
          [(set GR:$dst, (add GR:$src2, (shl GR:$src1, isSHLADDimm:$imm)))]>, isA;

def SHL   : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "shl $dst = $src1, $src2",
	  [(set GR:$dst, (shl GR:$src1, GR:$src2))]>, isI;

def SHRU  : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "shr.u $dst = $src1, $src2",
	  [(set GR:$dst, (srl GR:$src1, GR:$src2))]>, isI;

def SHRS  : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
          "shr $dst = $src1, $src2",
	  [(set GR:$dst, (sra GR:$src1, GR:$src2))]>, isI;

def MOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "mov $dst = $src">, isA;
def FMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "mov $dst = $src">, isF; // XXX: there _is_ no fmov
def PMOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src, PR:$qp),
  "($qp) mov $dst = $src">, isA;

def SPILL_ALL_PREDICATES_TO_GR : AForm<0x03, 0x0b, (outs GR:$dst), (ins),
  "mov $dst = pr">, isI;
def FILL_ALL_PREDICATES_FROM_GR : AForm<0x03, 0x0b, (outs), (ins GR:$src),
  "mov pr = $src">, isI;

let isTwoAddress = 1 in {
  def CMOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src2, GR:$src, PR:$qp),
    "($qp) mov $dst = $src">, isA;
}

def PFMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src, PR:$qp),
  "($qp) mov $dst = $src">, isF;

let isTwoAddress = 1 in {
  def CFMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src2, FP:$src, PR:$qp),
    "($qp) mov $dst = $src">, isF;
}

def SELECTINT : Pat<(select PR:$which, GR:$src1, GR:$src2),
          (CMOV (MOV GR:$src2), GR:$src1, PR:$which)>; // note order!
def SELECTFP : Pat<(select PR:$which, FP:$src1, FP:$src2),
          (CFMOV (FMOV FP:$src2), FP:$src1, PR:$which)>; // note order!
// TODO: can do this faster, w/o using any integer regs (see pattern isel)
def SELECTBOOL : Pat<(select PR:$which, PR:$src1, PR:$src2), // note order!
          (CMPNE (CMOV
            (MOV (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src2)),
            (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src1), PR:$which), r0)>;

// load constants of various sizes // FIXME: prettyprint -ve constants
def : Pat<(i64 immSExt14:$imm), (ADDS r0, immSExt14:$imm)>;
def : Pat<(i1 -1), (CMPEQ r0, r0)>; // TODO: this should just be a ref to p0
def : Pat<(i1  0), (CMPNE r0, r0)>; // TODO: any instruction actually *using*
                                    //       this predicate should be killed!

// TODO: support postincrement (reg, imm9) loads+stores - this needs more
// tablegen support

def IDEF : PseudoInstIA64<(outs variable_ops), (ins), "// IDEF">;

def IDEF_GR_D : PseudoInstIA64_DAG<(outs GR:$reg), (ins), "// $reg = IDEF",
    [(set GR:$reg, (undef))]>;
def IDEF_FP_D : PseudoInstIA64_DAG<(outs FP:$reg), (ins), "// $reg = IDEF",
    [(set FP:$reg, (undef))]>;
def IDEF_PR_D : PseudoInstIA64_DAG<(outs PR:$reg), (ins), "// $reg = IDEF",
    [(set PR:$reg, (undef))]>;

def IUSE : PseudoInstIA64<(outs), (ins variable_ops), "// IUSE">;
def ADJUSTCALLSTACKUP : PseudoInstIA64<(outs), (ins variable_ops),
                                        "// ADJUSTCALLSTACKUP">;
def ADJUSTCALLSTACKDOWN : PseudoInstIA64<(outs), (ins variable_ops),
                                         "// ADJUSTCALLSTACKDOWN">;
def PSEUDO_ALLOC : PseudoInstIA64<(outs), (ins GR:$foo), "// PSEUDO_ALLOC">;

def ALLOC : AForm<0x03, 0x0b,
  (outs GR:$dst), (ins i8imm:$inputs, i8imm:$locals, i8imm:$outputs, i8imm:$rotating),
    "alloc $dst = ar.pfs,$inputs,$locals,$outputs,$rotating">, isM;

let isTwoAddress = 1 in {
  def TCMPNE : AForm<0x03, 0x0b,
  (outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4),
    "cmp.ne $dst, p0 = $src3, $src4">, isA;
  
  def TPCMPEQOR : AForm<0x03, 0x0b,
  (outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp),
    "($qp) cmp.eq.or $dst, p0 = $src3, $src4">, isA;
  
  def TPCMPNE : AForm<0x03, 0x0b,
  (outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp),
    "($qp) cmp.ne $dst, p0 = $src3, $src4">, isA;
  
  def TPCMPEQ : AForm<0x03, 0x0b,
  (outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp),
    "($qp) cmp.eq $dst, p0 = $src3, $src4">, isA;
}

def MOVSIMM14 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s14imm:$imm),
  "mov $dst = $imm">, isA;
def MOVSIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s22imm:$imm),
  "mov $dst = $imm">, isA;
def MOVLIMM64 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s64imm:$imm),
  "movl $dst = $imm">, isLX;

def SHLI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm), 
  "shl $dst = $src1, $imm">, isI;
def SHRUI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm),
  "shr.u $dst = $src1, $imm">, isI;
def SHRSI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm),
  "shr $dst = $src1, $imm">, isI;

def EXTRU : AForm<0x03, 0x0b,
  (outs GR:$dst), (ins GR:$src1, u6imm:$imm1, u6imm:$imm2),
  "extr.u $dst = $src1, $imm1, $imm2">, isI;

def DEPZ : AForm<0x03, 0x0b,
  (outs GR:$dst), (ins GR:$src1, u6imm:$imm1, u6imm:$imm2),
  "dep.z $dst = $src1, $imm1, $imm2">, isI;

def PCMPEQOR : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp),
  "($qp) cmp.eq.or $dst, p0 = $src1, $src2">, isA;
def PCMPEQUNC : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp),
  "($qp) cmp.eq.unc $dst, p0 = $src1, $src2">, isA;
def PCMPNE : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp),
  "($qp) cmp.ne $dst, p0 = $src1, $src2">, isA;

// two destinations! 
def BCMPEQ : AForm<0x03, 0x0b, (outs PR:$dst1, PR:$dst2), (ins GR:$src1, GR:$src2),
  "cmp.eq $dst1, dst2 = $src1, $src2">, isA;

def ADDIMM14 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm),
  "adds $dst = $imm, $src1">, isA;

def ADDIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s22imm:$imm),
  "add $dst = $imm, $src1">, isA;
def CADDIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s22imm:$imm, PR:$qp),
  "($qp) add $dst = $imm, $src1">, isA;

def SUBIMM8 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s8imm:$imm, GR:$src2),
  "sub $dst = $imm, $src2">, isA;

let isStore = 1 in {
  def ST1 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value),
    "st1 [$dstPtr] = $value">, isM;
  def ST2 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value),
    "st2 [$dstPtr] = $value">, isM;
  def ST4 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value),
    "st4 [$dstPtr] = $value">, isM;
  def ST8 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value),
    "st8 [$dstPtr] = $value">, isM;
  def STF4 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value),
    "stfs [$dstPtr] = $value">, isM;
  def STF8 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value),
    "stfd [$dstPtr] = $value">, isM;
  def STF_SPILL : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value),
    "stf.spill [$dstPtr] = $value">, isM;
}

let isLoad = 1 in {
  def LD1 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr),
    "ld1 $dst = [$srcPtr]">, isM;
  def LD2 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr),
    "ld2 $dst = [$srcPtr]">, isM;
  def LD4 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr),
    "ld4 $dst = [$srcPtr]">, isM;
  def LD8 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr),
    "ld8 $dst = [$srcPtr]">, isM;
  def LDF4 : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr),
    "ldfs $dst = [$srcPtr]">, isM;
  def LDF8 : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr),
    "ldfd $dst = [$srcPtr]">, isM;
  def LDF_FILL : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr),
    "ldf.fill $dst = [$srcPtr]">, isM;
}

def POPCNT : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src),
  "popcnt $dst = $src",
  [(set GR:$dst, (ctpop GR:$src))]>, isI;

// some FP stuff:  // TODO: single-precision stuff?
def FADD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2),
  "fadd $dst = $src1, $src2",
  [(set FP:$dst, (fadd FP:$src1, FP:$src2))]>, isF;
def FADDS: AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2),
  "fadd.s $dst = $src1, $src2">, isF;
def FSUB : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2),
  "fsub $dst = $src1, $src2",
  [(set FP:$dst, (fsub FP:$src1, FP:$src2))]>, isF;
def FMPY : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2),
  "fmpy $dst = $src1, $src2",
  [(set FP:$dst, (fmul FP:$src1, FP:$src2))]>, isF;
def FMA : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
  "fma $dst = $src1, $src2, $src3",
  [(set FP:$dst, (fadd (fmul FP:$src1, FP:$src2), FP:$src3))]>, isF;
def FMS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
  "fms $dst = $src1, $src2, $src3",
  [(set FP:$dst, (fsub (fmul FP:$src1, FP:$src2), FP:$src3))]>, isF;
def FNMA : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
  "fnma $dst = $src1, $src2, $src3",
  [(set FP:$dst, (fneg (fadd (fmul FP:$src1, FP:$src2), FP:$src3)))]>, isF;
def FABS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fabs $dst = $src",
  [(set FP:$dst, (fabs FP:$src))]>, isF;
def FNEG : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fneg $dst = $src",
  [(set FP:$dst, (fneg FP:$src))]>, isF;
def FNEGABS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fnegabs $dst = $src",
  [(set FP:$dst, (fneg (fabs FP:$src)))]>, isF;

let isTwoAddress=1 in {
def TCFMAS1 : AForm<0x03, 0x0b,
  (outs FP:$dst), (ins FP:$bogussrc, FP:$src1, FP:$src2, FP:$src3, PR:$qp),
    "($qp) fma.s1 $dst = $src1, $src2, $src3">, isF;
def TCFMADS0 : AForm<0x03, 0x0b,
  (outs FP:$dst), (ins FP:$bogussrc, FP:$src1, FP:$src2, FP:$src3, PR:$qp),
    "($qp) fma.d.s0 $dst = $src1, $src2, $src3">, isF;
}

def CFMAS1 : AForm<0x03, 0x0b,
  (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
    "($qp) fma.s1 $dst = $src1, $src2, $src3">, isF;
def CFNMAS1 : AForm<0x03, 0x0b,
  (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
    "($qp) fnma.s1 $dst = $src1, $src2, $src3">, isF;

def CFMADS1 : AForm<0x03, 0x0b,
  (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
    "($qp) fma.d.s1 $dst = $src1, $src2, $src3">, isF;
def CFMADS0 : AForm<0x03, 0x0b,
  (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
    "($qp) fma.d.s0 $dst = $src1, $src2, $src3">, isF;
def CFNMADS1 : AForm<0x03, 0x0b,
  (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
    "($qp) fnma.d.s1 $dst = $src1, $src2, $src3">, isF;

def FRCPAS0 : AForm<0x03, 0x0b, (outs FP:$dstFR, PR:$dstPR), (ins FP:$src1, FP:$src2),
  "frcpa.s0 $dstFR, $dstPR = $src1, $src2">, isF;
def FRCPAS1 : AForm<0x03, 0x0b, (outs FP:$dstFR, PR:$dstPR), (ins FP:$src1, FP:$src2),
  "frcpa.s1 $dstFR, $dstPR = $src1, $src2">, isF;

def XMAL : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
  "xma.l $dst = $src1, $src2, $src3">, isF;

def FCVTXF : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.xf $dst = $src">, isF;
def FCVTXUF : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.xuf $dst = $src">, isF;
def FCVTXUFS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.xuf.s1 $dst = $src">, isF;
def FCVTFX : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.fx $dst = $src">, isF;
def FCVTFXU : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.fxu $dst = $src">, isF;

def FCVTFXTRUNC : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.fx.trunc $dst = $src">, isF;
def FCVTFXUTRUNC : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.fxu.trunc $dst = $src">, isF;

def FCVTFXTRUNCS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.fx.trunc.s1 $dst = $src">, isF;
def FCVTFXUTRUNCS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fcvt.fxu.trunc.s1 $dst = $src">, isF;

def FNORMD : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
  "fnorm.d $dst = $src">, isF;

def GETFD : AForm<0x03, 0x0b, (outs GR:$dst), (ins FP:$src),
  "getf.d $dst = $src">, isM;
def SETFD : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$src),
  "setf.d $dst = $src">, isM;

def GETFSIG : AForm<0x03, 0x0b, (outs GR:$dst), (ins FP:$src),
  "getf.sig $dst = $src">, isM;
def SETFSIG : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$src),
  "setf.sig $dst = $src">, isM;

// these four FP<->int conversion patterns need checking/cleaning
def SINT_TO_FP : Pat<(sint_to_fp GR:$src),
  (FNORMD (FCVTXF (SETFSIG GR:$src)))>;
def UINT_TO_FP : Pat<(uint_to_fp GR:$src),
  (FNORMD (FCVTXUF (SETFSIG GR:$src)))>;
def FP_TO_SINT : Pat<(i64 (fp_to_sint FP:$src)),
  (GETFSIG (FCVTFXTRUNC FP:$src))>;
def FP_TO_UINT : Pat<(i64 (fp_to_uint FP:$src)),
  (GETFSIG (FCVTFXUTRUNC FP:$src))>;


let isTerminator = 1, isBranch = 1 in {
  def BRL_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins i64imm:$dst),
    "(p0) brl.cond.sptk $dst">, isB;
  def BRLCOND_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, i64imm:$dst),
    "($qp) brl.cond.sptk $dst">, isB;
  def BRCOND_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, GR:$dst),
    "($qp) br.cond.sptk $dst">, isB;
}

let isCall = 1, /* isTerminator = 1, isBranch = 1, */
  Uses = [out0,out1,out2,out3,out4,out5,out6,out7],
// all calls clobber non-callee-saved registers, and for now, they are these:
  Defs = [r2,r3,r8,r9,r10,r11,r14,r15,r16,r17,r18,r19,r20,r21,r22,r23,r24,
  r25,r26,r27,r28,r29,r30,r31,
  p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,
  F6,F7,F8,F9,F10,F11,F12,F13,F14,F15,
  F32,F33,F34,F35,F36,F37,F38,F39,F40,F41,F42,F43,F44,F45,F46,F47,F48,F49,
  F50,F51,F52,F53,F54,F55,F56,
  F57,F58,F59,F60,F61,F62,F63,F64,F65,F66,F67,F68,F69,F70,F71,F72,F73,F74,
  F75,F76,F77,F78,F79,F80,F81,
  F82,F83,F84,F85,F86,F87,F88,F89,F90,F91,F92,F93,F94,F95,F96,F97,F98,F99,
  F100,F101,F102,F103,F104,F105,
  F106,F107,F108,F109,F110,F111,F112,F113,F114,F115,F116,F117,F118,F119,
  F120,F121,F122,F123,F124,F125,F126,F127,
  out0,out1,out2,out3,out4,out5,out6,out7] in {
// old pattern call
  def BRCALL: RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst),
  "br.call.sptk rp = $dst">, isB;   // FIXME: teach llvm about branch regs?
// new daggy stuff!  

// calls a globaladdress
  def BRCALL_IPREL_GA : RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst),
  "br.call.sptk rp = $dst">, isB;       // FIXME: teach llvm about branch regs?
// calls an externalsymbol
  def BRCALL_IPREL_ES : RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst),
  "br.call.sptk rp = $dst">, isB;       // FIXME: teach llvm about branch regs?
// calls through a function descriptor
  def BRCALL_INDIRECT : RawForm<0x03, 0xb0, (outs), (ins GR:$branchreg),
  "br.call.sptk rp = $branchreg">, isB; // FIXME: teach llvm about branch regs?
  def BRLCOND_CALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, i64imm:$dst),
    "($qp) brl.cond.call.sptk $dst">, isB;
  def BRCOND_CALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, GR:$dst),
    "($qp) br.cond.call.sptk $dst">, isB;
}

// Return branch:
let isTerminator = 1, isReturn = 1 in
  def RET : AForm_DAG<0x03, 0x0b, (outs), (ins),
            "br.ret.sptk.many rp",
            [(retflag)]>, isB; // return
def : Pat<(ret), (RET)>;

// the evil stop bit of despair
def STOP : PseudoInstIA64<(outs), (ins variable_ops), ";;">;