1 //===-- SICodeEmitter.cpp - SI Code Emitter -------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // The SI code emitter produces machine code that can be executed directly on
13 //===----------------------------------------------------------------------===//
17 #include "AMDGPUCodeEmitter.h"
18 #include "SIInstrInfo.h"
19 #include "SIMachineFunctionInfo.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/Support/FormattedStream.h"
24 #include "llvm/Target/TargetMachine.h"
29 #define LITERAL_REG 255
30 #define VGPR_BIT(src_idx) (1ULL << (9 * src_idx - 1))
35 class SICodeEmitter
: public MachineFunctionPass
, public AMDGPUCodeEmitter
{
39 formatted_raw_ostream
&_OS
;
40 const TargetMachine
*TM
;
45 unsigned CurrentInstrIndex
;
46 std::map
<int, unsigned> BBIndexes
;
48 void InitProgramInfo(MachineFunction
&MF
);
49 void EmitState(MachineFunction
& MF
);
50 void emitInstr(MachineInstr
&MI
);
52 void outputBytes(uint64_t value
, unsigned bytes
);
53 unsigned GPRAlign(const MachineInstr
&MI
, unsigned OpNo
, unsigned shift
)
57 SICodeEmitter(formatted_raw_ostream
&OS
) : MachineFunctionPass(ID
),
58 _OS(OS
), TM(NULL
), MaxSGPR(0), MaxVGPR(0), CurrentInstrIndex(0) { }
59 const char *getPassName() const { return "SI Code Emitter"; }
60 bool runOnMachineFunction(MachineFunction
&MF
);
62 /// getMachineOpValue - Return the encoding for MO
63 virtual uint64_t getMachineOpValue(const MachineInstr
&MI
,
64 const MachineOperand
&MO
) const;
66 /// GPR4AlignEncode - Encoding for when 4 consectuive registers are used
67 virtual unsigned GPR4AlignEncode(const MachineInstr
&MI
, unsigned OpNo
)
70 /// GPR2AlignEncode - Encoding for when 2 consecutive registers are used
71 virtual unsigned GPR2AlignEncode(const MachineInstr
&MI
, unsigned OpNo
)
73 /// i32LiteralEncode - Encode an i32 literal this is used as an operand
74 /// for an instruction in place of a register.
75 virtual uint64_t i32LiteralEncode(const MachineInstr
&MI
, unsigned OpNo
)
77 /// SMRDmemriEncode - Encoding for SMRD indexed loads
78 virtual uint32_t SMRDmemriEncode(const MachineInstr
&MI
, unsigned OpNo
)
81 /// VOPPostEncode - Post-Encoder method for VOP instructions
82 virtual uint64_t VOPPostEncode(const MachineInstr
&MI
,
83 uint64_t Value
) const;
87 char SICodeEmitter::ID
= 0;
89 FunctionPass
*llvm::createSICodeEmitterPass(formatted_raw_ostream
&OS
) {
90 return new SICodeEmitter(OS
);
93 void SICodeEmitter::EmitState(MachineFunction
& MF
) {
94 SIMachineFunctionInfo
* MFI
= MF
.getInfo
<SIMachineFunctionInfo
>();
95 outputBytes(MaxSGPR
+ 1, 4);
96 outputBytes(MaxVGPR
+ 1, 4);
97 outputBytes(MFI
->spi_ps_input_addr
, 4);
100 void SICodeEmitter::InitProgramInfo(MachineFunction
&MF
) {
101 unsigned InstrIndex
= 0;
102 bool VCCUsed
= false;
103 const SIRegisterInfo
* RI
=
104 static_cast<const SIRegisterInfo
*>(TM
->getRegisterInfo());
106 for (MachineFunction::iterator BB
= MF
.begin(), BB_E
= MF
.end();
108 MachineBasicBlock
&MBB
= *BB
;
109 BBIndexes
[MBB
.getNumber()] = InstrIndex
;
110 InstrIndex
+= MBB
.size();
111 for (MachineBasicBlock::iterator I
= MBB
.begin(), E
= MBB
.end();
113 MachineInstr
&MI
= *I
;
115 unsigned numOperands
= MI
.getNumOperands();
116 for (unsigned op_idx
= 0; op_idx
< numOperands
; op_idx
++) {
117 MachineOperand
& MO
= MI
.getOperand(op_idx
);
127 if (reg
== AMDGPU::VCC
) {
131 if (AMDGPU::SReg_32RegClass
.contains(reg
)) {
134 } else if (AMDGPU::VReg_32RegClass
.contains(reg
)) {
137 } else if (AMDGPU::SReg_64RegClass
.contains(reg
)) {
140 } else if (AMDGPU::VReg_64RegClass
.contains(reg
)) {
143 } else if (AMDGPU::SReg_128RegClass
.contains(reg
)) {
146 } else if (AMDGPU::VReg_128RegClass
.contains(reg
)) {
149 } else if (AMDGPU::SReg_256RegClass
.contains(reg
)) {
153 assert("!Unknown register class");
155 hwReg
= RI
->getHWRegNum(reg
);
156 maxUsed
= hwReg
+ width
- 1;
158 MaxSGPR
= maxUsed
> MaxSGPR
? maxUsed
: MaxSGPR
;
160 MaxVGPR
= maxUsed
> MaxVGPR
? maxUsed
: MaxVGPR
;
170 bool SICodeEmitter::runOnMachineFunction(MachineFunction
&MF
)
172 TM
= &MF
.getTarget();
173 const AMDGPUSubtarget
&STM
= TM
->getSubtarget
<AMDGPUSubtarget
>();
175 if (STM
.dumpCode()) {
183 for (MachineFunction::iterator BB
= MF
.begin(), BB_E
= MF
.end();
185 MachineBasicBlock
&MBB
= *BB
;
186 for (MachineBasicBlock::iterator I
= MBB
.begin(), E
= MBB
.end();
188 MachineInstr
&MI
= *I
;
189 if (MI
.getOpcode() != AMDGPU::KILL
&& MI
.getOpcode() != AMDGPU::RETURN
) {
196 MachineInstr
* End
= BuildMI(MF
, DebugLoc(),
197 TM
->getInstrInfo()->get(AMDGPU::S_ENDPGM
));
202 void SICodeEmitter::emitInstr(MachineInstr
&MI
)
204 const SIInstrInfo
* SII
= static_cast<const SIInstrInfo
*>(TM
->getInstrInfo());
206 uint64_t hwInst
= getBinaryCodeForInstr(MI
);
208 if ((hwInst
& 0xffffffff) == 0xffffffff) {
209 fprintf(stderr
, "Unsupported Instruction: \n");
214 unsigned bytes
= SII
->getEncodingBytes(MI
);
215 outputBytes(hwInst
, bytes
);
218 uint64_t SICodeEmitter::getMachineOpValue(const MachineInstr
&MI
,
219 const MachineOperand
&MO
) const
221 const SIRegisterInfo
* RI
=
222 static_cast<const SIRegisterInfo
*>(TM
->getRegisterInfo());
224 switch(MO
.getType()) {
225 case MachineOperand::MO_Register
:
226 return RI
->getBinaryCode(MO
.getReg());
228 case MachineOperand::MO_Immediate
:
231 case MachineOperand::MO_FPImmediate
:
232 // XXX: Not all instructions can use inline literals
233 // XXX: We should make sure this is a 32-bit constant
236 case MachineOperand::MO_MachineBasicBlock
:
237 return (*BBIndexes
.find(MI
.getParent()->getNumber())).second
-
238 CurrentInstrIndex
- 1;
240 llvm_unreachable("Encoding of this operand type is not supported yet.");
245 unsigned SICodeEmitter::GPRAlign(const MachineInstr
&MI
, unsigned OpNo
,
246 unsigned shift
) const
248 const SIRegisterInfo
* RI
=
249 static_cast<const SIRegisterInfo
*>(TM
->getRegisterInfo());
250 unsigned regCode
= RI
->getHWRegNum(MI
.getOperand(OpNo
).getReg());
251 return regCode
>> shift
;
254 unsigned SICodeEmitter::GPR4AlignEncode(const MachineInstr
&MI
,
257 return GPRAlign(MI
, OpNo
, 2);
260 unsigned SICodeEmitter::GPR2AlignEncode(const MachineInstr
&MI
,
263 return GPRAlign(MI
, OpNo
, 1);
266 uint64_t SICodeEmitter::i32LiteralEncode(const MachineInstr
&MI
,
269 return LITERAL_REG
| (MI
.getOperand(OpNo
).getImm() << 32);
272 #define SMRD_OFFSET_MASK 0xff
273 #define SMRD_IMM_SHIFT 8
274 #define SMRD_SBASE_MASK 0x3f
275 #define SMRD_SBASE_SHIFT 9
276 /// SMRDmemriEncode - This function is responsibe for encoding the offset
277 /// and the base ptr for SMRD instructions it should return a bit string in
280 /// OFFSET = bits{7-0}
282 /// SBASE = bits{14-9}
284 uint32_t SICodeEmitter::SMRDmemriEncode(const MachineInstr
&MI
,
289 const MachineOperand
&OffsetOp
= MI
.getOperand(OpNo
+ 1);
291 //XXX: Use this function for SMRD loads with register offsets
292 assert(OffsetOp
.isImm());
295 (getMachineOpValue(MI
, OffsetOp
) & SMRD_OFFSET_MASK
)
296 | (1 << SMRD_IMM_SHIFT
) //XXX If the Offset is a register we shouldn't set this bit
297 | ((GPR2AlignEncode(MI
, OpNo
) & SMRD_SBASE_MASK
) << SMRD_SBASE_SHIFT
)
303 /// Set the "VGPR" bit for VOP args that can take either a VGPR or a SGPR.
304 /// XXX: It would be nice if we could handle this without a PostEncode function.
305 uint64_t SICodeEmitter::VOPPostEncode(const MachineInstr
&MI
,
306 uint64_t Value
) const
308 const SIInstrInfo
* SII
= static_cast<const SIInstrInfo
*>(TM
->getInstrInfo());
309 unsigned encodingType
= SII
->getEncodingType(MI
);
311 unsigned vgprBitOffset
;
313 if (encodingType
== SIInstrEncodingType::VOP3
) {
321 // Add one to skip over the destination reg operand.
322 for (unsigned opIdx
= 1; opIdx
< numSrcOps
+ 1; opIdx
++) {
323 const MachineOperand
&MO
= MI
.getOperand(opIdx
);
324 switch(MO
.getType()) {
325 case MachineOperand::MO_Register
:
327 unsigned reg
= MI
.getOperand(opIdx
).getReg();
328 if (AMDGPU::VReg_32RegClass
.contains(reg
)
329 || AMDGPU::VReg_64RegClass
.contains(reg
)) {
330 Value
|= (VGPR_BIT(opIdx
)) << vgprBitOffset
;
335 case MachineOperand::MO_FPImmediate
:
336 // XXX: Not all instructions can use inline literals
337 // XXX: We should make sure this is a 32-bit constant
338 Value
|= (MO
.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue() << 32);
349 void SICodeEmitter::outputBytes(uint64_t value
, unsigned bytes
)
351 for (unsigned i
= 0; i
< bytes
; i
++) {
352 _OS
.write((uint8_t) ((value
>> (8 * i
)) & 0xff));