2012-12-12 05:25:42 +08:00
|
|
|
//===- R600MCCodeEmitter.cpp - Code Emitter for R600->Cayman GPU families -===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
/// \file
|
|
|
|
///
|
2018-05-01 23:54:18 +08:00
|
|
|
/// The R600 code emitter produces machine code that can be executed
|
2013-05-07 01:50:44 +08:00
|
|
|
/// directly on the GPU device.
|
2012-12-12 05:25:42 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2016-05-14 04:39:26 +08:00
|
|
|
#include "MCTargetDesc/AMDGPUFixupKinds.h"
|
2012-12-12 05:25:42 +08:00
|
|
|
#include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
|
2013-01-02 18:22:59 +08:00
|
|
|
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
|
2017-06-06 19:49:48 +08:00
|
|
|
#include "R600Defines.h"
|
2012-12-12 05:25:42 +08:00
|
|
|
#include "llvm/MC/MCCodeEmitter.h"
|
|
|
|
#include "llvm/MC/MCContext.h"
|
2016-12-13 06:23:53 +08:00
|
|
|
#include "llvm/MC/MCFixup.h"
|
2012-12-12 05:25:42 +08:00
|
|
|
#include "llvm/MC/MCInst.h"
|
2016-12-13 06:23:53 +08:00
|
|
|
#include "llvm/MC/MCInstrDesc.h"
|
2012-12-12 05:25:42 +08:00
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2016-12-13 06:23:53 +08:00
|
|
|
#include "llvm/Support/Endian.h"
|
2015-06-04 23:03:02 +08:00
|
|
|
#include "llvm/Support/EndianStream.h"
|
2012-12-12 05:25:42 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2016-12-13 06:23:53 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
2012-12-12 05:25:42 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class R600MCCodeEmitter : public AMDGPUMCCodeEmitter {
|
|
|
|
const MCRegisterInfo &MRI;
|
|
|
|
|
|
|
|
public:
|
2014-01-29 07:13:25 +08:00
|
|
|
R600MCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri)
|
2016-12-13 06:23:53 +08:00
|
|
|
: AMDGPUMCCodeEmitter(mcii), MRI(mri) {}
|
|
|
|
R600MCCodeEmitter(const R600MCCodeEmitter &) = delete;
|
|
|
|
R600MCCodeEmitter &operator=(const R600MCCodeEmitter &) = delete;
|
2012-12-12 05:25:42 +08:00
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Encode the instruction and write it to the OS.
|
2015-05-16 03:13:16 +08:00
|
|
|
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
|
2014-01-29 07:13:07 +08:00
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
2014-04-29 15:57:24 +08:00
|
|
|
const MCSubtargetInfo &STI) const override;
|
2012-12-12 05:25:42 +08:00
|
|
|
|
|
|
|
/// \returns the encoding for an MCOperand.
|
2014-04-29 15:57:24 +08:00
|
|
|
uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const override;
|
2012-12-12 05:25:42 +08:00
|
|
|
|
2015-09-22 19:14:39 +08:00
|
|
|
private:
|
2012-12-12 05:25:42 +08:00
|
|
|
void Emit(uint32_t value, raw_ostream &OS) const;
|
|
|
|
void Emit(uint64_t value, raw_ostream &OS) const;
|
|
|
|
|
|
|
|
unsigned getHWReg(unsigned regNo) const;
|
|
|
|
};
|
|
|
|
|
2016-12-13 06:23:53 +08:00
|
|
|
} // end anonymous namespace
|
2012-12-12 05:25:42 +08:00
|
|
|
|
|
|
|
enum RegElement {
|
|
|
|
ELEMENT_X = 0,
|
|
|
|
ELEMENT_Y,
|
|
|
|
ELEMENT_Z,
|
|
|
|
ELEMENT_W
|
|
|
|
};
|
|
|
|
|
|
|
|
enum FCInstr {
|
|
|
|
FC_IF_PREDICATE = 0,
|
|
|
|
FC_ELSE,
|
|
|
|
FC_ENDIF,
|
|
|
|
FC_BGNLOOP,
|
|
|
|
FC_ENDLOOP,
|
|
|
|
FC_BREAK_PREDICATE,
|
|
|
|
FC_CONTINUE
|
|
|
|
};
|
|
|
|
|
|
|
|
MCCodeEmitter *llvm::createR600MCCodeEmitter(const MCInstrInfo &MCII,
|
2015-03-11 05:57:34 +08:00
|
|
|
const MCRegisterInfo &MRI,
|
2015-09-22 19:15:07 +08:00
|
|
|
MCContext &Ctx) {
|
2014-01-29 07:13:25 +08:00
|
|
|
return new R600MCCodeEmitter(MCII, MRI);
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
|
|
|
|
2015-05-16 03:13:16 +08:00
|
|
|
void R600MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
|
2014-01-29 07:13:07 +08:00
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const {
|
Check that emitted instructions meet their predicates on all targets except ARM, Mips, and X86.
Summary:
* ARM is omitted from this patch because this check appears to expose bugs in this target.
* Mips is omitted from this patch because this check either detects bugs or deliberate
emission of instructions that don't satisfy their predicates. One deliberate
use is the SYNC instruction where the version with an operand is correctly
defined as requiring MIPS32 while the version without an operand is defined
as an alias of 'SYNC 0' and requires MIPS2.
* X86 is omitted from this patch because it doesn't use the tablegen-erated
MCCodeEmitter infrastructure.
Patches for ARM and Mips will follow.
Depends on D25617
Reviewers: tstellarAMD, jmolloy
Subscribers: wdng, jmolloy, aemerson, rengolin, arsenm, jyknight, nemanjai, nhaehnle, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D25618
llvm-svn: 287439
2016-11-19 21:05:44 +08:00
|
|
|
verifyInstructionPredicates(MI,
|
|
|
|
computeAvailableFeatures(STI.getFeatureBits()));
|
|
|
|
|
2013-05-07 01:50:57 +08:00
|
|
|
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
|
|
|
|
if (MI.getOpcode() == AMDGPU::RETURN ||
|
2013-04-30 08:13:53 +08:00
|
|
|
MI.getOpcode() == AMDGPU::FETCH_CLAUSE ||
|
2013-04-30 08:14:38 +08:00
|
|
|
MI.getOpcode() == AMDGPU::ALU_CLAUSE ||
|
2012-12-12 05:25:42 +08:00
|
|
|
MI.getOpcode() == AMDGPU::BUNDLE ||
|
|
|
|
MI.getOpcode() == AMDGPU::KILL) {
|
|
|
|
return;
|
2013-05-07 01:50:57 +08:00
|
|
|
} else if (IS_VTX(Desc)) {
|
2014-01-29 07:13:18 +08:00
|
|
|
uint64_t InstWord01 = getBinaryCodeForInstr(MI, Fixups, STI);
|
2013-05-07 01:50:57 +08:00
|
|
|
uint32_t InstWord2 = MI.getOperand(2).getImm(); // Offset
|
2015-05-26 18:47:10 +08:00
|
|
|
if (!(STI.getFeatureBits()[AMDGPU::FeatureCaymanISA])) {
|
2013-06-15 06:12:30 +08:00
|
|
|
InstWord2 |= 1 << 19; // Mega-Fetch bit
|
|
|
|
}
|
2013-05-07 01:50:57 +08:00
|
|
|
|
|
|
|
Emit(InstWord01, OS);
|
|
|
|
Emit(InstWord2, OS);
|
2013-05-22 09:36:19 +08:00
|
|
|
Emit((uint32_t) 0, OS);
|
2013-05-07 01:50:57 +08:00
|
|
|
} else if (IS_TEX(Desc)) {
|
2013-05-18 00:50:20 +08:00
|
|
|
int64_t Sampler = MI.getOperand(14).getImm();
|
|
|
|
|
2013-05-18 06:45:52 +08:00
|
|
|
int64_t SrcSelect[4] = {
|
2013-05-18 00:50:20 +08:00
|
|
|
MI.getOperand(2).getImm(),
|
|
|
|
MI.getOperand(3).getImm(),
|
|
|
|
MI.getOperand(4).getImm(),
|
|
|
|
MI.getOperand(5).getImm()
|
|
|
|
};
|
2013-05-23 21:22:30 +08:00
|
|
|
int64_t Offsets[3] = {
|
2013-05-18 00:50:20 +08:00
|
|
|
MI.getOperand(6).getImm() & 0x1F,
|
|
|
|
MI.getOperand(7).getImm() & 0x1F,
|
|
|
|
MI.getOperand(8).getImm() & 0x1F
|
|
|
|
};
|
|
|
|
|
2014-01-29 07:13:18 +08:00
|
|
|
uint64_t Word01 = getBinaryCodeForInstr(MI, Fixups, STI);
|
2013-05-18 00:50:20 +08:00
|
|
|
uint32_t Word2 = Sampler << 15 | SrcSelect[ELEMENT_X] << 20 |
|
|
|
|
SrcSelect[ELEMENT_Y] << 23 | SrcSelect[ELEMENT_Z] << 26 |
|
|
|
|
SrcSelect[ELEMENT_W] << 29 | Offsets[0] << 0 | Offsets[1] << 5 |
|
|
|
|
Offsets[2] << 10;
|
|
|
|
|
|
|
|
Emit(Word01, OS);
|
|
|
|
Emit(Word2, OS);
|
2013-05-22 09:36:19 +08:00
|
|
|
Emit((uint32_t) 0, OS);
|
2012-12-12 05:25:42 +08:00
|
|
|
} else {
|
2014-01-29 07:13:18 +08:00
|
|
|
uint64_t Inst = getBinaryCodeForInstr(MI, Fixups, STI);
|
2015-05-26 18:47:10 +08:00
|
|
|
if ((STI.getFeatureBits()[AMDGPU::FeatureR600ALUInst]) &&
|
2013-05-17 23:23:21 +08:00
|
|
|
((Desc.TSFlags & R600_InstFlag::OP1) ||
|
|
|
|
Desc.TSFlags & R600_InstFlag::OP2)) {
|
|
|
|
uint64_t ISAOpCode = Inst & (0x3FFULL << 39);
|
|
|
|
Inst &= ~(0x3FFULL << 39);
|
|
|
|
Inst |= ISAOpCode << 1;
|
|
|
|
}
|
2013-05-07 01:50:57 +08:00
|
|
|
Emit(Inst, OS);
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void R600MCCodeEmitter::Emit(uint32_t Value, raw_ostream &OS) const {
|
2015-06-04 23:03:02 +08:00
|
|
|
support::endian::Writer<support::little>(OS).write(Value);
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void R600MCCodeEmitter::Emit(uint64_t Value, raw_ostream &OS) const {
|
2015-06-04 23:03:02 +08:00
|
|
|
support::endian::Writer<support::little>(OS).write(Value);
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo) const {
|
|
|
|
return MRI.getEncodingValue(RegNo) & HW_REG_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst &MI,
|
|
|
|
const MCOperand &MO,
|
2016-05-14 04:39:26 +08:00
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
2014-01-29 07:13:18 +08:00
|
|
|
const MCSubtargetInfo &STI) const {
|
2012-12-12 05:25:42 +08:00
|
|
|
if (MO.isReg()) {
|
2014-06-19 14:10:58 +08:00
|
|
|
if (HAS_NATIVE_OPERANDS(MCII.get(MI.getOpcode()).TSFlags))
|
2012-12-12 05:25:42 +08:00
|
|
|
return MRI.getEncodingValue(MO.getReg());
|
2014-06-19 14:10:58 +08:00
|
|
|
return getHWReg(MO.getReg());
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
2014-06-19 14:10:58 +08:00
|
|
|
|
2016-05-14 04:39:26 +08:00
|
|
|
if (MO.isExpr()) {
|
|
|
|
// We put rodata at the end of code section, then map the entire
|
|
|
|
// code secetion as vtx buf. Thus the section relative address is the
|
|
|
|
// correct one.
|
|
|
|
// Each R600 literal instruction has two operands
|
|
|
|
// We can't easily get the order of the current one, so compare against
|
|
|
|
// the first one and adjust offset.
|
|
|
|
const unsigned offset = (&MO == &MI.getOperand(0)) ? 0 : 4;
|
2016-06-26 02:24:16 +08:00
|
|
|
Fixups.push_back(MCFixup::create(offset, MO.getExpr(), FK_SecRel_4, MI.getLoc()));
|
2016-05-14 04:39:26 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-19 14:10:58 +08:00
|
|
|
assert(MO.isImm());
|
|
|
|
return MO.getImm();
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
|
|
|
|
Check that emitted instructions meet their predicates on all targets except ARM, Mips, and X86.
Summary:
* ARM is omitted from this patch because this check appears to expose bugs in this target.
* Mips is omitted from this patch because this check either detects bugs or deliberate
emission of instructions that don't satisfy their predicates. One deliberate
use is the SYNC instruction where the version with an operand is correctly
defined as requiring MIPS32 while the version without an operand is defined
as an alias of 'SYNC 0' and requires MIPS2.
* X86 is omitted from this patch because it doesn't use the tablegen-erated
MCCodeEmitter infrastructure.
Patches for ARM and Mips will follow.
Depends on D25617
Reviewers: tstellarAMD, jmolloy
Subscribers: wdng, jmolloy, aemerson, rengolin, arsenm, jyknight, nemanjai, nhaehnle, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D25618
llvm-svn: 287439
2016-11-19 21:05:44 +08:00
|
|
|
#define ENABLE_INSTR_PREDICATE_VERIFIER
|
2012-12-12 05:25:42 +08:00
|
|
|
#include "AMDGPUGenMCCodeEmitter.inc"
|