aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/IA64/IA64InstrInfo.td
blob: 13443c3d22f22dd37f44f5e880a2de2336679017 (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
//===- 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"

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<i32> {
  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);
}]>;

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

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

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

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

def ADDL_GA : AForm_DAG<0x03, 0x0b, (ops GR:$dst, GR:$src1, globaladdress:$imm),
           "addl $dst = $imm, $src1;;",
	   []>;
  
def SUB  : AForm_DAG<0x03, 0x0b, (ops GR:$dst, GR:$src1, GR:$src2),
           "sub $dst = $src1, $src2;;",
	   [(set GR:$dst, (sub GR:$src1, GR:$src2))]>;

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

let isTwoAddress = 1 in {
def TPCADDIMM22 : AForm<0x03, 0x0b,
  (ops GR:$dst, GR:$src1, s22imm:$imm, PR:$qp),
    "($qp) add $dst = $imm, $dst;;">;
def TPCMPIMM8NE : AForm<0x03, 0x0b,
  (ops PR:$dst, PR:$src1, s22imm:$imm, GR:$src2, PR:$qp),
    "($qp) cmp.ne $dst , p0 = $imm, $src2;;">;
}

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

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

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

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

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

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

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

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

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

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

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

// 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, (ops GR:$dst, GR:$src1, s14imm:$imm),
//   "adds $dst = $imm, $src1;;">;

// load constants of various sizes // FIXME: prettyprint -ve constants
def : Pat<(i64 immSExt14:$imm), (ADDS r0, immSExt14:$imm)>;
def : Pat<(i64 imm64:$imm), (MOVL imm64:$imm)>;
// TODO: def : Pat<(i1 1), (<stuff>)>;

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

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

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

let isTwoAddress=1 in
def TPCMPEQR0R0 : AForm<0x03, 0x0b, (ops PR:$dst, PR:$bogus, PR:$qp),
  "($qp) cmp.eq $dst, p0 = r0, r0;;">;
  
/* 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)>;

// FIXME: these are bogus
def bXOR  : Pat<(xor PR:$src1, PR:$src2),
          (PCMPEQUNCR0R0 PR:$src1)>;

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

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

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

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

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

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

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

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

def PHI : PseudoInstIA64<(ops variable_ops), "PHI">;
def IDEF : PseudoInstIA64<(ops variable_ops), "// IDEF">;

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

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

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

def MOV : AForm<0x03, 0x0b, (ops GR:$dst, GR:$src), "mov $dst = $src;;">;
def PMOV : AForm<0x03, 0x0b, (ops GR:$dst, GR:$src, PR:$qp),
  "($qp) mov $dst = $src;;">;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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, (ops calltarget:$dst),
  "br.call.sptk rp = $dst;;">;       // FIXME: teach llvm about branch regs?
// new daggy stuff!  
  def BRCALL_IPREL : RawForm<0x03, 0xb0, (ops calltarget:$dst, variable_ops),
  "br.call.sptk rp = $dst;;">;       // FIXME: teach llvm about branch regs?
  def BRCALL_INDIRECT : RawForm<0x03, 0xb0, (ops GR:$branchreg, variable_ops),
  "br.call.sptk rp = $branchreg;;">; // FIXME: teach llvm about branch regs?
  def BRLCOND_CALL : RawForm<0x03, 0xb0, (ops PR:$qp, i64imm:$dst),
    "($qp) brl.cond.call.sptk $dst;;">;
  def BRCOND_CALL : RawForm<0x03, 0xb0, (ops PR:$qp, GR:$dst),
    "($qp) br.cond.call.sptk $dst;;">;
}

let isTerminator = 1, isReturn = 1 in
  def RET : RawForm<0x03, 0xb0, (ops), "br.ret.sptk.many rp;;">; // return