blob: be3318a0b4c818c6f06a78aae0f6969c38617125 [file] [log] [blame]
Tom Stellardf98f2ce2012-12-11 21:25:42 +00001//===-- R600InstrInfo.cpp - R600 Instruction Information ------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10/// \file
11/// \brief R600 Implementation of TargetInstrInfo.
12//
13//===----------------------------------------------------------------------===//
14
15#include "R600InstrInfo.h"
Tom Stellardf98f2ce2012-12-11 21:25:42 +000016#include "AMDGPUSubtarget.h"
Chandler Carruth58a2cbe2013-01-02 10:22:59 +000017#include "AMDGPUTargetMachine.h"
Tom Stellardf98f2ce2012-12-11 21:25:42 +000018#include "R600Defines.h"
Tom Stellardc0b0c672013-02-06 17:32:29 +000019#include "R600MachineFunctionInfo.h"
Tom Stellardf98f2ce2012-12-11 21:25:42 +000020#include "R600RegisterInfo.h"
21#include "llvm/CodeGen/MachineInstrBuilder.h"
Tom Stellardc0b0c672013-02-06 17:32:29 +000022#include "llvm/CodeGen/MachineFrameInfo.h"
23#include "llvm/CodeGen/MachineRegisterInfo.h"
Tom Stellardf98f2ce2012-12-11 21:25:42 +000024
25#define GET_INSTRINFO_CTOR
26#include "AMDGPUGenDFAPacketizer.inc"
27
28using namespace llvm;
29
30R600InstrInfo::R600InstrInfo(AMDGPUTargetMachine &tm)
31 : AMDGPUInstrInfo(tm),
32 RI(tm, *this)
33 { }
34
35const R600RegisterInfo &R600InstrInfo::getRegisterInfo() const {
36 return RI;
37}
38
39bool R600InstrInfo::isTrig(const MachineInstr &MI) const {
40 return get(MI.getOpcode()).TSFlags & R600_InstFlag::TRIG;
41}
42
43bool R600InstrInfo::isVector(const MachineInstr &MI) const {
44 return get(MI.getOpcode()).TSFlags & R600_InstFlag::VECTOR;
45}
46
47void
48R600InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
49 MachineBasicBlock::iterator MI, DebugLoc DL,
50 unsigned DestReg, unsigned SrcReg,
51 bool KillSrc) const {
52 if (AMDGPU::R600_Reg128RegClass.contains(DestReg)
53 && AMDGPU::R600_Reg128RegClass.contains(SrcReg)) {
54 for (unsigned I = 0; I < 4; I++) {
55 unsigned SubRegIndex = RI.getSubRegFromChannel(I);
56 buildDefaultInstruction(MBB, MI, AMDGPU::MOV,
57 RI.getSubReg(DestReg, SubRegIndex),
58 RI.getSubReg(SrcReg, SubRegIndex))
59 .addReg(DestReg,
60 RegState::Define | RegState::Implicit);
61 }
62 } else {
63
64 // We can't copy vec4 registers
65 assert(!AMDGPU::R600_Reg128RegClass.contains(DestReg)
66 && !AMDGPU::R600_Reg128RegClass.contains(SrcReg));
67
68 MachineInstr *NewMI = buildDefaultInstruction(MBB, MI, AMDGPU::MOV,
69 DestReg, SrcReg);
70 NewMI->getOperand(getOperandIdx(*NewMI, R600Operands::SRC0))
71 .setIsKill(KillSrc);
72 }
73}
74
75MachineInstr * R600InstrInfo::getMovImmInstr(MachineFunction *MF,
76 unsigned DstReg, int64_t Imm) const {
77 MachineInstr * MI = MF->CreateMachineInstr(get(AMDGPU::MOV), DebugLoc());
NAKAMURA Takumi6b207d32012-12-20 00:22:11 +000078 MachineInstrBuilder MIB(*MF, MI);
79 MIB.addReg(DstReg, RegState::Define);
80 MIB.addReg(AMDGPU::ALU_LITERAL_X);
81 MIB.addImm(Imm);
82 MIB.addReg(0); // PREDICATE_BIT
Tom Stellardf98f2ce2012-12-11 21:25:42 +000083
84 return MI;
85}
86
87unsigned R600InstrInfo::getIEQOpcode() const {
88 return AMDGPU::SETE_INT;
89}
90
91bool R600InstrInfo::isMov(unsigned Opcode) const {
92
93
94 switch(Opcode) {
95 default: return false;
96 case AMDGPU::MOV:
97 case AMDGPU::MOV_IMM_F32:
98 case AMDGPU::MOV_IMM_I32:
99 return true;
100 }
101}
102
103// Some instructions act as place holders to emulate operations that the GPU
104// hardware does automatically. This function can be used to check if
105// an opcode falls into this category.
106bool R600InstrInfo::isPlaceHolderOpcode(unsigned Opcode) const {
107 switch (Opcode) {
108 default: return false;
109 case AMDGPU::RETURN:
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000110 return true;
111 }
112}
113
114bool R600InstrInfo::isReductionOp(unsigned Opcode) const {
115 switch(Opcode) {
116 default: return false;
117 case AMDGPU::DOT4_r600_pseudo:
118 case AMDGPU::DOT4_eg_pseudo:
119 return true;
120 }
121}
122
123bool R600InstrInfo::isCubeOp(unsigned Opcode) const {
124 switch(Opcode) {
125 default: return false;
126 case AMDGPU::CUBE_r600_pseudo:
127 case AMDGPU::CUBE_r600_real:
128 case AMDGPU::CUBE_eg_pseudo:
129 case AMDGPU::CUBE_eg_real:
130 return true;
131 }
132}
133
134bool R600InstrInfo::isALUInstr(unsigned Opcode) const {
135 unsigned TargetFlags = get(Opcode).TSFlags;
136
137 return ((TargetFlags & R600_InstFlag::OP1) |
138 (TargetFlags & R600_InstFlag::OP2) |
139 (TargetFlags & R600_InstFlag::OP3));
140}
141
142DFAPacketizer *R600InstrInfo::CreateTargetScheduleState(const TargetMachine *TM,
143 const ScheduleDAG *DAG) const {
144 const InstrItineraryData *II = TM->getInstrItineraryData();
145 return TM->getSubtarget<AMDGPUSubtarget>().createDFAPacketizer(II);
146}
147
148static bool
149isPredicateSetter(unsigned Opcode) {
150 switch (Opcode) {
151 case AMDGPU::PRED_X:
152 return true;
153 default:
154 return false;
155 }
156}
157
158static MachineInstr *
159findFirstPredicateSetterFrom(MachineBasicBlock &MBB,
160 MachineBasicBlock::iterator I) {
161 while (I != MBB.begin()) {
162 --I;
163 MachineInstr *MI = I;
164 if (isPredicateSetter(MI->getOpcode()))
165 return MI;
166 }
167
168 return NULL;
169}
170
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000171static
172bool isJump(unsigned Opcode) {
173 return Opcode == AMDGPU::JUMP || Opcode == AMDGPU::JUMP_COND;
174}
175
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000176bool
177R600InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
178 MachineBasicBlock *&TBB,
179 MachineBasicBlock *&FBB,
180 SmallVectorImpl<MachineOperand> &Cond,
181 bool AllowModify) const {
182 // Most of the following comes from the ARM implementation of AnalyzeBranch
183
184 // If the block has no terminators, it just falls into the block after it.
185 MachineBasicBlock::iterator I = MBB.end();
186 if (I == MBB.begin())
187 return false;
188 --I;
189 while (I->isDebugValue()) {
190 if (I == MBB.begin())
191 return false;
192 --I;
193 }
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000194 if (!isJump(static_cast<MachineInstr *>(I)->getOpcode())) {
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000195 return false;
196 }
197
198 // Get the last instruction in the block.
199 MachineInstr *LastInst = I;
200
201 // If there is only one terminator instruction, process it.
202 unsigned LastOpc = LastInst->getOpcode();
203 if (I == MBB.begin() ||
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000204 !isJump(static_cast<MachineInstr *>(--I)->getOpcode())) {
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000205 if (LastOpc == AMDGPU::JUMP) {
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000206 TBB = LastInst->getOperand(0).getMBB();
207 return false;
208 } else if (LastOpc == AMDGPU::JUMP_COND) {
209 MachineInstr *predSet = I;
210 while (!isPredicateSetter(predSet->getOpcode())) {
211 predSet = --I;
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000212 }
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000213 TBB = LastInst->getOperand(0).getMBB();
214 Cond.push_back(predSet->getOperand(1));
215 Cond.push_back(predSet->getOperand(2));
216 Cond.push_back(MachineOperand::CreateReg(AMDGPU::PRED_SEL_ONE, false));
217 return false;
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000218 }
219 return true; // Can't handle indirect branch.
220 }
221
222 // Get the instruction before it if it is a terminator.
223 MachineInstr *SecondLastInst = I;
224 unsigned SecondLastOpc = SecondLastInst->getOpcode();
225
226 // If the block ends with a B and a Bcc, handle it.
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000227 if (SecondLastOpc == AMDGPU::JUMP_COND && LastOpc == AMDGPU::JUMP) {
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000228 MachineInstr *predSet = --I;
229 while (!isPredicateSetter(predSet->getOpcode())) {
230 predSet = --I;
231 }
232 TBB = SecondLastInst->getOperand(0).getMBB();
233 FBB = LastInst->getOperand(0).getMBB();
234 Cond.push_back(predSet->getOperand(1));
235 Cond.push_back(predSet->getOperand(2));
236 Cond.push_back(MachineOperand::CreateReg(AMDGPU::PRED_SEL_ONE, false));
237 return false;
238 }
239
240 // Otherwise, can't handle this.
241 return true;
242}
243
244int R600InstrInfo::getBranchInstr(const MachineOperand &op) const {
245 const MachineInstr *MI = op.getParent();
246
247 switch (MI->getDesc().OpInfo->RegClass) {
248 default: // FIXME: fallthrough??
249 case AMDGPU::GPRI32RegClassID: return AMDGPU::BRANCH_COND_i32;
250 case AMDGPU::GPRF32RegClassID: return AMDGPU::BRANCH_COND_f32;
251 };
252}
253
254unsigned
255R600InstrInfo::InsertBranch(MachineBasicBlock &MBB,
256 MachineBasicBlock *TBB,
257 MachineBasicBlock *FBB,
258 const SmallVectorImpl<MachineOperand> &Cond,
259 DebugLoc DL) const {
260 assert(TBB && "InsertBranch must not be told to insert a fallthrough");
261
262 if (FBB == 0) {
263 if (Cond.empty()) {
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000264 BuildMI(&MBB, DL, get(AMDGPU::JUMP)).addMBB(TBB);
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000265 return 1;
266 } else {
267 MachineInstr *PredSet = findFirstPredicateSetterFrom(MBB, MBB.end());
268 assert(PredSet && "No previous predicate !");
269 addFlag(PredSet, 0, MO_FLAG_PUSH);
270 PredSet->getOperand(2).setImm(Cond[1].getImm());
271
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000272 BuildMI(&MBB, DL, get(AMDGPU::JUMP_COND))
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000273 .addMBB(TBB)
274 .addReg(AMDGPU::PREDICATE_BIT, RegState::Kill);
275 return 1;
276 }
277 } else {
278 MachineInstr *PredSet = findFirstPredicateSetterFrom(MBB, MBB.end());
279 assert(PredSet && "No previous predicate !");
280 addFlag(PredSet, 0, MO_FLAG_PUSH);
281 PredSet->getOperand(2).setImm(Cond[1].getImm());
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000282 BuildMI(&MBB, DL, get(AMDGPU::JUMP_COND))
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000283 .addMBB(TBB)
284 .addReg(AMDGPU::PREDICATE_BIT, RegState::Kill);
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000285 BuildMI(&MBB, DL, get(AMDGPU::JUMP)).addMBB(FBB);
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000286 return 2;
287 }
288}
289
290unsigned
291R600InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
292
293 // Note : we leave PRED* instructions there.
294 // They may be needed when predicating instructions.
295
296 MachineBasicBlock::iterator I = MBB.end();
297
298 if (I == MBB.begin()) {
299 return 0;
300 }
301 --I;
302 switch (I->getOpcode()) {
303 default:
304 return 0;
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000305 case AMDGPU::JUMP_COND: {
306 MachineInstr *predSet = findFirstPredicateSetterFrom(MBB, I);
307 clearFlag(predSet, 0, MO_FLAG_PUSH);
308 I->eraseFromParent();
309 break;
310 }
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000311 case AMDGPU::JUMP:
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000312 I->eraseFromParent();
313 break;
314 }
315 I = MBB.end();
316
317 if (I == MBB.begin()) {
318 return 1;
319 }
320 --I;
321 switch (I->getOpcode()) {
322 // FIXME: only one case??
323 default:
324 return 1;
Vincent Lejeunefd49dac2013-03-11 18:15:06 +0000325 case AMDGPU::JUMP_COND: {
326 MachineInstr *predSet = findFirstPredicateSetterFrom(MBB, I);
327 clearFlag(predSet, 0, MO_FLAG_PUSH);
328 I->eraseFromParent();
329 break;
330 }
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000331 case AMDGPU::JUMP:
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000332 I->eraseFromParent();
333 break;
334 }
335 return 2;
336}
337
338bool
339R600InstrInfo::isPredicated(const MachineInstr *MI) const {
340 int idx = MI->findFirstPredOperandIdx();
341 if (idx < 0)
342 return false;
343
344 unsigned Reg = MI->getOperand(idx).getReg();
345 switch (Reg) {
346 default: return false;
347 case AMDGPU::PRED_SEL_ONE:
348 case AMDGPU::PRED_SEL_ZERO:
349 case AMDGPU::PREDICATE_BIT:
350 return true;
351 }
352}
353
354bool
355R600InstrInfo::isPredicable(MachineInstr *MI) const {
356 // XXX: KILL* instructions can be predicated, but they must be the last
357 // instruction in a clause, so this means any instructions after them cannot
358 // be predicated. Until we have proper support for instruction clauses in the
359 // backend, we will mark KILL* instructions as unpredicable.
360
361 if (MI->getOpcode() == AMDGPU::KILLGT) {
362 return false;
Vincent Lejeune62b0a9b2013-03-05 19:12:06 +0000363 } else if (isVector(*MI)) {
364 return false;
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000365 } else {
366 return AMDGPUInstrInfo::isPredicable(MI);
367 }
368}
369
370
371bool
372R600InstrInfo::isProfitableToIfCvt(MachineBasicBlock &MBB,
373 unsigned NumCyles,
374 unsigned ExtraPredCycles,
375 const BranchProbability &Probability) const{
376 return true;
377}
378
379bool
380R600InstrInfo::isProfitableToIfCvt(MachineBasicBlock &TMBB,
381 unsigned NumTCycles,
382 unsigned ExtraTCycles,
383 MachineBasicBlock &FMBB,
384 unsigned NumFCycles,
385 unsigned ExtraFCycles,
386 const BranchProbability &Probability) const {
387 return true;
388}
389
390bool
391R600InstrInfo::isProfitableToDupForIfCvt(MachineBasicBlock &MBB,
392 unsigned NumCyles,
393 const BranchProbability &Probability)
394 const {
395 return true;
396}
397
398bool
399R600InstrInfo::isProfitableToUnpredicate(MachineBasicBlock &TMBB,
400 MachineBasicBlock &FMBB) const {
401 return false;
402}
403
404
405bool
406R600InstrInfo::ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
407 MachineOperand &MO = Cond[1];
408 switch (MO.getImm()) {
409 case OPCODE_IS_ZERO_INT:
410 MO.setImm(OPCODE_IS_NOT_ZERO_INT);
411 break;
412 case OPCODE_IS_NOT_ZERO_INT:
413 MO.setImm(OPCODE_IS_ZERO_INT);
414 break;
415 case OPCODE_IS_ZERO:
416 MO.setImm(OPCODE_IS_NOT_ZERO);
417 break;
418 case OPCODE_IS_NOT_ZERO:
419 MO.setImm(OPCODE_IS_ZERO);
420 break;
421 default:
422 return true;
423 }
424
425 MachineOperand &MO2 = Cond[2];
426 switch (MO2.getReg()) {
427 case AMDGPU::PRED_SEL_ZERO:
428 MO2.setReg(AMDGPU::PRED_SEL_ONE);
429 break;
430 case AMDGPU::PRED_SEL_ONE:
431 MO2.setReg(AMDGPU::PRED_SEL_ZERO);
432 break;
433 default:
434 return true;
435 }
436 return false;
437}
438
439bool
440R600InstrInfo::DefinesPredicate(MachineInstr *MI,
441 std::vector<MachineOperand> &Pred) const {
442 return isPredicateSetter(MI->getOpcode());
443}
444
445
446bool
447R600InstrInfo::SubsumesPredicate(const SmallVectorImpl<MachineOperand> &Pred1,
448 const SmallVectorImpl<MachineOperand> &Pred2) const {
449 return false;
450}
451
452
453bool
454R600InstrInfo::PredicateInstruction(MachineInstr *MI,
455 const SmallVectorImpl<MachineOperand> &Pred) const {
456 int PIdx = MI->findFirstPredOperandIdx();
457
458 if (PIdx != -1) {
459 MachineOperand &PMO = MI->getOperand(PIdx);
460 PMO.setReg(Pred[2].getReg());
NAKAMURA Takumi6b207d32012-12-20 00:22:11 +0000461 MachineInstrBuilder MIB(*MI->getParent()->getParent(), MI);
462 MIB.addReg(AMDGPU::PREDICATE_BIT, RegState::Implicit);
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000463 return true;
464 }
465
466 return false;
467}
468
469unsigned int R600InstrInfo::getInstrLatency(const InstrItineraryData *ItinData,
470 const MachineInstr *MI,
471 unsigned *PredCost) const {
472 if (PredCost)
473 *PredCost = 2;
474 return 2;
475}
476
Tom Stellardc0b0c672013-02-06 17:32:29 +0000477int R600InstrInfo::getIndirectIndexBegin(const MachineFunction &MF) const {
478 const MachineRegisterInfo &MRI = MF.getRegInfo();
479 const MachineFrameInfo *MFI = MF.getFrameInfo();
480 int Offset = 0;
481
482 if (MFI->getNumObjects() == 0) {
483 return -1;
484 }
485
486 if (MRI.livein_empty()) {
487 return 0;
488 }
489
490 for (MachineRegisterInfo::livein_iterator LI = MRI.livein_begin(),
491 LE = MRI.livein_end();
492 LI != LE; ++LI) {
493 Offset = std::max(Offset,
494 GET_REG_INDEX(RI.getEncodingValue(LI->first)));
495 }
496
497 return Offset + 1;
498}
499
500int R600InstrInfo::getIndirectIndexEnd(const MachineFunction &MF) const {
501 int Offset = 0;
502 const MachineFrameInfo *MFI = MF.getFrameInfo();
503
504 // Variable sized objects are not supported
505 assert(!MFI->hasVarSizedObjects());
506
507 if (MFI->getNumObjects() == 0) {
508 return -1;
509 }
510
511 Offset = TM.getFrameLowering()->getFrameIndexOffset(MF, -1);
512
513 return getIndirectIndexBegin(MF) + Offset;
514}
515
516std::vector<unsigned> R600InstrInfo::getIndirectReservedRegs(
517 const MachineFunction &MF) const {
518 const AMDGPUFrameLowering *TFL =
519 static_cast<const AMDGPUFrameLowering*>(TM.getFrameLowering());
520 std::vector<unsigned> Regs;
521
522 unsigned StackWidth = TFL->getStackWidth(MF);
523 int End = getIndirectIndexEnd(MF);
524
525 if (End == -1) {
526 return Regs;
527 }
528
529 for (int Index = getIndirectIndexBegin(MF); Index <= End; ++Index) {
530 unsigned SuperReg = AMDGPU::R600_Reg128RegClass.getRegister(Index);
531 Regs.push_back(SuperReg);
532 for (unsigned Chan = 0; Chan < StackWidth; ++Chan) {
533 unsigned Reg = AMDGPU::R600_TReg32RegClass.getRegister((4 * Index) + Chan);
534 Regs.push_back(Reg);
535 }
536 }
537 return Regs;
538}
539
540unsigned R600InstrInfo::calculateIndirectAddress(unsigned RegIndex,
541 unsigned Channel) const {
542 // XXX: Remove when we support a stack width > 2
543 assert(Channel == 0);
544 return RegIndex;
545}
546
547const TargetRegisterClass * R600InstrInfo::getIndirectAddrStoreRegClass(
548 unsigned SourceReg) const {
549 return &AMDGPU::R600_TReg32RegClass;
550}
551
552const TargetRegisterClass *R600InstrInfo::getIndirectAddrLoadRegClass() const {
553 return &AMDGPU::TRegMemRegClass;
554}
555
556MachineInstrBuilder R600InstrInfo::buildIndirectWrite(MachineBasicBlock *MBB,
557 MachineBasicBlock::iterator I,
558 unsigned ValueReg, unsigned Address,
559 unsigned OffsetReg) const {
560 unsigned AddrReg = AMDGPU::R600_AddrRegClass.getRegister(Address);
561 MachineInstr *MOVA = buildDefaultInstruction(*MBB, I, AMDGPU::MOVA_INT_eg,
562 AMDGPU::AR_X, OffsetReg);
563 setImmOperand(MOVA, R600Operands::WRITE, 0);
564
565 MachineInstrBuilder Mov = buildDefaultInstruction(*MBB, I, AMDGPU::MOV,
566 AddrReg, ValueReg)
567 .addReg(AMDGPU::AR_X, RegState::Implicit);
568 setImmOperand(Mov, R600Operands::DST_REL, 1);
569 return Mov;
570}
571
572MachineInstrBuilder R600InstrInfo::buildIndirectRead(MachineBasicBlock *MBB,
573 MachineBasicBlock::iterator I,
574 unsigned ValueReg, unsigned Address,
575 unsigned OffsetReg) const {
576 unsigned AddrReg = AMDGPU::R600_AddrRegClass.getRegister(Address);
577 MachineInstr *MOVA = buildDefaultInstruction(*MBB, I, AMDGPU::MOVA_INT_eg,
578 AMDGPU::AR_X,
579 OffsetReg);
580 setImmOperand(MOVA, R600Operands::WRITE, 0);
581 MachineInstrBuilder Mov = buildDefaultInstruction(*MBB, I, AMDGPU::MOV,
582 ValueReg,
583 AddrReg)
584 .addReg(AMDGPU::AR_X, RegState::Implicit);
585 setImmOperand(Mov, R600Operands::SRC0_REL, 1);
586
587 return Mov;
588}
589
590const TargetRegisterClass *R600InstrInfo::getSuperIndirectRegClass() const {
591 return &AMDGPU::IndirectRegRegClass;
592}
593
594
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000595MachineInstrBuilder R600InstrInfo::buildDefaultInstruction(MachineBasicBlock &MBB,
596 MachineBasicBlock::iterator I,
597 unsigned Opcode,
598 unsigned DstReg,
599 unsigned Src0Reg,
600 unsigned Src1Reg) const {
601 MachineInstrBuilder MIB = BuildMI(MBB, I, MBB.findDebugLoc(I), get(Opcode),
602 DstReg); // $dst
603
604 if (Src1Reg) {
605 MIB.addImm(0) // $update_exec_mask
606 .addImm(0); // $update_predicate
607 }
608 MIB.addImm(1) // $write
609 .addImm(0) // $omod
610 .addImm(0) // $dst_rel
611 .addImm(0) // $dst_clamp
612 .addReg(Src0Reg) // $src0
613 .addImm(0) // $src0_neg
614 .addImm(0) // $src0_rel
Tom Stellard9f7818d2013-01-23 02:09:06 +0000615 .addImm(0) // $src0_abs
616 .addImm(-1); // $src0_sel
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000617
618 if (Src1Reg) {
619 MIB.addReg(Src1Reg) // $src1
620 .addImm(0) // $src1_neg
621 .addImm(0) // $src1_rel
Tom Stellard9f7818d2013-01-23 02:09:06 +0000622 .addImm(0) // $src1_abs
623 .addImm(-1); // $src1_sel
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000624 }
625
626 //XXX: The r600g finalizer expects this to be 1, once we've moved the
627 //scheduling to the backend, we can change the default to 0.
628 MIB.addImm(1) // $last
629 .addReg(AMDGPU::PRED_SEL_OFF) // $pred_sel
630 .addImm(0); // $literal
631
632 return MIB;
633}
634
635MachineInstr *R600InstrInfo::buildMovImm(MachineBasicBlock &BB,
636 MachineBasicBlock::iterator I,
637 unsigned DstReg,
638 uint64_t Imm) const {
639 MachineInstr *MovImm = buildDefaultInstruction(BB, I, AMDGPU::MOV, DstReg,
640 AMDGPU::ALU_LITERAL_X);
641 setImmOperand(MovImm, R600Operands::IMM, Imm);
642 return MovImm;
643}
644
645int R600InstrInfo::getOperandIdx(const MachineInstr &MI,
646 R600Operands::Ops Op) const {
647 return getOperandIdx(MI.getOpcode(), Op);
648}
649
650int R600InstrInfo::getOperandIdx(unsigned Opcode,
651 R600Operands::Ops Op) const {
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000652 unsigned TargetFlags = get(Opcode).TSFlags;
653 unsigned OpTableIdx;
654
655 if (!HAS_NATIVE_OPERANDS(TargetFlags)) {
656 switch (Op) {
657 case R600Operands::DST: return 0;
658 case R600Operands::SRC0: return 1;
659 case R600Operands::SRC1: return 2;
660 case R600Operands::SRC2: return 3;
661 default:
662 assert(!"Unknown operand type for instruction");
663 return -1;
664 }
665 }
666
667 if (TargetFlags & R600_InstFlag::OP1) {
668 OpTableIdx = 0;
669 } else if (TargetFlags & R600_InstFlag::OP2) {
670 OpTableIdx = 1;
671 } else {
672 assert((TargetFlags & R600_InstFlag::OP3) && "OP1, OP2, or OP3 not defined "
673 "for this instruction");
674 OpTableIdx = 2;
675 }
676
Tom Stellard9f7818d2013-01-23 02:09:06 +0000677 return R600Operands::ALUOpTable[OpTableIdx][Op];
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000678}
679
680void R600InstrInfo::setImmOperand(MachineInstr *MI, R600Operands::Ops Op,
681 int64_t Imm) const {
682 int Idx = getOperandIdx(*MI, Op);
683 assert(Idx != -1 && "Operand not supported for this instruction.");
684 assert(MI->getOperand(Idx).isImm());
685 MI->getOperand(Idx).setImm(Imm);
686}
687
688//===----------------------------------------------------------------------===//
689// Instruction flag getters/setters
690//===----------------------------------------------------------------------===//
691
692bool R600InstrInfo::hasFlagOperand(const MachineInstr &MI) const {
693 return GET_FLAG_OPERAND_IDX(get(MI.getOpcode()).TSFlags) != 0;
694}
695
696MachineOperand &R600InstrInfo::getFlagOp(MachineInstr *MI, unsigned SrcIdx,
697 unsigned Flag) const {
698 unsigned TargetFlags = get(MI->getOpcode()).TSFlags;
699 int FlagIndex = 0;
700 if (Flag != 0) {
701 // If we pass something other than the default value of Flag to this
702 // function, it means we are want to set a flag on an instruction
703 // that uses native encoding.
704 assert(HAS_NATIVE_OPERANDS(TargetFlags));
705 bool IsOP3 = (TargetFlags & R600_InstFlag::OP3) == R600_InstFlag::OP3;
706 switch (Flag) {
707 case MO_FLAG_CLAMP:
708 FlagIndex = getOperandIdx(*MI, R600Operands::CLAMP);
709 break;
710 case MO_FLAG_MASK:
711 FlagIndex = getOperandIdx(*MI, R600Operands::WRITE);
712 break;
713 case MO_FLAG_NOT_LAST:
714 case MO_FLAG_LAST:
715 FlagIndex = getOperandIdx(*MI, R600Operands::LAST);
716 break;
717 case MO_FLAG_NEG:
718 switch (SrcIdx) {
719 case 0: FlagIndex = getOperandIdx(*MI, R600Operands::SRC0_NEG); break;
720 case 1: FlagIndex = getOperandIdx(*MI, R600Operands::SRC1_NEG); break;
721 case 2: FlagIndex = getOperandIdx(*MI, R600Operands::SRC2_NEG); break;
722 }
723 break;
724
725 case MO_FLAG_ABS:
726 assert(!IsOP3 && "Cannot set absolute value modifier for OP3 "
727 "instructions.");
Tom Stellard08f2d932012-12-13 19:38:52 +0000728 (void)IsOP3;
Tom Stellardf98f2ce2012-12-11 21:25:42 +0000729 switch (SrcIdx) {
730 case 0: FlagIndex = getOperandIdx(*MI, R600Operands::SRC0_ABS); break;
731 case 1: FlagIndex = getOperandIdx(*MI, R600Operands::SRC1_ABS); break;
732 }
733 break;
734
735 default:
736 FlagIndex = -1;
737 break;
738 }
739 assert(FlagIndex != -1 && "Flag not supported for this instruction");
740 } else {
741 FlagIndex = GET_FLAG_OPERAND_IDX(TargetFlags);
742 assert(FlagIndex != 0 &&
743 "Instruction flags not supported for this instruction");
744 }
745
746 MachineOperand &FlagOp = MI->getOperand(FlagIndex);
747 assert(FlagOp.isImm());
748 return FlagOp;
749}
750
751void R600InstrInfo::addFlag(MachineInstr *MI, unsigned Operand,
752 unsigned Flag) const {
753 unsigned TargetFlags = get(MI->getOpcode()).TSFlags;
754 if (Flag == 0) {
755 return;
756 }
757 if (HAS_NATIVE_OPERANDS(TargetFlags)) {
758 MachineOperand &FlagOp = getFlagOp(MI, Operand, Flag);
759 if (Flag == MO_FLAG_NOT_LAST) {
760 clearFlag(MI, Operand, MO_FLAG_LAST);
761 } else if (Flag == MO_FLAG_MASK) {
762 clearFlag(MI, Operand, Flag);
763 } else {
764 FlagOp.setImm(1);
765 }
766 } else {
767 MachineOperand &FlagOp = getFlagOp(MI, Operand);
768 FlagOp.setImm(FlagOp.getImm() | (Flag << (NUM_MO_FLAGS * Operand)));
769 }
770}
771
772void R600InstrInfo::clearFlag(MachineInstr *MI, unsigned Operand,
773 unsigned Flag) const {
774 unsigned TargetFlags = get(MI->getOpcode()).TSFlags;
775 if (HAS_NATIVE_OPERANDS(TargetFlags)) {
776 MachineOperand &FlagOp = getFlagOp(MI, Operand, Flag);
777 FlagOp.setImm(0);
778 } else {
779 MachineOperand &FlagOp = getFlagOp(MI);
780 unsigned InstFlags = FlagOp.getImm();
781 InstFlags &= ~(Flag << (NUM_MO_FLAGS * Operand));
782 FlagOp.setImm(InstFlags);
783 }
784}