1//===- R600MCCodeEmitter.cpp - Code Emitter for R600->Cayman GPU families -===//
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///
12/// \brief The R600 code emitter produces machine code that can be executed
13/// directly on the GPU device.
14//
15//===----------------------------------------------------------------------===//
16
17#include "R600Defines.h"
18#include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
19#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
20#include "llvm/MC/MCCodeEmitter.h"
21#include "llvm/MC/MCContext.h"
22#include "llvm/MC/MCInst.h"
23#include "llvm/MC/MCInstrInfo.h"
24#include "llvm/MC/MCRegisterInfo.h"
25#include "llvm/MC/MCSubtargetInfo.h"
26#include "llvm/Support/raw_ostream.h"
27
28using namespace llvm;
29
30namespace {
31
32class R600MCCodeEmitter : public AMDGPUMCCodeEmitter {
33  R600MCCodeEmitter(const R600MCCodeEmitter &) = delete;
34  void operator=(const R600MCCodeEmitter &) = delete;
35  const MCInstrInfo &MCII;
36  const MCRegisterInfo &MRI;
37
38public:
39
40  R600MCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri)
41    : MCII(mcii), MRI(mri) { }
42
43  /// \brief Encode the instruction and write it to the OS.
44  void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
45                         SmallVectorImpl<MCFixup> &Fixups,
46                         const MCSubtargetInfo &STI) const override;
47
48  /// \returns the encoding for an MCOperand.
49  uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
50                             SmallVectorImpl<MCFixup> &Fixups,
51                             const MCSubtargetInfo &STI) const override;
52private:
53
54  void EmitByte(unsigned int byte, raw_ostream &OS) const;
55
56  void Emit(uint32_t value, raw_ostream &OS) const;
57  void Emit(uint64_t value, raw_ostream &OS) const;
58
59  unsigned getHWRegChan(unsigned reg) const;
60  unsigned getHWReg(unsigned regNo) const;
61
62};
63
64} // End anonymous namespace
65
66enum RegElement {
67  ELEMENT_X = 0,
68  ELEMENT_Y,
69  ELEMENT_Z,
70  ELEMENT_W
71};
72
73enum FCInstr {
74  FC_IF_PREDICATE = 0,
75  FC_ELSE,
76  FC_ENDIF,
77  FC_BGNLOOP,
78  FC_ENDLOOP,
79  FC_BREAK_PREDICATE,
80  FC_CONTINUE
81};
82
83MCCodeEmitter *llvm::createR600MCCodeEmitter(const MCInstrInfo &MCII,
84                                             const MCRegisterInfo &MRI,
85					     MCContext &Ctx) {
86  return new R600MCCodeEmitter(MCII, MRI);
87}
88
89void R600MCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
90                                       SmallVectorImpl<MCFixup> &Fixups,
91                                       const MCSubtargetInfo &STI) const {
92  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
93  if (MI.getOpcode() == AMDGPU::RETURN ||
94    MI.getOpcode() == AMDGPU::FETCH_CLAUSE ||
95    MI.getOpcode() == AMDGPU::ALU_CLAUSE ||
96    MI.getOpcode() == AMDGPU::BUNDLE ||
97    MI.getOpcode() == AMDGPU::KILL) {
98    return;
99  } else if (IS_VTX(Desc)) {
100    uint64_t InstWord01 = getBinaryCodeForInstr(MI, Fixups, STI);
101    uint32_t InstWord2 = MI.getOperand(2).getImm(); // Offset
102    if (!(STI.getFeatureBits() & AMDGPU::FeatureCaymanISA)) {
103      InstWord2 |= 1 << 19; // Mega-Fetch bit
104    }
105
106    Emit(InstWord01, OS);
107    Emit(InstWord2, OS);
108    Emit((uint32_t) 0, OS);
109  } else if (IS_TEX(Desc)) {
110      int64_t Sampler = MI.getOperand(14).getImm();
111
112      int64_t SrcSelect[4] = {
113        MI.getOperand(2).getImm(),
114        MI.getOperand(3).getImm(),
115        MI.getOperand(4).getImm(),
116        MI.getOperand(5).getImm()
117      };
118      int64_t Offsets[3] = {
119        MI.getOperand(6).getImm() & 0x1F,
120        MI.getOperand(7).getImm() & 0x1F,
121        MI.getOperand(8).getImm() & 0x1F
122      };
123
124      uint64_t Word01 = getBinaryCodeForInstr(MI, Fixups, STI);
125      uint32_t Word2 = Sampler << 15 | SrcSelect[ELEMENT_X] << 20 |
126          SrcSelect[ELEMENT_Y] << 23 | SrcSelect[ELEMENT_Z] << 26 |
127          SrcSelect[ELEMENT_W] << 29 | Offsets[0] << 0 | Offsets[1] << 5 |
128          Offsets[2] << 10;
129
130      Emit(Word01, OS);
131      Emit(Word2, OS);
132      Emit((uint32_t) 0, OS);
133  } else {
134    uint64_t Inst = getBinaryCodeForInstr(MI, Fixups, STI);
135    if ((STI.getFeatureBits() & AMDGPU::FeatureR600ALUInst) &&
136       ((Desc.TSFlags & R600_InstFlag::OP1) ||
137         Desc.TSFlags & R600_InstFlag::OP2)) {
138      uint64_t ISAOpCode = Inst & (0x3FFULL << 39);
139      Inst &= ~(0x3FFULL << 39);
140      Inst |= ISAOpCode << 1;
141    }
142    Emit(Inst, OS);
143  }
144}
145
146void R600MCCodeEmitter::EmitByte(unsigned int Byte, raw_ostream &OS) const {
147  OS.write((uint8_t) Byte & 0xff);
148}
149
150void R600MCCodeEmitter::Emit(uint32_t Value, raw_ostream &OS) const {
151  for (unsigned i = 0; i < 4; i++) {
152    OS.write((uint8_t) ((Value >> (8 * i)) & 0xff));
153  }
154}
155
156void R600MCCodeEmitter::Emit(uint64_t Value, raw_ostream &OS) const {
157  for (unsigned i = 0; i < 8; i++) {
158    EmitByte((Value >> (8 * i)) & 0xff, OS);
159  }
160}
161
162unsigned R600MCCodeEmitter::getHWRegChan(unsigned reg) const {
163  return MRI.getEncodingValue(reg) >> HW_CHAN_SHIFT;
164}
165
166unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo) const {
167  return MRI.getEncodingValue(RegNo) & HW_REG_MASK;
168}
169
170uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst &MI,
171                                              const MCOperand &MO,
172                                        SmallVectorImpl<MCFixup> &Fixup,
173                                        const MCSubtargetInfo &STI) const {
174  if (MO.isReg()) {
175    if (HAS_NATIVE_OPERANDS(MCII.get(MI.getOpcode()).TSFlags))
176      return MRI.getEncodingValue(MO.getReg());
177    return getHWReg(MO.getReg());
178  }
179
180  assert(MO.isImm());
181  return MO.getImm();
182}
183
184#include "AMDGPUGenMCCodeEmitter.inc"
185