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