2012-12-12 05:25:42 +08:00
|
|
|
//===-- AMDGPUInstPrinter.cpp - AMDGPU MC Inst -> ASM ---------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2012-12-12 05:25:42 +08:00
|
|
|
//
|
|
|
|
// \file
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "AMDGPUInstPrinter.h"
|
2016-10-01 01:01:40 +08:00
|
|
|
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
|
2017-06-06 19:49:48 +08:00
|
|
|
#include "SIDefines.h"
|
2021-02-18 05:37:46 +08:00
|
|
|
#include "SIRegisterInfo.h"
|
2016-05-27 01:00:33 +08:00
|
|
|
#include "Utils/AMDGPUAsmUtils.h"
|
2016-10-01 01:01:40 +08:00
|
|
|
#include "Utils/AMDGPUBaseInfo.h"
|
2013-02-21 23:17:22 +08:00
|
|
|
#include "llvm/MC/MCExpr.h"
|
2013-05-24 01:10:37 +08:00
|
|
|
#include "llvm/MC/MCInst.h"
|
2016-12-13 06:23:53 +08:00
|
|
|
#include "llvm/MC/MCInstrDesc.h"
|
2014-12-18 05:04:08 +08:00
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
2016-10-01 01:01:40 +08:00
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2020-05-24 21:16:03 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2020-12-25 23:52:14 +08:00
|
|
|
#include "llvm/Support/TargetParser.h"
|
2016-04-14 00:18:41 +08:00
|
|
|
|
2012-12-12 05:25:42 +08:00
|
|
|
using namespace llvm;
|
2016-10-01 01:01:40 +08:00
|
|
|
using namespace llvm::AMDGPU;
|
2012-12-12 05:25:42 +08:00
|
|
|
|
2020-05-06 01:25:54 +08:00
|
|
|
static cl::opt<bool> Keep16BitSuffixes(
|
|
|
|
"amdgpu-keep-16-bit-reg-suffixes",
|
|
|
|
cl::desc("Keep .l and .h suffixes in asm for debugging purposes"),
|
|
|
|
cl::init(false),
|
|
|
|
cl::ReallyHidden);
|
|
|
|
|
2019-11-09 04:07:54 +08:00
|
|
|
void AMDGPUInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
|
2020-03-17 05:12:09 +08:00
|
|
|
// FIXME: The current implementation of
|
|
|
|
// AsmParser::parseRegisterOrRegisterNumber in MC implies we either emit this
|
|
|
|
// as an integer or we provide a name which represents a physical register.
|
|
|
|
// For CFI instructions we really want to emit a name for the DWARF register
|
|
|
|
// instead, because there may be multiple DWARF registers corresponding to a
|
|
|
|
// single physical register. One case where this problem manifests is with
|
|
|
|
// wave32/wave64 where using the physical register name is ambiguous: if we
|
|
|
|
// write e.g. `.cfi_undefined v0` we lose information about the wavefront
|
|
|
|
// size which we need to encode the register in the final DWARF. Ideally we
|
|
|
|
// would extend MC to support parsing DWARF register names so we could do
|
|
|
|
// something like `.cfi_undefined dwarf_wave32_v0`. For now we just live with
|
|
|
|
// non-pretty DWARF register names in assembly text.
|
|
|
|
OS << RegNo;
|
2019-11-09 04:07:54 +08:00
|
|
|
}
|
|
|
|
|
2020-01-04 02:55:30 +08:00
|
|
|
void AMDGPUInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
|
|
|
StringRef Annot, const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &OS) {
|
2013-05-03 05:52:30 +08:00
|
|
|
OS.flush();
|
2020-01-04 04:02:46 +08:00
|
|
|
printInstruction(MI, Address, STI, OS);
|
2012-12-12 05:25:42 +08:00
|
|
|
printAnnotation(OS, Annot);
|
|
|
|
}
|
|
|
|
|
2016-03-09 20:29:31 +08:00
|
|
|
void AMDGPUInstPrinter::printU4ImmOperand(const MCInst *MI, unsigned OpNo,
|
2016-10-13 02:00:51 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2016-09-27 22:42:48 +08:00
|
|
|
raw_ostream &O) {
|
2016-03-09 20:29:31 +08:00
|
|
|
O << formatHex(MI->getOperand(OpNo).getImm() & 0xf);
|
|
|
|
}
|
|
|
|
|
2014-04-16 06:32:49 +08:00
|
|
|
void AMDGPUInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
raw_ostream &O) {
|
2014-04-16 06:32:49 +08:00
|
|
|
O << formatHex(MI->getOperand(OpNo).getImm() & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2014-04-16 06:32:49 +08:00
|
|
|
raw_ostream &O) {
|
2016-12-10 08:39:12 +08:00
|
|
|
// It's possible to end up with a 32-bit literal used with a 16-bit operand
|
|
|
|
// with ignored high bits. Print as 32-bit anyway in that case.
|
|
|
|
int64_t Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (isInt<16>(Imm) || isUInt<16>(Imm))
|
|
|
|
O << formatHex(static_cast<uint64_t>(Imm & 0xffff));
|
|
|
|
else
|
|
|
|
printU32ImmOperand(MI, OpNo, STI, O);
|
2014-04-16 06:32:49 +08:00
|
|
|
}
|
|
|
|
|
2016-03-09 20:29:31 +08:00
|
|
|
void AMDGPUInstPrinter::printU4ImmDecOperand(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O) {
|
|
|
|
O << formatDec(MI->getOperand(OpNo).getImm() & 0xf);
|
|
|
|
}
|
|
|
|
|
2014-10-11 06:16:07 +08:00
|
|
|
void AMDGPUInstPrinter::printU8ImmDecOperand(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O) {
|
|
|
|
O << formatDec(MI->getOperand(OpNo).getImm() & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printU16ImmDecOperand(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O) {
|
|
|
|
O << formatDec(MI->getOperand(OpNo).getImm() & 0xffff);
|
|
|
|
}
|
|
|
|
|
2016-09-27 22:42:48 +08:00
|
|
|
void AMDGPUInstPrinter::printU32ImmOperand(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
O << formatHex(MI->getOperand(OpNo).getImm() & 0xffffffff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printNamedBit(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O, StringRef BitName) {
|
2016-02-26 17:51:05 +08:00
|
|
|
if (MI->getOperand(OpNo).getImm()) {
|
2016-07-06 06:06:56 +08:00
|
|
|
O << ' ' << BitName;
|
2016-02-26 17:51:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-05 22:48:12 +08:00
|
|
|
void AMDGPUInstPrinter::printOffen(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "offen");
|
2014-08-05 22:48:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printIdxen(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "idxen");
|
2014-08-05 22:48:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printAddr64(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "addr64");
|
2014-08-05 22:48:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printMBUFOffset(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O) {
|
|
|
|
if (MI->getOperand(OpNo).getImm()) {
|
|
|
|
O << " offset:";
|
2014-12-03 11:12:13 +08:00
|
|
|
printU16ImmDecOperand(MI, OpNo, O);
|
2014-08-05 22:48:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 17:02:30 +08:00
|
|
|
void AMDGPUInstPrinter::printOffset(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2014-10-11 06:16:07 +08:00
|
|
|
uint16_t Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (Imm != 0) {
|
2020-10-28 21:06:44 +08:00
|
|
|
O << " offset:";
|
2014-10-11 06:16:07 +08:00
|
|
|
printU16ImmDecOperand(MI, OpNo, O);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-08 22:27:37 +08:00
|
|
|
void AMDGPUInstPrinter::printFlatOffset(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2017-06-21 03:54:14 +08:00
|
|
|
uint16_t Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (Imm != 0) {
|
2020-10-28 21:06:44 +08:00
|
|
|
O << " offset:";
|
2019-07-08 22:27:37 +08:00
|
|
|
|
|
|
|
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
|
2020-11-03 02:56:12 +08:00
|
|
|
bool IsFlatSeg = !(Desc.TSFlags &
|
2021-04-09 17:20:15 +08:00
|
|
|
(SIInstrFlags::FlatGlobal | SIInstrFlags::FlatScratch));
|
2019-07-08 22:27:37 +08:00
|
|
|
|
|
|
|
if (IsFlatSeg) { // Unsigned offset
|
|
|
|
printU16ImmDecOperand(MI, OpNo, O);
|
|
|
|
} else { // Signed offset
|
2020-11-25 19:51:23 +08:00
|
|
|
if (AMDGPU::isGFX10Plus(STI)) {
|
2019-07-08 22:27:37 +08:00
|
|
|
O << formatDec(SignExtend32<12>(MI->getOperand(OpNo).getImm()));
|
|
|
|
} else {
|
|
|
|
O << formatDec(SignExtend32<13>(MI->getOperand(OpNo).getImm()));
|
|
|
|
}
|
|
|
|
}
|
2017-06-21 03:54:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 17:02:30 +08:00
|
|
|
void AMDGPUInstPrinter::printOffset0(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2015-04-08 09:09:19 +08:00
|
|
|
if (MI->getOperand(OpNo).getImm()) {
|
|
|
|
O << " offset0:";
|
|
|
|
printU8ImmDecOperand(MI, OpNo, O);
|
|
|
|
}
|
2014-10-11 06:16:07 +08:00
|
|
|
}
|
|
|
|
|
2016-04-29 17:02:30 +08:00
|
|
|
void AMDGPUInstPrinter::printOffset1(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2015-04-08 09:09:19 +08:00
|
|
|
if (MI->getOperand(OpNo).getImm()) {
|
|
|
|
O << " offset1:";
|
|
|
|
printU8ImmDecOperand(MI, OpNo, O);
|
|
|
|
}
|
2014-10-11 06:16:07 +08:00
|
|
|
}
|
|
|
|
|
2016-11-01 00:07:39 +08:00
|
|
|
void AMDGPUInstPrinter::printSMRDOffset8(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
printU32ImmOperand(MI, OpNo, STI, O);
|
|
|
|
}
|
|
|
|
|
2020-05-06 19:11:02 +08:00
|
|
|
void AMDGPUInstPrinter::printSMEMOffset(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2016-04-29 17:02:30 +08:00
|
|
|
raw_ostream &O) {
|
2020-05-06 19:11:02 +08:00
|
|
|
O << formatHex(MI->getOperand(OpNo).getImm());
|
2016-04-29 17:02:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printSMRDLiteralOffset(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2016-04-29 17:02:30 +08:00
|
|
|
raw_ostream &O) {
|
2016-09-27 22:42:48 +08:00
|
|
|
printU32ImmOperand(MI, OpNo, STI, O);
|
2016-04-29 17:02:30 +08:00
|
|
|
}
|
|
|
|
|
2015-03-10 02:49:54 +08:00
|
|
|
void AMDGPUInstPrinter::printGDS(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "gds");
|
2015-03-10 02:49:54 +08:00
|
|
|
}
|
|
|
|
|
2021-02-09 08:36:10 +08:00
|
|
|
void AMDGPUInstPrinter::printCPol(const MCInst *MI, unsigned OpNo,
|
2021-02-18 05:37:46 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2021-02-09 08:36:10 +08:00
|
|
|
auto Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (Imm & CPol::GLC)
|
|
|
|
O << " glc";
|
|
|
|
if (Imm & CPol::SLC)
|
|
|
|
O << " slc";
|
|
|
|
if ((Imm & CPol::DLC) && AMDGPU::isGFX10Plus(STI))
|
|
|
|
O << " dlc";
|
|
|
|
if ((Imm & CPol::SCC) && AMDGPU::isGFX90A(STI))
|
|
|
|
O << " scc";
|
|
|
|
if (Imm & ~CPol::ALL)
|
|
|
|
O << " /* unexpected cache policy bit */";
|
2014-08-05 22:48:12 +08:00
|
|
|
}
|
|
|
|
|
[AMDGPU] Extend buffer intrinsics with swizzling
Summary:
Extend cachepolicy operand in the new VMEM buffer intrinsics
to supply information whether the buffer data is swizzled.
Also, propagate this information to MIR.
Intrinsics updated:
int_amdgcn_raw_buffer_load
int_amdgcn_raw_buffer_load_format
int_amdgcn_raw_buffer_store
int_amdgcn_raw_buffer_store_format
int_amdgcn_raw_tbuffer_load
int_amdgcn_raw_tbuffer_store
int_amdgcn_struct_buffer_load
int_amdgcn_struct_buffer_load_format
int_amdgcn_struct_buffer_store
int_amdgcn_struct_buffer_store_format
int_amdgcn_struct_tbuffer_load
int_amdgcn_struct_tbuffer_store
Furthermore, disable merging of VMEM buffer instructions
in SI Load/Store optimizer, if the "swizzled" bit on the instruction
is on.
The default value of the bit is 0, meaning that data in buffer
is linear and buffer instructions can be merged.
There is no difference in the generated code with this commit.
However, in the future it will be expected that front-ends
use buffer intrinsics with correct "swizzled" bit set.
Reviewers: arsenm, nhaehnle, tpr
Reviewed By: nhaehnle
Subscribers: arsenm, kzhuravl, jvesely, wdng, nhaehnle, yaxunl, dstuttard, tpr, t-tye, arphaman, jfb, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68200
llvm-svn: 373491
2019-10-03 01:22:36 +08:00
|
|
|
void AMDGPUInstPrinter::printSWZ(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
|
|
|
}
|
|
|
|
|
2014-08-05 22:48:12 +08:00
|
|
|
void AMDGPUInstPrinter::printTFE(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "tfe");
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printDMask(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
if (MI->getOperand(OpNo).getImm()) {
|
|
|
|
O << " dmask:";
|
2016-09-27 22:42:48 +08:00
|
|
|
printU16ImmOperand(MI, OpNo, STI, O);
|
2016-02-26 17:51:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-02 00:32:58 +08:00
|
|
|
void AMDGPUInstPrinter::printDim(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
|
|
|
unsigned Dim = MI->getOperand(OpNo).getImm();
|
|
|
|
O << " dim:SQ_RSRC_IMG_";
|
|
|
|
|
|
|
|
const AMDGPU::MIMGDimInfo *DimInfo = AMDGPU::getMIMGDimInfoByEncoding(Dim);
|
|
|
|
if (DimInfo)
|
|
|
|
O << DimInfo->AsmSuffix;
|
|
|
|
else
|
|
|
|
O << Dim;
|
|
|
|
}
|
|
|
|
|
2016-02-26 17:51:05 +08:00
|
|
|
void AMDGPUInstPrinter::printUNorm(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "unorm");
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printDA(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "da");
|
|
|
|
}
|
|
|
|
|
2018-08-28 23:07:30 +08:00
|
|
|
void AMDGPUInstPrinter::printR128A16(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2018-08-28 23:07:30 +08:00
|
|
|
if (STI.hasFeature(AMDGPU::FeatureR128A16))
|
|
|
|
printNamedBit(MI, OpNo, O, "a16");
|
|
|
|
else
|
|
|
|
printNamedBit(MI, OpNo, O, "r128");
|
2016-02-26 17:51:05 +08:00
|
|
|
}
|
|
|
|
|
2020-01-29 17:04:36 +08:00
|
|
|
void AMDGPUInstPrinter::printGFX10A16(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
|
|
|
printNamedBit(MI, OpNo, O, "a16");
|
|
|
|
}
|
|
|
|
|
2016-02-26 17:51:05 +08:00
|
|
|
void AMDGPUInstPrinter::printLWE(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2016-02-26 17:51:05 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "lwe");
|
AMDGPU: Turn D16 for MIMG instructions into a regular operand
Summary:
This allows us to reduce the number of different machine instruction
opcodes, which reduces the table sizes and helps flatten the TableGen
multiclass hierarchies.
We can do this because for each hardware MIMG opcode, we have a full set
of IMAGE_xxx_Vn_Vm machine instructions for all required sizes of vdata
and vaddr registers. Instead of having separate D16 machine instructions,
a packed D16 instructions loading e.g. 4 components can simply use the
same V2 opcode variant that non-D16 instructions use.
We still require a TSFlag for D16 buffer instructions, because the
D16-ness of buffer instructions is part of the opcode. Renaming the flag
should help avoid future confusion.
The one non-obvious code change is that for gather4 instructions, the
disassembler can no longer automatically decide whether to use a V2 or
a V4 variant. The existing logic which choose the correct variant for
other MIMG instruction is extended to cover gather4 as well.
As a bonus, some of the assembler error messages are now more helpful
(e.g., complaining about a wrong data size instead of a non-existing
instruction).
While we're at it, delete a whole bunch of dead legacy TableGen code.
Change-Id: I89b02c2841c06f95e662541433e597f5d4553978
Reviewers: arsenm, rampitec, kzhuravl, artem.tamazov, dp, rtaylor
Subscribers: wdng, yaxunl, dstuttard, tpr, t-tye, llvm-commits
Differential Revision: https://reviews.llvm.org/D47434
llvm-svn: 335222
2018-06-21 21:36:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printD16(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
|
|
|
printNamedBit(MI, OpNo, O, "d16");
|
2014-08-05 22:48:12 +08:00
|
|
|
}
|
|
|
|
|
2016-12-06 04:31:49 +08:00
|
|
|
void AMDGPUInstPrinter::printExpCompr(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2020-10-26 22:03:35 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "compr");
|
2016-12-06 04:31:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printExpVM(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2020-10-26 22:03:35 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "vm");
|
2016-12-06 04:31:49 +08:00
|
|
|
}
|
|
|
|
|
[AMDGPU] New tbuffer intrinsics
Summary:
This commit adds new intrinsics
llvm.amdgcn.raw.tbuffer.load
llvm.amdgcn.struct.tbuffer.load
llvm.amdgcn.raw.tbuffer.store
llvm.amdgcn.struct.tbuffer.store
with the following changes from the llvm.amdgcn.tbuffer.* intrinsics:
* there are separate raw and struct versions: raw does not have an index
arg and sets idxen=0 in the instruction, and struct always sets
idxen=1 in the instruction even if the index is 0, to allow for the
fact that gfx9 does bounds checking differently depending on whether
idxen is set;
* there is a combined format arg (dfmt+nfmt)
* there is a combined cachepolicy arg (glc+slc)
* there are now only two offset args: one for the offset that is
included in bounds checking and swizzling, to be split between the
instruction's voffset and immoffset fields, and one for the offset
that is excluded from bounds checking and swizzling, to go into the
instruction's soffset field.
The AMDISD::TBUFFER_* SD nodes always have an index operand, all three
offset operands, combined format operand, combined cachepolicy operand,
and an extra idxen operand.
The tbuffer pseudo- and real instructions now also have a combined
format operand.
The obsolescent llvm.amdgcn.tbuffer.* and llvm.SI.tbuffer.store
intrinsics continue to work.
V2: Separate raw and struct intrinsics.
V3: Moved extract_glc and extract_slc defs to a more sensible place.
V4: Rebased on D49995.
V5: Only two separate offset args instead of three.
V6: Pseudo- and real instructions have joint format operand.
V7: Restored optionality of dfmt and nfmt in assembler.
V8: Addressed minor review comments.
Subscribers: arsenm, kzhuravl, wdng, nhaehnle, yaxunl, dstuttard, t-tye, llvm-commits
Differential Revision: https://reviews.llvm.org/D49026
Change-Id: If22ad77e349fac3a5d2f72dda53c010377d470d4
llvm-svn: 340268
2018-08-21 19:06:05 +08:00
|
|
|
void AMDGPUInstPrinter::printFORMAT(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
[AMDGPU][MC] Added support of SP3 syntax for MTBUF format modifier
Currently supported LLVM MTBUF syntax is shown below. It is not compatible with SP3.
op dst, addr, rsrc, FORMAT, soffset
This change adds support for SP3 syntax:
op dst, addr, rsrc, soffset SP3FORMAT
In addition to being compatible with SP3, this syntax allows using symbolic names for data, numeric and unified formats. Below is a list of added syntax variants.
format:<expression>
format:[<numeric-format-name>,<data-format-name>]
format:[<data-format-name>,<numeric-format-name>]
format:[<data-format-name>]
format:[<numeric-format-name>]
format:[<unified-format-name>]
The last syntax variant is supported for GFX10 only.
See llvm bug 37738
Reviewers: arsenm, rampitec, vpykhtin
Differential Revision: https://reviews.llvm.org/D84026
2020-07-24 21:39:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printSymbolicFormat(const MCInst *MI,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2020-07-16 00:44:07 +08:00
|
|
|
using namespace llvm::AMDGPU::MTBUFFormat;
|
|
|
|
|
[AMDGPU][MC] Added support of SP3 syntax for MTBUF format modifier
Currently supported LLVM MTBUF syntax is shown below. It is not compatible with SP3.
op dst, addr, rsrc, FORMAT, soffset
This change adds support for SP3 syntax:
op dst, addr, rsrc, soffset SP3FORMAT
In addition to being compatible with SP3, this syntax allows using symbolic names for data, numeric and unified formats. Below is a list of added syntax variants.
format:<expression>
format:[<numeric-format-name>,<data-format-name>]
format:[<data-format-name>,<numeric-format-name>]
format:[<data-format-name>]
format:[<numeric-format-name>]
format:[<unified-format-name>]
The last syntax variant is supported for GFX10 only.
See llvm bug 37738
Reviewers: arsenm, rampitec, vpykhtin
Differential Revision: https://reviews.llvm.org/D84026
2020-07-24 21:39:42 +08:00
|
|
|
int OpNo =
|
|
|
|
AMDGPU::getNamedOperandIdx(MI->getOpcode(), AMDGPU::OpName::format);
|
|
|
|
assert(OpNo != -1);
|
|
|
|
|
2020-07-16 00:44:07 +08:00
|
|
|
unsigned Val = MI->getOperand(OpNo).getImm();
|
2020-11-25 19:51:23 +08:00
|
|
|
if (AMDGPU::isGFX10Plus(STI)) {
|
2020-07-16 00:44:07 +08:00
|
|
|
if (Val == UFMT_DEFAULT)
|
|
|
|
return;
|
[AMDGPU][MC] Added support of SP3 syntax for MTBUF format modifier
Currently supported LLVM MTBUF syntax is shown below. It is not compatible with SP3.
op dst, addr, rsrc, FORMAT, soffset
This change adds support for SP3 syntax:
op dst, addr, rsrc, soffset SP3FORMAT
In addition to being compatible with SP3, this syntax allows using symbolic names for data, numeric and unified formats. Below is a list of added syntax variants.
format:<expression>
format:[<numeric-format-name>,<data-format-name>]
format:[<data-format-name>,<numeric-format-name>]
format:[<data-format-name>]
format:[<numeric-format-name>]
format:[<unified-format-name>]
The last syntax variant is supported for GFX10 only.
See llvm bug 37738
Reviewers: arsenm, rampitec, vpykhtin
Differential Revision: https://reviews.llvm.org/D84026
2020-07-24 21:39:42 +08:00
|
|
|
if (isValidUnifiedFormat(Val)) {
|
|
|
|
O << " format:[" << getUnifiedFormatName(Val) << ']';
|
|
|
|
} else {
|
|
|
|
O << " format:" << Val;
|
|
|
|
}
|
2020-07-16 00:44:07 +08:00
|
|
|
} else {
|
|
|
|
if (Val == DFMT_NFMT_DEFAULT)
|
|
|
|
return;
|
[AMDGPU][MC] Added support of SP3 syntax for MTBUF format modifier
Currently supported LLVM MTBUF syntax is shown below. It is not compatible with SP3.
op dst, addr, rsrc, FORMAT, soffset
This change adds support for SP3 syntax:
op dst, addr, rsrc, soffset SP3FORMAT
In addition to being compatible with SP3, this syntax allows using symbolic names for data, numeric and unified formats. Below is a list of added syntax variants.
format:<expression>
format:[<numeric-format-name>,<data-format-name>]
format:[<data-format-name>,<numeric-format-name>]
format:[<data-format-name>]
format:[<numeric-format-name>]
format:[<unified-format-name>]
The last syntax variant is supported for GFX10 only.
See llvm bug 37738
Reviewers: arsenm, rampitec, vpykhtin
Differential Revision: https://reviews.llvm.org/D84026
2020-07-24 21:39:42 +08:00
|
|
|
if (isValidDfmtNfmt(Val, STI)) {
|
|
|
|
unsigned Dfmt;
|
|
|
|
unsigned Nfmt;
|
|
|
|
decodeDfmtNfmt(Val, Dfmt, Nfmt);
|
|
|
|
O << " format:[";
|
|
|
|
if (Dfmt != DFMT_DEFAULT) {
|
|
|
|
O << getDfmtName(Dfmt);
|
|
|
|
if (Nfmt != NFMT_DEFAULT) {
|
|
|
|
O << ',';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Nfmt != NFMT_DEFAULT) {
|
|
|
|
O << getNfmtName(Nfmt, STI);
|
|
|
|
}
|
|
|
|
O << ']';
|
|
|
|
} else {
|
|
|
|
O << " format:" << Val;
|
|
|
|
}
|
2017-06-23 00:29:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 22:42:48 +08:00
|
|
|
void AMDGPUInstPrinter::printRegOperand(unsigned RegNo, raw_ostream &O,
|
2015-04-08 09:09:26 +08:00
|
|
|
const MCRegisterInfo &MRI) {
|
2019-07-18 06:58:43 +08:00
|
|
|
#if !defined(NDEBUG)
|
2016-09-27 22:42:48 +08:00
|
|
|
switch (RegNo) {
|
2017-07-25 02:06:15 +08:00
|
|
|
case AMDGPU::FP_REG:
|
|
|
|
case AMDGPU::SP_REG:
|
|
|
|
case AMDGPU::PRIVATE_RSRC_REG:
|
|
|
|
llvm_unreachable("pseudo-register should not ever be emitted");
|
2019-06-03 21:51:24 +08:00
|
|
|
case AMDGPU::SCC:
|
|
|
|
llvm_unreachable("pseudo scc should not ever be emitted");
|
2013-11-12 10:35:51 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-07-18 06:58:43 +08:00
|
|
|
#endif
|
|
|
|
|
2020-05-06 01:25:54 +08:00
|
|
|
StringRef RegName(getRegisterName(RegNo));
|
|
|
|
if (!Keep16BitSuffixes)
|
|
|
|
if (!RegName.consume_back(".l"))
|
|
|
|
RegName.consume_back(".h");
|
|
|
|
|
|
|
|
O << RegName;
|
2013-11-12 10:35:51 +08:00
|
|
|
}
|
|
|
|
|
2015-03-13 05:34:22 +08:00
|
|
|
void AMDGPUInstPrinter::printVOPDst(const MCInst *MI, unsigned OpNo,
|
2021-04-01 18:41:09 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
auto Opcode = MI->getOpcode();
|
|
|
|
auto Flags = MII.get(Opcode).TSFlags;
|
|
|
|
|
2019-04-27 07:16:16 +08:00
|
|
|
if (OpNo == 0) {
|
2021-04-01 18:41:09 +08:00
|
|
|
if (Flags & SIInstrFlags::VOP3) {
|
|
|
|
if (!getVOP3IsSingle(Opcode))
|
|
|
|
O << "_e64";
|
|
|
|
} else if (Flags & SIInstrFlags::DPP) {
|
|
|
|
O << "_dpp";
|
|
|
|
} else if (Flags & SIInstrFlags::SDWA) {
|
|
|
|
O << "_sdwa";
|
|
|
|
} else if (((Flags & SIInstrFlags::VOP1) && !getVOP1IsSingle(Opcode)) ||
|
|
|
|
((Flags & SIInstrFlags::VOP2) && !getVOP2IsSingle(Opcode))) {
|
|
|
|
O << "_e32";
|
|
|
|
}
|
|
|
|
O << " ";
|
2019-04-27 07:16:16 +08:00
|
|
|
}
|
2015-03-13 05:34:22 +08:00
|
|
|
|
2016-09-27 22:42:48 +08:00
|
|
|
printOperand(MI, OpNo, STI, O);
|
2019-04-27 07:16:16 +08:00
|
|
|
|
2019-06-14 03:18:29 +08:00
|
|
|
// Print default vcc/vcc_lo operand.
|
2021-04-01 18:41:09 +08:00
|
|
|
switch (Opcode) {
|
2019-04-27 07:16:16 +08:00
|
|
|
default: break;
|
|
|
|
|
|
|
|
case AMDGPU::V_ADD_CO_CI_U32_e32_gfx10:
|
|
|
|
case AMDGPU::V_SUB_CO_CI_U32_e32_gfx10:
|
|
|
|
case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx10:
|
|
|
|
case AMDGPU::V_ADD_CO_CI_U32_sdwa_gfx10:
|
|
|
|
case AMDGPU::V_SUB_CO_CI_U32_sdwa_gfx10:
|
|
|
|
case AMDGPU::V_SUBREV_CO_CI_U32_sdwa_gfx10:
|
2019-06-13 02:02:41 +08:00
|
|
|
case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx10:
|
|
|
|
case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx10:
|
|
|
|
case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx10:
|
|
|
|
case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx10:
|
|
|
|
case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx10:
|
|
|
|
case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx10:
|
2019-04-27 07:16:16 +08:00
|
|
|
printDefaultVccOperand(1, STI, O);
|
|
|
|
break;
|
|
|
|
}
|
2015-03-13 05:34:22 +08:00
|
|
|
}
|
|
|
|
|
2018-03-17 00:38:04 +08:00
|
|
|
void AMDGPUInstPrinter::printVINTRPDst(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
|
|
|
if (AMDGPU::isSI(STI) || AMDGPU::isCI(STI))
|
|
|
|
O << " ";
|
|
|
|
else
|
|
|
|
O << "_e32 ";
|
|
|
|
|
|
|
|
printOperand(MI, OpNo, STI, O);
|
|
|
|
}
|
|
|
|
|
AMDGPU: Don't use 16-bit FP inline constants in integer operands
It seems to be a hardware defect that the half inline constants do not
work as expected for the 16-bit integer operations (the inverse does
work correctly). Experimentation seems to show these are really
reading the 32-bit inline constants, which can be observed by writing
inline asm using op_sel to see what's in the high half of the
constant. Theoretically we could fold the high halves of the 32-bit
constants using op_sel.
The *_asm_all.s MC tests are broken, and I don't know where the script
to autogenerate these are. I started manually fixing it, but there's
just too many cases to fix. This also does break the
assembler/disassembler support for these values, and I'm not sure what
to do about it. These are still valid encodings, so it seems like you
should be able to use them in some way. If you wrote assembly using
them, you could have really meant it (perhaps to read the high bits
with op_sel?). The disassembler will print the invalid literal
constant which will fail to re-assemble. The behavior is also
different depending on the use context. Consider this example, which
was previously accepted and encoded using the inline constant:
v_mad_i16 v5, v1, -4.0, v3
; encoding: [0x05,0x00,0xec,0xd1,0x01,0xef,0x0d,0x04]
In contexts where an inline immediate is required (such as on gfx8/9),
this will now be rejected. For gfx10, this will produce the literal
encoding and change the printed format:
v_mad_i16 v5, v1, 0xc400, v3
; encoding: [0x05,0x00,0x5e,0xd7,0x01,0xff,0x0d,0x04,0x00,0xc4,0x00,0x00]
This is just another variation of the issue that we don't perfectly
handle round trip assembly/disassembly due to not tracking how
immediates were encoded. This doesn't matter much in practice, since
compilers don't emit the suboptimal encoding. I doubt any users are
relying on this behavior (although I did make use of the old behavior
to figure out what was wrong).
Fixes bug 46302.
2020-06-15 01:09:02 +08:00
|
|
|
void AMDGPUInstPrinter::printImmediateInt16(uint32_t Imm,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
int16_t SImm = static_cast<int16_t>(Imm);
|
[AMDGPU][MC] Corrected decoding of 16-bit literals
16-bit literals are encoded as 32-bit values. If high 16-bits of the value is 0xFFFF, the decoded instruction cannot be reassembled.
For example, the following code
0xff,0x04,0x04,0x52,0xcd,0xab,0xff,0xff
was decoded as
v_mul_lo_u16_e32 v2, 0xffffabcd, v2
However this literal is actually a 64-bit constant 0x00000000ffffabcd which violates requirements described in the documentation - the truncation is not safe.
This change corrects decoding to make reassembly possible.
Reviewers: arsenm, rampitec
Differential Revision: https://reviews.llvm.org/D84098
2020-07-22 22:16:59 +08:00
|
|
|
if (isInlinableIntLiteral(SImm)) {
|
AMDGPU: Don't use 16-bit FP inline constants in integer operands
It seems to be a hardware defect that the half inline constants do not
work as expected for the 16-bit integer operations (the inverse does
work correctly). Experimentation seems to show these are really
reading the 32-bit inline constants, which can be observed by writing
inline asm using op_sel to see what's in the high half of the
constant. Theoretically we could fold the high halves of the 32-bit
constants using op_sel.
The *_asm_all.s MC tests are broken, and I don't know where the script
to autogenerate these are. I started manually fixing it, but there's
just too many cases to fix. This also does break the
assembler/disassembler support for these values, and I'm not sure what
to do about it. These are still valid encodings, so it seems like you
should be able to use them in some way. If you wrote assembly using
them, you could have really meant it (perhaps to read the high bits
with op_sel?). The disassembler will print the invalid literal
constant which will fail to re-assemble. The behavior is also
different depending on the use context. Consider this example, which
was previously accepted and encoded using the inline constant:
v_mad_i16 v5, v1, -4.0, v3
; encoding: [0x05,0x00,0xec,0xd1,0x01,0xef,0x0d,0x04]
In contexts where an inline immediate is required (such as on gfx8/9),
this will now be rejected. For gfx10, this will produce the literal
encoding and change the printed format:
v_mad_i16 v5, v1, 0xc400, v3
; encoding: [0x05,0x00,0x5e,0xd7,0x01,0xff,0x0d,0x04,0x00,0xc4,0x00,0x00]
This is just another variation of the issue that we don't perfectly
handle round trip assembly/disassembly due to not tracking how
immediates were encoded. This doesn't matter much in practice, since
compilers don't emit the suboptimal encoding. I doubt any users are
relying on this behavior (although I did make use of the old behavior
to figure out what was wrong).
Fixes bug 46302.
2020-06-15 01:09:02 +08:00
|
|
|
O << SImm;
|
[AMDGPU][MC] Corrected decoding of 16-bit literals
16-bit literals are encoded as 32-bit values. If high 16-bits of the value is 0xFFFF, the decoded instruction cannot be reassembled.
For example, the following code
0xff,0x04,0x04,0x52,0xcd,0xab,0xff,0xff
was decoded as
v_mul_lo_u16_e32 v2, 0xffffabcd, v2
However this literal is actually a 64-bit constant 0x00000000ffffabcd which violates requirements described in the documentation - the truncation is not safe.
This change corrects decoding to make reassembly possible.
Reviewers: arsenm, rampitec
Differential Revision: https://reviews.llvm.org/D84098
2020-07-22 22:16:59 +08:00
|
|
|
} else {
|
|
|
|
uint64_t Imm16 = static_cast<uint16_t>(Imm);
|
|
|
|
O << formatHex(Imm16);
|
|
|
|
}
|
AMDGPU: Don't use 16-bit FP inline constants in integer operands
It seems to be a hardware defect that the half inline constants do not
work as expected for the 16-bit integer operations (the inverse does
work correctly). Experimentation seems to show these are really
reading the 32-bit inline constants, which can be observed by writing
inline asm using op_sel to see what's in the high half of the
constant. Theoretically we could fold the high halves of the 32-bit
constants using op_sel.
The *_asm_all.s MC tests are broken, and I don't know where the script
to autogenerate these are. I started manually fixing it, but there's
just too many cases to fix. This also does break the
assembler/disassembler support for these values, and I'm not sure what
to do about it. These are still valid encodings, so it seems like you
should be able to use them in some way. If you wrote assembly using
them, you could have really meant it (perhaps to read the high bits
with op_sel?). The disassembler will print the invalid literal
constant which will fail to re-assemble. The behavior is also
different depending on the use context. Consider this example, which
was previously accepted and encoded using the inline constant:
v_mad_i16 v5, v1, -4.0, v3
; encoding: [0x05,0x00,0xec,0xd1,0x01,0xef,0x0d,0x04]
In contexts where an inline immediate is required (such as on gfx8/9),
this will now be rejected. For gfx10, this will produce the literal
encoding and change the printed format:
v_mad_i16 v5, v1, 0xc400, v3
; encoding: [0x05,0x00,0x5e,0xd7,0x01,0xff,0x0d,0x04,0x00,0xc4,0x00,0x00]
This is just another variation of the issue that we don't perfectly
handle round trip assembly/disassembly due to not tracking how
immediates were encoded. This doesn't matter much in practice, since
compilers don't emit the suboptimal encoding. I doubt any users are
relying on this behavior (although I did make use of the old behavior
to figure out what was wrong).
Fixes bug 46302.
2020-06-15 01:09:02 +08:00
|
|
|
}
|
|
|
|
|
2016-12-10 08:39:12 +08:00
|
|
|
void AMDGPUInstPrinter::printImmediate16(uint32_t Imm,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
int16_t SImm = static_cast<int16_t>(Imm);
|
AMDGPU: Don't use 16-bit FP inline constants in integer operands
It seems to be a hardware defect that the half inline constants do not
work as expected for the 16-bit integer operations (the inverse does
work correctly). Experimentation seems to show these are really
reading the 32-bit inline constants, which can be observed by writing
inline asm using op_sel to see what's in the high half of the
constant. Theoretically we could fold the high halves of the 32-bit
constants using op_sel.
The *_asm_all.s MC tests are broken, and I don't know where the script
to autogenerate these are. I started manually fixing it, but there's
just too many cases to fix. This also does break the
assembler/disassembler support for these values, and I'm not sure what
to do about it. These are still valid encodings, so it seems like you
should be able to use them in some way. If you wrote assembly using
them, you could have really meant it (perhaps to read the high bits
with op_sel?). The disassembler will print the invalid literal
constant which will fail to re-assemble. The behavior is also
different depending on the use context. Consider this example, which
was previously accepted and encoded using the inline constant:
v_mad_i16 v5, v1, -4.0, v3
; encoding: [0x05,0x00,0xec,0xd1,0x01,0xef,0x0d,0x04]
In contexts where an inline immediate is required (such as on gfx8/9),
this will now be rejected. For gfx10, this will produce the literal
encoding and change the printed format:
v_mad_i16 v5, v1, 0xc400, v3
; encoding: [0x05,0x00,0x5e,0xd7,0x01,0xff,0x0d,0x04,0x00,0xc4,0x00,0x00]
This is just another variation of the issue that we don't perfectly
handle round trip assembly/disassembly due to not tracking how
immediates were encoded. This doesn't matter much in practice, since
compilers don't emit the suboptimal encoding. I doubt any users are
relying on this behavior (although I did make use of the old behavior
to figure out what was wrong).
Fixes bug 46302.
2020-06-15 01:09:02 +08:00
|
|
|
if (isInlinableIntLiteral(SImm)) {
|
2016-12-10 08:39:12 +08:00
|
|
|
O << SImm;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Imm == 0x3C00)
|
|
|
|
O<< "1.0";
|
|
|
|
else if (Imm == 0xBC00)
|
|
|
|
O<< "-1.0";
|
|
|
|
else if (Imm == 0x3800)
|
|
|
|
O<< "0.5";
|
|
|
|
else if (Imm == 0xB800)
|
|
|
|
O<< "-0.5";
|
|
|
|
else if (Imm == 0x4000)
|
|
|
|
O<< "2.0";
|
|
|
|
else if (Imm == 0xC000)
|
|
|
|
O<< "-2.0";
|
|
|
|
else if (Imm == 0x4400)
|
|
|
|
O<< "4.0";
|
|
|
|
else if (Imm == 0xC400)
|
|
|
|
O<< "-4.0";
|
2020-07-23 00:27:50 +08:00
|
|
|
else if (Imm == 0x3118 &&
|
|
|
|
STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm]) {
|
2016-12-10 08:39:12 +08:00
|
|
|
O << "0.15915494";
|
[AMDGPU][MC] Corrected decoding of 16-bit literals
16-bit literals are encoded as 32-bit values. If high 16-bits of the value is 0xFFFF, the decoded instruction cannot be reassembled.
For example, the following code
0xff,0x04,0x04,0x52,0xcd,0xab,0xff,0xff
was decoded as
v_mul_lo_u16_e32 v2, 0xffffabcd, v2
However this literal is actually a 64-bit constant 0x00000000ffffabcd which violates requirements described in the documentation - the truncation is not safe.
This change corrects decoding to make reassembly possible.
Reviewers: arsenm, rampitec
Differential Revision: https://reviews.llvm.org/D84098
2020-07-22 22:16:59 +08:00
|
|
|
} else {
|
|
|
|
uint64_t Imm16 = static_cast<uint16_t>(Imm);
|
|
|
|
O << formatHex(Imm16);
|
|
|
|
}
|
2016-12-10 08:39:12 +08:00
|
|
|
}
|
|
|
|
|
2017-02-28 02:49:11 +08:00
|
|
|
void AMDGPUInstPrinter::printImmediateV216(uint32_t Imm,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
uint16_t Lo16 = static_cast<uint16_t>(Imm);
|
|
|
|
printImmediate16(Lo16, STI, O);
|
|
|
|
}
|
|
|
|
|
2016-10-29 12:05:06 +08:00
|
|
|
void AMDGPUInstPrinter::printImmediate32(uint32_t Imm,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2014-04-16 06:32:49 +08:00
|
|
|
int32_t SImm = static_cast<int32_t>(Imm);
|
|
|
|
if (SImm >= -16 && SImm <= 64) {
|
|
|
|
O << SImm;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-18 01:32:13 +08:00
|
|
|
if (Imm == FloatToBits(0.0f))
|
|
|
|
O << "0.0";
|
|
|
|
else if (Imm == FloatToBits(1.0f))
|
|
|
|
O << "1.0";
|
|
|
|
else if (Imm == FloatToBits(-1.0f))
|
|
|
|
O << "-1.0";
|
|
|
|
else if (Imm == FloatToBits(0.5f))
|
|
|
|
O << "0.5";
|
|
|
|
else if (Imm == FloatToBits(-0.5f))
|
|
|
|
O << "-0.5";
|
|
|
|
else if (Imm == FloatToBits(2.0f))
|
|
|
|
O << "2.0";
|
|
|
|
else if (Imm == FloatToBits(-2.0f))
|
|
|
|
O << "-2.0";
|
|
|
|
else if (Imm == FloatToBits(4.0f))
|
|
|
|
O << "4.0";
|
|
|
|
else if (Imm == FloatToBits(-4.0f))
|
|
|
|
O << "-4.0";
|
2016-10-29 12:05:06 +08:00
|
|
|
else if (Imm == 0x3e22f983 &&
|
|
|
|
STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
|
2016-11-15 08:04:33 +08:00
|
|
|
O << "0.15915494";
|
2014-12-18 05:04:08 +08:00
|
|
|
else
|
2014-09-18 01:32:13 +08:00
|
|
|
O << formatHex(static_cast<uint64_t>(Imm));
|
2014-12-18 05:04:08 +08:00
|
|
|
}
|
|
|
|
|
2016-10-29 12:05:06 +08:00
|
|
|
void AMDGPUInstPrinter::printImmediate64(uint64_t Imm,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2014-12-18 05:04:08 +08:00
|
|
|
int64_t SImm = static_cast<int64_t>(Imm);
|
|
|
|
if (SImm >= -16 && SImm <= 64) {
|
|
|
|
O << SImm;
|
|
|
|
return;
|
2014-04-16 06:32:49 +08:00
|
|
|
}
|
2014-12-18 05:04:08 +08:00
|
|
|
|
|
|
|
if (Imm == DoubleToBits(0.0))
|
|
|
|
O << "0.0";
|
|
|
|
else if (Imm == DoubleToBits(1.0))
|
|
|
|
O << "1.0";
|
|
|
|
else if (Imm == DoubleToBits(-1.0))
|
|
|
|
O << "-1.0";
|
|
|
|
else if (Imm == DoubleToBits(0.5))
|
|
|
|
O << "0.5";
|
|
|
|
else if (Imm == DoubleToBits(-0.5))
|
|
|
|
O << "-0.5";
|
|
|
|
else if (Imm == DoubleToBits(2.0))
|
|
|
|
O << "2.0";
|
|
|
|
else if (Imm == DoubleToBits(-2.0))
|
|
|
|
O << "-2.0";
|
|
|
|
else if (Imm == DoubleToBits(4.0))
|
|
|
|
O << "4.0";
|
|
|
|
else if (Imm == DoubleToBits(-4.0))
|
|
|
|
O << "-4.0";
|
2016-10-29 12:05:06 +08:00
|
|
|
else if (Imm == 0x3fc45f306dc9c882 &&
|
|
|
|
STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
|
2019-01-18 23:17:17 +08:00
|
|
|
O << "0.15915494309189532";
|
2015-10-24 02:07:58 +08:00
|
|
|
else {
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 22:44:04 +08:00
|
|
|
assert(isUInt<32>(Imm) || Imm == 0x3fc45f306dc9c882);
|
2015-10-24 02:07:58 +08:00
|
|
|
|
|
|
|
// In rare situations, we will have a 32-bit literal in a 64-bit
|
|
|
|
// operand. This is technically allowed for the encoding of s_mov_b64.
|
|
|
|
O << formatHex(static_cast<uint64_t>(Imm));
|
|
|
|
}
|
2014-04-16 06:32:49 +08:00
|
|
|
}
|
|
|
|
|
2019-07-10 05:43:09 +08:00
|
|
|
void AMDGPUInstPrinter::printBLGP(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (!Imm)
|
|
|
|
return;
|
|
|
|
|
|
|
|
O << " blgp:" << Imm;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printCBSZ(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (!Imm)
|
|
|
|
return;
|
|
|
|
|
|
|
|
O << " cbsz:" << Imm;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printABID(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (!Imm)
|
|
|
|
return;
|
|
|
|
|
|
|
|
O << " abid:" << Imm;
|
|
|
|
}
|
|
|
|
|
2019-04-27 07:16:16 +08:00
|
|
|
void AMDGPUInstPrinter::printDefaultVccOperand(unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
if (OpNo > 0)
|
|
|
|
O << ", ";
|
2019-06-14 03:18:29 +08:00
|
|
|
printRegOperand(STI.getFeatureBits()[AMDGPU::FeatureWavefrontSize64] ?
|
|
|
|
AMDGPU::VCC : AMDGPU::VCC_LO, O, MRI);
|
2019-04-27 07:16:16 +08:00
|
|
|
if (OpNo == 0)
|
|
|
|
O << ", ";
|
|
|
|
}
|
|
|
|
|
2012-12-12 05:25:42 +08:00
|
|
|
void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2012-12-12 05:25:42 +08:00
|
|
|
raw_ostream &O) {
|
2019-06-14 03:18:29 +08:00
|
|
|
// Print default vcc/vcc_lo operand of VOPC.
|
2019-04-27 07:16:16 +08:00
|
|
|
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
|
|
|
|
if (OpNo == 0 && (Desc.TSFlags & SIInstrFlags::VOPC) &&
|
|
|
|
(Desc.hasImplicitDefOfPhysReg(AMDGPU::VCC) ||
|
|
|
|
Desc.hasImplicitDefOfPhysReg(AMDGPU::VCC_LO)))
|
|
|
|
printDefaultVccOperand(OpNo, STI, O);
|
|
|
|
|
2016-08-15 18:56:48 +08:00
|
|
|
if (OpNo >= MI->getNumOperands()) {
|
|
|
|
O << "/*Missing OP" << OpNo << "*/";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-12 05:25:42 +08:00
|
|
|
const MCOperand &Op = MI->getOperand(OpNo);
|
|
|
|
if (Op.isReg()) {
|
AMDGPU: Add R600InstPrinter class
Summary:
This is step towards separating the GCN and R600 tablegen'd code.
This is a little awkward for now, because the R600 functions won't have the
MCSubtargetInfo parameter, so we need to have AMDMGPUInstPrinter
delegate to R600InstPrinter, but once the tablegen'd code is split,
we will be able to drop the delegation and use R600InstPrinter directly.
Reviewers: arsenm
Subscribers: kzhuravl, wdng, nhaehnle, yaxunl, dstuttard, tpr, t-tye, llvm-commits
Differential Revision: https://reviews.llvm.org/D36444
llvm-svn: 311128
2017-08-18 06:20:04 +08:00
|
|
|
printRegOperand(Op.getReg(), O, MRI);
|
2012-12-12 05:25:42 +08:00
|
|
|
} else if (Op.isImm()) {
|
AMDGPU: Don't use 16-bit FP inline constants in integer operands
It seems to be a hardware defect that the half inline constants do not
work as expected for the 16-bit integer operations (the inverse does
work correctly). Experimentation seems to show these are really
reading the 32-bit inline constants, which can be observed by writing
inline asm using op_sel to see what's in the high half of the
constant. Theoretically we could fold the high halves of the 32-bit
constants using op_sel.
The *_asm_all.s MC tests are broken, and I don't know where the script
to autogenerate these are. I started manually fixing it, but there's
just too many cases to fix. This also does break the
assembler/disassembler support for these values, and I'm not sure what
to do about it. These are still valid encodings, so it seems like you
should be able to use them in some way. If you wrote assembly using
them, you could have really meant it (perhaps to read the high bits
with op_sel?). The disassembler will print the invalid literal
constant which will fail to re-assemble. The behavior is also
different depending on the use context. Consider this example, which
was previously accepted and encoded using the inline constant:
v_mad_i16 v5, v1, -4.0, v3
; encoding: [0x05,0x00,0xec,0xd1,0x01,0xef,0x0d,0x04]
In contexts where an inline immediate is required (such as on gfx8/9),
this will now be rejected. For gfx10, this will produce the literal
encoding and change the printed format:
v_mad_i16 v5, v1, 0xc400, v3
; encoding: [0x05,0x00,0x5e,0xd7,0x01,0xff,0x0d,0x04,0x00,0xc4,0x00,0x00]
This is just another variation of the issue that we don't perfectly
handle round trip assembly/disassembly due to not tracking how
immediates were encoded. This doesn't matter much in practice, since
compilers don't emit the suboptimal encoding. I doubt any users are
relying on this behavior (although I did make use of the old behavior
to figure out what was wrong).
Fixes bug 46302.
2020-06-15 01:09:02 +08:00
|
|
|
const uint8_t OpTy = Desc.OpInfo[OpNo].OperandType;
|
|
|
|
switch (OpTy) {
|
2016-12-10 08:39:12 +08:00
|
|
|
case AMDGPU::OPERAND_REG_IMM_INT32:
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_FP32:
|
2021-10-04 22:56:30 +08:00
|
|
|
case AMDGPU::OPERAND_REG_IMM_FP32_DEFERRED:
|
2016-12-10 08:39:12 +08:00
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_INT32:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_FP32:
|
2019-07-10 05:43:09 +08:00
|
|
|
case AMDGPU::OPERAND_REG_INLINE_AC_INT32:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_AC_FP32:
|
2021-02-18 05:37:46 +08:00
|
|
|
case AMDGPU::OPERAND_REG_IMM_V2INT32:
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_V2FP32:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_V2INT32:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_V2FP32:
|
2016-12-10 08:39:12 +08:00
|
|
|
case MCOI::OPERAND_IMMEDIATE:
|
2016-10-29 12:05:06 +08:00
|
|
|
printImmediate32(Op.getImm(), STI, O);
|
2016-12-10 08:39:12 +08:00
|
|
|
break;
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_INT64:
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_FP64:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_INT64:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_FP64:
|
2021-02-18 05:37:46 +08:00
|
|
|
case AMDGPU::OPERAND_REG_INLINE_AC_FP64:
|
2016-12-10 08:39:12 +08:00
|
|
|
printImmediate64(Op.getImm(), STI, O);
|
|
|
|
break;
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_INT16:
|
2019-07-10 05:43:09 +08:00
|
|
|
case AMDGPU::OPERAND_REG_INLINE_AC_INT16:
|
2016-12-10 08:39:12 +08:00
|
|
|
case AMDGPU::OPERAND_REG_IMM_INT16:
|
AMDGPU: Don't use 16-bit FP inline constants in integer operands
It seems to be a hardware defect that the half inline constants do not
work as expected for the 16-bit integer operations (the inverse does
work correctly). Experimentation seems to show these are really
reading the 32-bit inline constants, which can be observed by writing
inline asm using op_sel to see what's in the high half of the
constant. Theoretically we could fold the high halves of the 32-bit
constants using op_sel.
The *_asm_all.s MC tests are broken, and I don't know where the script
to autogenerate these are. I started manually fixing it, but there's
just too many cases to fix. This also does break the
assembler/disassembler support for these values, and I'm not sure what
to do about it. These are still valid encodings, so it seems like you
should be able to use them in some way. If you wrote assembly using
them, you could have really meant it (perhaps to read the high bits
with op_sel?). The disassembler will print the invalid literal
constant which will fail to re-assemble. The behavior is also
different depending on the use context. Consider this example, which
was previously accepted and encoded using the inline constant:
v_mad_i16 v5, v1, -4.0, v3
; encoding: [0x05,0x00,0xec,0xd1,0x01,0xef,0x0d,0x04]
In contexts where an inline immediate is required (such as on gfx8/9),
this will now be rejected. For gfx10, this will produce the literal
encoding and change the printed format:
v_mad_i16 v5, v1, 0xc400, v3
; encoding: [0x05,0x00,0x5e,0xd7,0x01,0xff,0x0d,0x04,0x00,0xc4,0x00,0x00]
This is just another variation of the issue that we don't perfectly
handle round trip assembly/disassembly due to not tracking how
immediates were encoded. This doesn't matter much in practice, since
compilers don't emit the suboptimal encoding. I doubt any users are
relying on this behavior (although I did make use of the old behavior
to figure out what was wrong).
Fixes bug 46302.
2020-06-15 01:09:02 +08:00
|
|
|
printImmediateInt16(Op.getImm(), STI, O);
|
|
|
|
break;
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_FP16:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_AC_FP16:
|
2016-12-10 08:39:12 +08:00
|
|
|
case AMDGPU::OPERAND_REG_IMM_FP16:
|
2021-10-04 22:56:30 +08:00
|
|
|
case AMDGPU::OPERAND_REG_IMM_FP16_DEFERRED:
|
2016-12-10 08:39:12 +08:00
|
|
|
printImmediate16(Op.getImm(), STI, O);
|
|
|
|
break;
|
2019-05-02 12:01:39 +08:00
|
|
|
case AMDGPU::OPERAND_REG_IMM_V2INT16:
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_V2FP16:
|
|
|
|
if (!isUInt<16>(Op.getImm()) &&
|
|
|
|
STI.getFeatureBits()[AMDGPU::FeatureVOP3Literal]) {
|
|
|
|
printImmediate32(Op.getImm(), STI, O);
|
|
|
|
break;
|
|
|
|
}
|
AMDGPU: Don't use 16-bit FP inline constants in integer operands
It seems to be a hardware defect that the half inline constants do not
work as expected for the 16-bit integer operations (the inverse does
work correctly). Experimentation seems to show these are really
reading the 32-bit inline constants, which can be observed by writing
inline asm using op_sel to see what's in the high half of the
constant. Theoretically we could fold the high halves of the 32-bit
constants using op_sel.
The *_asm_all.s MC tests are broken, and I don't know where the script
to autogenerate these are. I started manually fixing it, but there's
just too many cases to fix. This also does break the
assembler/disassembler support for these values, and I'm not sure what
to do about it. These are still valid encodings, so it seems like you
should be able to use them in some way. If you wrote assembly using
them, you could have really meant it (perhaps to read the high bits
with op_sel?). The disassembler will print the invalid literal
constant which will fail to re-assemble. The behavior is also
different depending on the use context. Consider this example, which
was previously accepted and encoded using the inline constant:
v_mad_i16 v5, v1, -4.0, v3
; encoding: [0x05,0x00,0xec,0xd1,0x01,0xef,0x0d,0x04]
In contexts where an inline immediate is required (such as on gfx8/9),
this will now be rejected. For gfx10, this will produce the literal
encoding and change the printed format:
v_mad_i16 v5, v1, 0xc400, v3
; encoding: [0x05,0x00,0x5e,0xd7,0x01,0xff,0x0d,0x04,0x00,0xc4,0x00,0x00]
This is just another variation of the issue that we don't perfectly
handle round trip assembly/disassembly due to not tracking how
immediates were encoded. This doesn't matter much in practice, since
compilers don't emit the suboptimal encoding. I doubt any users are
relying on this behavior (although I did make use of the old behavior
to figure out what was wrong).
Fixes bug 46302.
2020-06-15 01:09:02 +08:00
|
|
|
|
|
|
|
// Deal with 16-bit FP inline immediates not working.
|
|
|
|
if (OpTy == AMDGPU::OPERAND_REG_IMM_V2FP16) {
|
|
|
|
printImmediate16(static_cast<uint16_t>(Op.getImm()), STI, O);
|
|
|
|
break;
|
|
|
|
}
|
2019-05-02 12:01:39 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2017-02-28 02:49:11 +08:00
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_V2INT16:
|
2019-07-10 05:43:09 +08:00
|
|
|
case AMDGPU::OPERAND_REG_INLINE_AC_V2INT16:
|
AMDGPU: Don't use 16-bit FP inline constants in integer operands
It seems to be a hardware defect that the half inline constants do not
work as expected for the 16-bit integer operations (the inverse does
work correctly). Experimentation seems to show these are really
reading the 32-bit inline constants, which can be observed by writing
inline asm using op_sel to see what's in the high half of the
constant. Theoretically we could fold the high halves of the 32-bit
constants using op_sel.
The *_asm_all.s MC tests are broken, and I don't know where the script
to autogenerate these are. I started manually fixing it, but there's
just too many cases to fix. This also does break the
assembler/disassembler support for these values, and I'm not sure what
to do about it. These are still valid encodings, so it seems like you
should be able to use them in some way. If you wrote assembly using
them, you could have really meant it (perhaps to read the high bits
with op_sel?). The disassembler will print the invalid literal
constant which will fail to re-assemble. The behavior is also
different depending on the use context. Consider this example, which
was previously accepted and encoded using the inline constant:
v_mad_i16 v5, v1, -4.0, v3
; encoding: [0x05,0x00,0xec,0xd1,0x01,0xef,0x0d,0x04]
In contexts where an inline immediate is required (such as on gfx8/9),
this will now be rejected. For gfx10, this will produce the literal
encoding and change the printed format:
v_mad_i16 v5, v1, 0xc400, v3
; encoding: [0x05,0x00,0x5e,0xd7,0x01,0xff,0x0d,0x04,0x00,0xc4,0x00,0x00]
This is just another variation of the issue that we don't perfectly
handle round trip assembly/disassembly due to not tracking how
immediates were encoded. This doesn't matter much in practice, since
compilers don't emit the suboptimal encoding. I doubt any users are
relying on this behavior (although I did make use of the old behavior
to figure out what was wrong).
Fixes bug 46302.
2020-06-15 01:09:02 +08:00
|
|
|
printImmediateInt16(static_cast<uint16_t>(Op.getImm()), STI, O);
|
|
|
|
break;
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_V2FP16:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_AC_V2FP16:
|
2017-02-28 02:49:11 +08:00
|
|
|
printImmediateV216(Op.getImm(), STI, O);
|
|
|
|
break;
|
2016-12-10 08:39:12 +08:00
|
|
|
case MCOI::OPERAND_UNKNOWN:
|
|
|
|
case MCOI::OPERAND_PCREL:
|
|
|
|
O << formatDec(Op.getImm());
|
|
|
|
break;
|
|
|
|
case MCOI::OPERAND_REGISTER:
|
|
|
|
// FIXME: This should be removed and handled somewhere else. Seems to come
|
|
|
|
// from a disassembler bug.
|
|
|
|
O << "/*invalid immediate*/";
|
|
|
|
break;
|
|
|
|
default:
|
2014-12-18 05:04:08 +08:00
|
|
|
// We hit this for the immediate instruction bits that don't yet have a
|
|
|
|
// custom printer.
|
2016-12-10 08:39:12 +08:00
|
|
|
llvm_unreachable("unexpected immediate operand type");
|
2014-12-18 05:04:08 +08:00
|
|
|
}
|
2021-02-05 10:01:38 +08:00
|
|
|
} else if (Op.isDFPImm()) {
|
|
|
|
double Value = bit_cast<double>(Op.getDFPImm());
|
2014-09-18 01:32:13 +08:00
|
|
|
// We special case 0.0 because otherwise it will be printed as an integer.
|
2021-02-05 10:01:38 +08:00
|
|
|
if (Value == 0.0)
|
2014-09-18 01:32:13 +08:00
|
|
|
O << "0.0";
|
2014-12-18 05:04:08 +08:00
|
|
|
else {
|
|
|
|
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
|
2016-10-20 01:40:36 +08:00
|
|
|
int RCID = Desc.OpInfo[OpNo].RegClass;
|
|
|
|
unsigned RCBits = AMDGPU::getRegBitWidth(MRI.getRegClass(RCID));
|
|
|
|
if (RCBits == 32)
|
2021-02-05 10:01:38 +08:00
|
|
|
printImmediate32(FloatToBits(Value), STI, O);
|
2016-10-20 01:40:36 +08:00
|
|
|
else if (RCBits == 64)
|
2021-02-05 10:01:38 +08:00
|
|
|
printImmediate64(DoubleToBits(Value), STI, O);
|
2014-12-18 05:04:08 +08:00
|
|
|
else
|
|
|
|
llvm_unreachable("Invalid register class size");
|
|
|
|
}
|
2013-02-21 23:17:22 +08:00
|
|
|
} else if (Op.isExpr()) {
|
|
|
|
const MCExpr *Exp = Op.getExpr();
|
2015-06-09 08:31:39 +08:00
|
|
|
Exp->print(O, &MAI);
|
2012-12-12 05:25:42 +08:00
|
|
|
} else {
|
2016-03-01 21:57:29 +08:00
|
|
|
O << "/*INV_OP*/";
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
2019-04-27 07:16:16 +08:00
|
|
|
|
2019-06-14 03:18:29 +08:00
|
|
|
// Print default vcc/vcc_lo operand of v_cndmask_b32_e32.
|
2019-04-27 07:16:16 +08:00
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
|
|
|
|
case AMDGPU::V_CNDMASK_B32_e32_gfx10:
|
|
|
|
case AMDGPU::V_ADD_CO_CI_U32_e32_gfx10:
|
|
|
|
case AMDGPU::V_SUB_CO_CI_U32_e32_gfx10:
|
|
|
|
case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx10:
|
2019-10-18 22:49:53 +08:00
|
|
|
case AMDGPU::V_CNDMASK_B32_dpp_gfx10:
|
2019-06-13 02:02:41 +08:00
|
|
|
case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx10:
|
|
|
|
case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx10:
|
|
|
|
case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx10:
|
2019-10-18 22:49:53 +08:00
|
|
|
case AMDGPU::V_CNDMASK_B32_dpp8_gfx10:
|
2019-06-13 02:02:41 +08:00
|
|
|
case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx10:
|
|
|
|
case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx10:
|
|
|
|
case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx10:
|
2019-04-27 07:16:16 +08:00
|
|
|
|
|
|
|
case AMDGPU::V_CNDMASK_B32_e32_gfx6_gfx7:
|
|
|
|
case AMDGPU::V_CNDMASK_B32_e32_vi:
|
|
|
|
if ((int)OpNo == AMDGPU::getNamedOperandIdx(MI->getOpcode(),
|
|
|
|
AMDGPU::OpName::src1))
|
|
|
|
printDefaultVccOperand(OpNo, STI, O);
|
|
|
|
break;
|
|
|
|
}
|
[AMDGPU][MC] Added support of SP3 syntax for MTBUF format modifier
Currently supported LLVM MTBUF syntax is shown below. It is not compatible with SP3.
op dst, addr, rsrc, FORMAT, soffset
This change adds support for SP3 syntax:
op dst, addr, rsrc, soffset SP3FORMAT
In addition to being compatible with SP3, this syntax allows using symbolic names for data, numeric and unified formats. Below is a list of added syntax variants.
format:<expression>
format:[<numeric-format-name>,<data-format-name>]
format:[<data-format-name>,<numeric-format-name>]
format:[<data-format-name>]
format:[<numeric-format-name>]
format:[<unified-format-name>]
The last syntax variant is supported for GFX10 only.
See llvm bug 37738
Reviewers: arsenm, rampitec, vpykhtin
Differential Revision: https://reviews.llvm.org/D84026
2020-07-24 21:39:42 +08:00
|
|
|
|
|
|
|
if (Desc.TSFlags & SIInstrFlags::MTBUF) {
|
|
|
|
int SOffsetIdx =
|
|
|
|
AMDGPU::getNamedOperandIdx(MI->getOpcode(), AMDGPU::OpName::soffset);
|
|
|
|
assert(SOffsetIdx != -1);
|
|
|
|
if ((int)OpNo == SOffsetIdx)
|
|
|
|
printSymbolicFormat(MI, STI, O);
|
|
|
|
}
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
|
|
|
|
2016-06-10 17:57:59 +08:00
|
|
|
void AMDGPUInstPrinter::printOperandAndFPInputMods(const MCInst *MI,
|
2016-09-27 22:42:48 +08:00
|
|
|
unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2014-05-11 03:18:33 +08:00
|
|
|
unsigned InputModifiers = MI->getOperand(OpNo).getImm();
|
2017-03-20 22:50:35 +08:00
|
|
|
|
|
|
|
// Use 'neg(...)' instead of '-' to avoid ambiguity.
|
|
|
|
// This is important for integer literals because
|
|
|
|
// -1 is not the same value as neg(1).
|
|
|
|
bool NegMnemo = false;
|
|
|
|
|
|
|
|
if (InputModifiers & SISrcMods::NEG) {
|
|
|
|
if (OpNo + 1 < MI->getNumOperands() &&
|
|
|
|
(InputModifiers & SISrcMods::ABS) == 0) {
|
|
|
|
const MCOperand &Op = MI->getOperand(OpNo + 1);
|
2021-02-05 10:01:38 +08:00
|
|
|
NegMnemo = Op.isImm() || Op.isDFPImm();
|
2017-03-20 22:50:35 +08:00
|
|
|
}
|
|
|
|
if (NegMnemo) {
|
|
|
|
O << "neg(";
|
|
|
|
} else {
|
|
|
|
O << '-';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 23:50:26 +08:00
|
|
|
if (InputModifiers & SISrcMods::ABS)
|
2014-09-22 01:27:28 +08:00
|
|
|
O << '|';
|
2016-09-27 22:42:48 +08:00
|
|
|
printOperand(MI, OpNo + 1, STI, O);
|
2014-09-29 23:50:26 +08:00
|
|
|
if (InputModifiers & SISrcMods::ABS)
|
2014-09-22 01:27:28 +08:00
|
|
|
O << '|';
|
2017-03-20 22:50:35 +08:00
|
|
|
|
|
|
|
if (NegMnemo) {
|
|
|
|
O << ')';
|
|
|
|
}
|
2014-05-11 03:18:33 +08:00
|
|
|
}
|
|
|
|
|
2016-06-10 17:57:59 +08:00
|
|
|
void AMDGPUInstPrinter::printOperandAndIntInputMods(const MCInst *MI,
|
2016-09-27 22:42:48 +08:00
|
|
|
unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2016-06-10 17:57:59 +08:00
|
|
|
unsigned InputModifiers = MI->getOperand(OpNo).getImm();
|
|
|
|
if (InputModifiers & SISrcMods::SEXT)
|
|
|
|
O << "sext(";
|
2016-09-27 22:42:48 +08:00
|
|
|
printOperand(MI, OpNo + 1, STI, O);
|
2016-06-10 17:57:59 +08:00
|
|
|
if (InputModifiers & SISrcMods::SEXT)
|
|
|
|
O << ')';
|
2019-04-27 07:16:16 +08:00
|
|
|
|
2019-06-14 03:18:29 +08:00
|
|
|
// Print default vcc/vcc_lo operand of VOP2b.
|
2019-04-27 07:16:16 +08:00
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
|
2019-10-18 22:49:53 +08:00
|
|
|
case AMDGPU::V_CNDMASK_B32_sdwa_gfx10:
|
2019-04-27 07:16:16 +08:00
|
|
|
case AMDGPU::V_ADD_CO_CI_U32_sdwa_gfx10:
|
|
|
|
case AMDGPU::V_SUB_CO_CI_U32_sdwa_gfx10:
|
|
|
|
case AMDGPU::V_SUBREV_CO_CI_U32_sdwa_gfx10:
|
|
|
|
if ((int)OpNo + 1 == AMDGPU::getNamedOperandIdx(MI->getOpcode(),
|
|
|
|
AMDGPU::OpName::src1))
|
|
|
|
printDefaultVccOperand(OpNo, STI, O);
|
|
|
|
break;
|
|
|
|
}
|
2016-06-10 17:57:59 +08:00
|
|
|
}
|
|
|
|
|
2019-06-13 02:02:41 +08:00
|
|
|
void AMDGPUInstPrinter::printDPP8(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2020-11-25 19:51:23 +08:00
|
|
|
if (!AMDGPU::isGFX10Plus(STI))
|
2019-06-13 02:02:41 +08:00
|
|
|
llvm_unreachable("dpp8 is not supported on ASICs earlier than GFX10");
|
|
|
|
|
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "dpp8:[" << formatDec(Imm & 0x7);
|
2019-06-13 02:02:41 +08:00
|
|
|
for (size_t i = 1; i < 8; ++i) {
|
|
|
|
O << ',' << formatDec((Imm >> (3 * i)) & 0x7);
|
|
|
|
}
|
|
|
|
O << ']';
|
|
|
|
}
|
|
|
|
|
2016-04-29 17:02:30 +08:00
|
|
|
void AMDGPUInstPrinter::printDPPCtrl(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2018-05-09 00:53:02 +08:00
|
|
|
using namespace AMDGPU::DPP;
|
|
|
|
|
2016-03-09 20:29:31 +08:00
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
2021-02-18 05:37:46 +08:00
|
|
|
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
|
|
|
|
int Src0Idx = AMDGPU::getNamedOperandIdx(MI->getOpcode(),
|
|
|
|
AMDGPU::OpName::src0);
|
|
|
|
|
2021-05-06 02:26:07 +08:00
|
|
|
if (Src0Idx >= 0 &&
|
|
|
|
Desc.OpInfo[Src0Idx].RegClass == AMDGPU::VReg_64RegClassID &&
|
2021-02-18 05:37:46 +08:00
|
|
|
!AMDGPU::isLegal64BitDPPControl(Imm)) {
|
|
|
|
O << " /* 64 bit dpp only supports row_newbcast */";
|
|
|
|
return;
|
|
|
|
} else if (Imm <= DppCtrl::QUAD_PERM_LAST) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "quad_perm:[";
|
2016-07-06 06:06:56 +08:00
|
|
|
O << formatDec(Imm & 0x3) << ',';
|
|
|
|
O << formatDec((Imm & 0xc) >> 2) << ',';
|
|
|
|
O << formatDec((Imm & 0x30) >> 4) << ',';
|
|
|
|
O << formatDec((Imm & 0xc0) >> 6) << ']';
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if ((Imm >= DppCtrl::ROW_SHL_FIRST) &&
|
|
|
|
(Imm <= DppCtrl::ROW_SHL_LAST)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "row_shl:";
|
2016-03-09 20:29:31 +08:00
|
|
|
printU4ImmDecOperand(MI, OpNo, O);
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if ((Imm >= DppCtrl::ROW_SHR_FIRST) &&
|
|
|
|
(Imm <= DppCtrl::ROW_SHR_LAST)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "row_shr:";
|
2016-03-09 20:29:31 +08:00
|
|
|
printU4ImmDecOperand(MI, OpNo, O);
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if ((Imm >= DppCtrl::ROW_ROR_FIRST) &&
|
|
|
|
(Imm <= DppCtrl::ROW_ROR_LAST)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "row_ror:";
|
2016-03-09 20:29:31 +08:00
|
|
|
printU4ImmDecOperand(MI, OpNo, O);
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if (Imm == DppCtrl::WAVE_SHL1) {
|
2020-11-25 19:51:23 +08:00
|
|
|
if (AMDGPU::isGFX10Plus(STI)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "/* wave_shl is not supported starting from GFX10 */";
|
2019-06-13 02:02:41 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "wave_shl:1";
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if (Imm == DppCtrl::WAVE_ROL1) {
|
2020-11-25 19:51:23 +08:00
|
|
|
if (AMDGPU::isGFX10Plus(STI)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "/* wave_rol is not supported starting from GFX10 */";
|
2019-06-13 02:02:41 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "wave_rol:1";
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if (Imm == DppCtrl::WAVE_SHR1) {
|
2020-11-25 19:51:23 +08:00
|
|
|
if (AMDGPU::isGFX10Plus(STI)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "/* wave_shr is not supported starting from GFX10 */";
|
2019-06-13 02:02:41 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "wave_shr:1";
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if (Imm == DppCtrl::WAVE_ROR1) {
|
2020-11-25 19:51:23 +08:00
|
|
|
if (AMDGPU::isGFX10Plus(STI)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "/* wave_ror is not supported starting from GFX10 */";
|
2019-06-13 02:02:41 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "wave_ror:1";
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if (Imm == DppCtrl::ROW_MIRROR) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "row_mirror";
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if (Imm == DppCtrl::ROW_HALF_MIRROR) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "row_half_mirror";
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if (Imm == DppCtrl::BCAST15) {
|
2020-11-25 19:51:23 +08:00
|
|
|
if (AMDGPU::isGFX10Plus(STI)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "/* row_bcast is not supported starting from GFX10 */";
|
2019-06-13 02:02:41 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "row_bcast:15";
|
2018-05-09 00:53:02 +08:00
|
|
|
} else if (Imm == DppCtrl::BCAST31) {
|
2020-11-25 19:51:23 +08:00
|
|
|
if (AMDGPU::isGFX10Plus(STI)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "/* row_bcast is not supported starting from GFX10 */";
|
2019-06-13 02:02:41 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "row_bcast:31";
|
2019-06-13 02:02:41 +08:00
|
|
|
} else if ((Imm >= DppCtrl::ROW_SHARE_FIRST) &&
|
|
|
|
(Imm <= DppCtrl::ROW_SHARE_LAST)) {
|
2021-02-18 05:37:46 +08:00
|
|
|
if (AMDGPU::isGFX90A(STI)) {
|
2021-04-12 18:30:29 +08:00
|
|
|
O << "row_newbcast:";
|
2021-02-18 05:37:46 +08:00
|
|
|
} else if (AMDGPU::isGFX10Plus(STI)) {
|
|
|
|
O << "row_share:";
|
|
|
|
} else {
|
|
|
|
O << " /* row_newbcast/row_share is not supported on ASICs earlier "
|
|
|
|
"than GFX90A/GFX10 */";
|
2019-06-13 02:02:41 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
printU4ImmDecOperand(MI, OpNo, O);
|
|
|
|
} else if ((Imm >= DppCtrl::ROW_XMASK_FIRST) &&
|
|
|
|
(Imm <= DppCtrl::ROW_XMASK_LAST)) {
|
2020-11-25 19:51:23 +08:00
|
|
|
if (!AMDGPU::isGFX10Plus(STI)) {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "/* row_xmask is not supported on ASICs earlier than GFX10 */";
|
2019-06-13 02:02:41 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
O << "row_xmask:";
|
|
|
|
printU4ImmDecOperand(MI, OpNo, O);
|
2016-03-09 20:29:31 +08:00
|
|
|
} else {
|
2020-10-29 00:59:29 +08:00
|
|
|
O << "/* Invalid dpp_ctrl value */";
|
2016-03-09 20:29:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 17:02:30 +08:00
|
|
|
void AMDGPUInstPrinter::printRowMask(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2016-03-09 20:29:31 +08:00
|
|
|
O << " row_mask:";
|
2016-10-13 02:00:51 +08:00
|
|
|
printU4ImmOperand(MI, OpNo, STI, O);
|
2016-03-09 20:29:31 +08:00
|
|
|
}
|
|
|
|
|
2016-04-29 17:02:30 +08:00
|
|
|
void AMDGPUInstPrinter::printBankMask(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2016-03-09 20:29:31 +08:00
|
|
|
O << " bank_mask:";
|
2016-10-13 02:00:51 +08:00
|
|
|
printU4ImmOperand(MI, OpNo, STI, O);
|
2016-03-09 20:29:31 +08:00
|
|
|
}
|
|
|
|
|
2016-04-29 17:02:30 +08:00
|
|
|
void AMDGPUInstPrinter::printBoundCtrl(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2016-03-09 20:29:31 +08:00
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (Imm) {
|
2021-02-22 19:59:40 +08:00
|
|
|
O << " bound_ctrl:1";
|
2016-03-09 20:29:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-13 02:02:41 +08:00
|
|
|
void AMDGPUInstPrinter::printFI(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
using namespace llvm::AMDGPU::DPP;
|
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (Imm == DPP_FI_1 || Imm == DPP8_FI_1) {
|
|
|
|
O << " fi:1";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-26 21:33:56 +08:00
|
|
|
void AMDGPUInstPrinter::printSDWASel(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O) {
|
2016-10-07 22:46:06 +08:00
|
|
|
using namespace llvm::AMDGPU::SDWA;
|
|
|
|
|
2016-04-26 21:33:56 +08:00
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
switch (Imm) {
|
2016-10-07 22:46:06 +08:00
|
|
|
case SdwaSel::BYTE_0: O << "BYTE_0"; break;
|
|
|
|
case SdwaSel::BYTE_1: O << "BYTE_1"; break;
|
|
|
|
case SdwaSel::BYTE_2: O << "BYTE_2"; break;
|
|
|
|
case SdwaSel::BYTE_3: O << "BYTE_3"; break;
|
|
|
|
case SdwaSel::WORD_0: O << "WORD_0"; break;
|
|
|
|
case SdwaSel::WORD_1: O << "WORD_1"; break;
|
|
|
|
case SdwaSel::DWORD: O << "DWORD"; break;
|
2016-04-26 21:33:56 +08:00
|
|
|
default: llvm_unreachable("Invalid SDWA data select operand");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printSDWADstSel(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2016-04-26 21:33:56 +08:00
|
|
|
raw_ostream &O) {
|
|
|
|
O << "dst_sel:";
|
|
|
|
printSDWASel(MI, OpNo, O);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printSDWASrc0Sel(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2016-04-26 21:33:56 +08:00
|
|
|
raw_ostream &O) {
|
|
|
|
O << "src0_sel:";
|
|
|
|
printSDWASel(MI, OpNo, O);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printSDWASrc1Sel(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2016-04-26 21:33:56 +08:00
|
|
|
raw_ostream &O) {
|
|
|
|
O << "src1_sel:";
|
|
|
|
printSDWASel(MI, OpNo, O);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printSDWADstUnused(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2016-04-26 21:33:56 +08:00
|
|
|
raw_ostream &O) {
|
2016-10-07 22:46:06 +08:00
|
|
|
using namespace llvm::AMDGPU::SDWA;
|
|
|
|
|
2016-04-26 21:33:56 +08:00
|
|
|
O << "dst_unused:";
|
|
|
|
unsigned Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
switch (Imm) {
|
2016-10-07 22:46:06 +08:00
|
|
|
case DstUnused::UNUSED_PAD: O << "UNUSED_PAD"; break;
|
|
|
|
case DstUnused::UNUSED_SEXT: O << "UNUSED_SEXT"; break;
|
|
|
|
case DstUnused::UNUSED_PRESERVE: O << "UNUSED_PRESERVE"; break;
|
2016-04-26 21:33:56 +08:00
|
|
|
default: llvm_unreachable("Invalid SDWA dest_unused operand");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-06 04:31:49 +08:00
|
|
|
void AMDGPUInstPrinter::printExpSrcN(const MCInst *MI, unsigned OpNo,
|
2021-01-19 18:26:19 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O,
|
|
|
|
unsigned N) {
|
2017-02-23 04:37:12 +08:00
|
|
|
unsigned Opc = MI->getOpcode();
|
|
|
|
int EnIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::en);
|
2016-12-06 04:31:49 +08:00
|
|
|
unsigned En = MI->getOperand(EnIdx).getImm();
|
|
|
|
|
2017-02-23 04:37:12 +08:00
|
|
|
int ComprIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::compr);
|
|
|
|
|
|
|
|
// If compr is set, print as src0, src0, src1, src1
|
2021-01-19 18:26:19 +08:00
|
|
|
if (MI->getOperand(ComprIdx).getImm())
|
|
|
|
OpNo = OpNo - N + N / 2;
|
2016-12-06 04:31:49 +08:00
|
|
|
|
|
|
|
if (En & (1 << N))
|
|
|
|
printRegOperand(MI->getOperand(OpNo).getReg(), O, MRI);
|
|
|
|
else
|
|
|
|
O << "off";
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printExpSrc0(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2021-01-19 18:26:19 +08:00
|
|
|
printExpSrcN(MI, OpNo, STI, O, 0);
|
2016-12-06 04:31:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printExpSrc1(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2021-01-19 18:26:19 +08:00
|
|
|
printExpSrcN(MI, OpNo, STI, O, 1);
|
2016-12-06 04:31:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printExpSrc2(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2021-01-19 18:26:19 +08:00
|
|
|
printExpSrcN(MI, OpNo, STI, O, 2);
|
2016-12-06 04:31:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printExpSrc3(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2021-01-19 18:26:19 +08:00
|
|
|
printExpSrcN(MI, OpNo, STI, O, 3);
|
2016-12-06 04:31:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printExpTgt(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2021-01-26 19:52:24 +08:00
|
|
|
using namespace llvm::AMDGPU::Exp;
|
|
|
|
|
2016-12-06 04:31:49 +08:00
|
|
|
// This is really a 6 bit field.
|
2021-01-26 19:52:24 +08:00
|
|
|
unsigned Id = MI->getOperand(OpNo).getImm() & ((1 << 6) - 1);
|
|
|
|
|
|
|
|
int Index;
|
|
|
|
StringRef TgtName;
|
|
|
|
if (getTgtName(Id, TgtName, Index) && isSupportedTgtId(Id, STI)) {
|
|
|
|
O << ' ' << TgtName;
|
|
|
|
if (Index >= 0)
|
|
|
|
O << Index;
|
|
|
|
} else {
|
|
|
|
O << " invalid_target_" << Id;
|
2016-12-06 04:31:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:54:11 +08:00
|
|
|
static bool allOpsDefaultValue(const int* Ops, int NumOps, int Mod,
|
2017-11-17 23:15:40 +08:00
|
|
|
bool IsPacked, bool HasDstSel) {
|
|
|
|
int DefaultValue = IsPacked && (Mod == SISrcMods::OP_SEL_1);
|
2017-02-28 02:49:11 +08:00
|
|
|
|
|
|
|
for (int I = 0; I < NumOps; ++I) {
|
|
|
|
if (!!(Ops[I] & Mod) != DefaultValue)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:54:11 +08:00
|
|
|
if (HasDstSel && (Ops[0] & SISrcMods::DST_OP_SEL) != 0)
|
|
|
|
return false;
|
|
|
|
|
2017-02-28 02:49:11 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:54:11 +08:00
|
|
|
void AMDGPUInstPrinter::printPackedModifier(const MCInst *MI,
|
|
|
|
StringRef Name,
|
|
|
|
unsigned Mod,
|
|
|
|
raw_ostream &O) {
|
2017-02-28 02:49:11 +08:00
|
|
|
unsigned Opc = MI->getOpcode();
|
|
|
|
int NumOps = 0;
|
|
|
|
int Ops[3];
|
|
|
|
|
|
|
|
for (int OpName : { AMDGPU::OpName::src0_modifiers,
|
|
|
|
AMDGPU::OpName::src1_modifiers,
|
|
|
|
AMDGPU::OpName::src2_modifiers }) {
|
|
|
|
int Idx = AMDGPU::getNamedOperandIdx(Opc, OpName);
|
|
|
|
if (Idx == -1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
Ops[NumOps++] = MI->getOperand(Idx).getImm();
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:54:11 +08:00
|
|
|
const bool HasDstSel =
|
|
|
|
NumOps > 0 &&
|
|
|
|
Mod == SISrcMods::OP_SEL_0 &&
|
|
|
|
MII.get(MI->getOpcode()).TSFlags & SIInstrFlags::VOP3_OPSEL;
|
|
|
|
|
2017-11-17 23:15:40 +08:00
|
|
|
const bool IsPacked =
|
|
|
|
MII.get(MI->getOpcode()).TSFlags & SIInstrFlags::IsPacked;
|
|
|
|
|
|
|
|
if (allOpsDefaultValue(Ops, NumOps, Mod, IsPacked, HasDstSel))
|
2017-02-28 02:49:11 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
O << Name;
|
|
|
|
for (int I = 0; I < NumOps; ++I) {
|
|
|
|
if (I != 0)
|
|
|
|
O << ',';
|
|
|
|
|
|
|
|
O << !!(Ops[I] & Mod);
|
|
|
|
}
|
|
|
|
|
2017-07-21 21:54:11 +08:00
|
|
|
if (HasDstSel) {
|
|
|
|
O << ',' << !!(Ops[0] & SISrcMods::DST_OP_SEL);
|
|
|
|
}
|
|
|
|
|
2017-02-28 02:49:11 +08:00
|
|
|
O << ']';
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printOpSel(const MCInst *MI, unsigned,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2019-06-13 01:52:51 +08:00
|
|
|
unsigned Opc = MI->getOpcode();
|
|
|
|
if (Opc == AMDGPU::V_PERMLANE16_B32_gfx10 ||
|
|
|
|
Opc == AMDGPU::V_PERMLANEX16_B32_gfx10) {
|
|
|
|
auto FIN = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0_modifiers);
|
|
|
|
auto BCN = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1_modifiers);
|
|
|
|
unsigned FI = !!(MI->getOperand(FIN).getImm() & SISrcMods::OP_SEL_0);
|
|
|
|
unsigned BC = !!(MI->getOperand(BCN).getImm() & SISrcMods::OP_SEL_0);
|
|
|
|
if (FI || BC)
|
|
|
|
O << " op_sel:[" << FI << ',' << BC << ']';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-28 02:49:11 +08:00
|
|
|
printPackedModifier(MI, " op_sel:[", SISrcMods::OP_SEL_0, O);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printOpSelHi(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
printPackedModifier(MI, " op_sel_hi:[", SISrcMods::OP_SEL_1, O);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printNegLo(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
printPackedModifier(MI, " neg_lo:[", SISrcMods::NEG, O);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printNegHi(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
printPackedModifier(MI, " neg_hi:[", SISrcMods::NEG_HI, O);
|
|
|
|
}
|
|
|
|
|
2016-12-06 04:31:49 +08:00
|
|
|
void AMDGPUInstPrinter::printInterpSlot(const MCInst *MI, unsigned OpNum,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2013-02-15 03:03:25 +08:00
|
|
|
raw_ostream &O) {
|
2016-12-06 04:31:49 +08:00
|
|
|
unsigned Imm = MI->getOperand(OpNum).getImm();
|
2016-12-10 08:23:12 +08:00
|
|
|
switch (Imm) {
|
|
|
|
case 0:
|
|
|
|
O << "p10";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
O << "p20";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
O << "p0";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
O << "invalid_param_" << Imm;
|
2013-02-15 03:03:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-15 00:36:12 +08:00
|
|
|
void AMDGPUInstPrinter::printInterpAttr(const MCInst *MI, unsigned OpNum,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
unsigned Attr = MI->getOperand(OpNum).getImm();
|
|
|
|
O << "attr" << Attr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printInterpAttrChan(const MCInst *MI, unsigned OpNum,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
unsigned Chan = MI->getOperand(OpNum).getImm();
|
|
|
|
O << '.' << "xyzw"[Chan & 0x3];
|
|
|
|
}
|
|
|
|
|
2016-10-13 02:00:51 +08:00
|
|
|
void AMDGPUInstPrinter::printVGPRIndexMode(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2019-02-27 21:12:12 +08:00
|
|
|
using namespace llvm::AMDGPU::VGPRIndexMode;
|
2016-10-13 02:00:51 +08:00
|
|
|
unsigned Val = MI->getOperand(OpNo).getImm();
|
|
|
|
|
2019-02-27 21:12:12 +08:00
|
|
|
if ((Val & ~ENABLE_MASK) != 0) {
|
2020-10-29 17:39:28 +08:00
|
|
|
O << formatHex(static_cast<uint64_t>(Val));
|
2019-02-27 21:12:12 +08:00
|
|
|
} else {
|
2020-10-29 17:39:28 +08:00
|
|
|
O << "gpr_idx(";
|
2019-02-27 21:12:12 +08:00
|
|
|
bool NeedComma = false;
|
|
|
|
for (unsigned ModeId = ID_MIN; ModeId <= ID_MAX; ++ModeId) {
|
|
|
|
if (Val & (1 << ModeId)) {
|
|
|
|
if (NeedComma)
|
|
|
|
O << ',';
|
|
|
|
O << IdSymbolic[ModeId];
|
|
|
|
NeedComma = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
O << ')';
|
|
|
|
}
|
2016-10-13 02:00:51 +08:00
|
|
|
}
|
|
|
|
|
2012-12-12 05:25:42 +08:00
|
|
|
void AMDGPUInstPrinter::printMemOperand(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2012-12-12 05:25:42 +08:00
|
|
|
raw_ostream &O) {
|
2016-09-27 22:42:48 +08:00
|
|
|
printOperand(MI, OpNo, STI, O);
|
2012-12-12 05:25:42 +08:00
|
|
|
O << ", ";
|
2016-09-27 22:42:48 +08:00
|
|
|
printOperand(MI, OpNo + 1, STI, O);
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printIfSet(const MCInst *MI, unsigned OpNo,
|
2013-05-03 05:52:30 +08:00
|
|
|
raw_ostream &O, StringRef Asm,
|
|
|
|
StringRef Default) {
|
2012-12-12 05:25:42 +08:00
|
|
|
const MCOperand &Op = MI->getOperand(OpNo);
|
|
|
|
assert(Op.isImm());
|
|
|
|
if (Op.getImm() == 1) {
|
|
|
|
O << Asm;
|
2013-05-03 05:52:30 +08:00
|
|
|
} else {
|
|
|
|
O << Default;
|
2012-12-12 05:25:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-06 06:06:56 +08:00
|
|
|
void AMDGPUInstPrinter::printIfSet(const MCInst *MI, unsigned OpNo,
|
|
|
|
raw_ostream &O, char Asm) {
|
|
|
|
const MCOperand &Op = MI->getOperand(OpNo);
|
|
|
|
assert(Op.isImm());
|
|
|
|
if (Op.getImm() == 1)
|
|
|
|
O << Asm;
|
|
|
|
}
|
|
|
|
|
2017-08-07 21:14:12 +08:00
|
|
|
void AMDGPUInstPrinter::printHigh(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2020-10-26 22:03:35 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "high");
|
2017-08-07 21:14:12 +08:00
|
|
|
}
|
|
|
|
|
2014-10-01 03:49:48 +08:00
|
|
|
void AMDGPUInstPrinter::printClampSI(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2014-10-01 03:49:48 +08:00
|
|
|
raw_ostream &O) {
|
2020-10-26 22:03:35 +08:00
|
|
|
printNamedBit(MI, OpNo, O, "clamp");
|
2014-10-01 03:49:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printOModSI(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
2014-10-01 03:49:48 +08:00
|
|
|
int Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (Imm == SIOutMods::MUL2)
|
|
|
|
O << " mul:2";
|
|
|
|
else if (Imm == SIOutMods::MUL4)
|
|
|
|
O << " mul:4";
|
|
|
|
else if (Imm == SIOutMods::DIV2)
|
|
|
|
O << " div:2";
|
|
|
|
}
|
|
|
|
|
2014-01-27 15:20:44 +08:00
|
|
|
void AMDGPUInstPrinter::printSendMsg(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2014-01-27 15:20:44 +08:00
|
|
|
raw_ostream &O) {
|
2016-05-07 01:48:48 +08:00
|
|
|
using namespace llvm::AMDGPU::SendMsg;
|
|
|
|
|
2019-06-28 22:14:02 +08:00
|
|
|
const unsigned Imm16 = MI->getOperand(OpNo).getImm();
|
|
|
|
|
|
|
|
uint16_t MsgId;
|
|
|
|
uint16_t OpId;
|
|
|
|
uint16_t StreamId;
|
|
|
|
decodeMsg(Imm16, MsgId, OpId, StreamId);
|
|
|
|
|
|
|
|
if (isValidMsgId(MsgId, STI) &&
|
2021-01-26 01:40:56 +08:00
|
|
|
isValidMsgOp(MsgId, OpId, STI) &&
|
|
|
|
isValidMsgStream(MsgId, OpId, StreamId, STI)) {
|
2019-06-28 22:14:02 +08:00
|
|
|
O << "sendmsg(" << getMsgName(MsgId);
|
|
|
|
if (msgRequiresOp(MsgId)) {
|
|
|
|
O << ", " << getMsgOpName(MsgId, OpId);
|
|
|
|
if (msgSupportsStream(MsgId, OpId)) {
|
|
|
|
O << ", " << StreamId;
|
|
|
|
}
|
2016-05-07 01:48:48 +08:00
|
|
|
}
|
2019-06-28 22:14:02 +08:00
|
|
|
O << ')';
|
|
|
|
} else if (encodeMsg(MsgId, OpId, StreamId) == Imm16) {
|
|
|
|
O << "sendmsg(" << MsgId << ", " << OpId << ", " << StreamId << ')';
|
|
|
|
} else {
|
|
|
|
O << Imm16; // Unknown imm16 code.
|
|
|
|
}
|
2014-01-27 15:20:44 +08:00
|
|
|
}
|
|
|
|
|
2017-06-01 00:26:47 +08:00
|
|
|
static void printSwizzleBitmask(const uint16_t AndMask,
|
|
|
|
const uint16_t OrMask,
|
|
|
|
const uint16_t XorMask,
|
|
|
|
raw_ostream &O) {
|
|
|
|
using namespace llvm::AMDGPU::Swizzle;
|
|
|
|
|
|
|
|
uint16_t Probe0 = ((0 & AndMask) | OrMask) ^ XorMask;
|
|
|
|
uint16_t Probe1 = ((BITMASK_MASK & AndMask) | OrMask) ^ XorMask;
|
|
|
|
|
|
|
|
O << "\"";
|
|
|
|
|
|
|
|
for (unsigned Mask = 1 << (BITMASK_WIDTH - 1); Mask > 0; Mask >>= 1) {
|
|
|
|
uint16_t p0 = Probe0 & Mask;
|
|
|
|
uint16_t p1 = Probe1 & Mask;
|
|
|
|
|
|
|
|
if (p0 == p1) {
|
|
|
|
if (p0 == 0) {
|
|
|
|
O << "0";
|
|
|
|
} else {
|
|
|
|
O << "1";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (p0 == 0) {
|
|
|
|
O << "p";
|
|
|
|
} else {
|
|
|
|
O << "i";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
O << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
void AMDGPUInstPrinter::printSwizzle(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
using namespace llvm::AMDGPU::Swizzle;
|
|
|
|
|
|
|
|
uint16_t Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (Imm == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
O << " offset:";
|
|
|
|
|
|
|
|
if ((Imm & QUAD_PERM_ENC_MASK) == QUAD_PERM_ENC) {
|
|
|
|
|
|
|
|
O << "swizzle(" << IdSymbolic[ID_QUAD_PERM];
|
2019-03-12 00:49:32 +08:00
|
|
|
for (unsigned I = 0; I < LANE_NUM; ++I) {
|
2017-06-01 00:26:47 +08:00
|
|
|
O << ",";
|
|
|
|
O << formatDec(Imm & LANE_MASK);
|
|
|
|
Imm >>= LANE_SHIFT;
|
|
|
|
}
|
|
|
|
O << ")";
|
|
|
|
|
|
|
|
} else if ((Imm & BITMASK_PERM_ENC_MASK) == BITMASK_PERM_ENC) {
|
|
|
|
|
|
|
|
uint16_t AndMask = (Imm >> BITMASK_AND_SHIFT) & BITMASK_MASK;
|
|
|
|
uint16_t OrMask = (Imm >> BITMASK_OR_SHIFT) & BITMASK_MASK;
|
|
|
|
uint16_t XorMask = (Imm >> BITMASK_XOR_SHIFT) & BITMASK_MASK;
|
|
|
|
|
|
|
|
if (AndMask == BITMASK_MAX &&
|
|
|
|
OrMask == 0 &&
|
|
|
|
countPopulation(XorMask) == 1) {
|
|
|
|
|
|
|
|
O << "swizzle(" << IdSymbolic[ID_SWAP];
|
|
|
|
O << ",";
|
|
|
|
O << formatDec(XorMask);
|
|
|
|
O << ")";
|
|
|
|
|
|
|
|
} else if (AndMask == BITMASK_MAX &&
|
|
|
|
OrMask == 0 && XorMask > 0 &&
|
|
|
|
isPowerOf2_64(XorMask + 1)) {
|
|
|
|
|
|
|
|
O << "swizzle(" << IdSymbolic[ID_REVERSE];
|
|
|
|
O << ",";
|
|
|
|
O << formatDec(XorMask + 1);
|
|
|
|
O << ")";
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
uint16_t GroupSize = BITMASK_MAX - AndMask + 1;
|
|
|
|
if (GroupSize > 1 &&
|
|
|
|
isPowerOf2_64(GroupSize) &&
|
|
|
|
OrMask < GroupSize &&
|
|
|
|
XorMask == 0) {
|
|
|
|
|
|
|
|
O << "swizzle(" << IdSymbolic[ID_BROADCAST];
|
|
|
|
O << ",";
|
|
|
|
O << formatDec(GroupSize);
|
|
|
|
O << ",";
|
|
|
|
O << formatDec(OrMask);
|
|
|
|
O << ")";
|
|
|
|
|
|
|
|
} else {
|
|
|
|
O << "swizzle(" << IdSymbolic[ID_BITMASK_PERM];
|
|
|
|
O << ",";
|
|
|
|
printSwizzleBitmask(AndMask, OrMask, XorMask, O);
|
|
|
|
O << ")";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printU16ImmDecOperand(MI, OpNo, O);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-14 01:56:28 +08:00
|
|
|
void AMDGPUInstPrinter::printWaitFlag(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI,
|
2013-10-14 01:56:28 +08:00
|
|
|
raw_ostream &O) {
|
2018-09-13 02:50:47 +08:00
|
|
|
AMDGPU::IsaVersion ISA = AMDGPU::getIsaVersion(STI.getCPU());
|
2016-10-01 01:01:40 +08:00
|
|
|
|
2013-10-14 01:56:28 +08:00
|
|
|
unsigned SImm16 = MI->getOperand(OpNo).getImm();
|
2016-10-12 02:58:22 +08:00
|
|
|
unsigned Vmcnt, Expcnt, Lgkmcnt;
|
2017-02-08 22:05:23 +08:00
|
|
|
decodeWaitcnt(ISA, SImm16, Vmcnt, Expcnt, Lgkmcnt);
|
2014-09-26 09:09:46 +08:00
|
|
|
|
|
|
|
bool NeedSpace = false;
|
|
|
|
|
2017-02-08 22:05:23 +08:00
|
|
|
if (Vmcnt != getVmcntBitMask(ISA)) {
|
2014-09-26 09:09:46 +08:00
|
|
|
O << "vmcnt(" << Vmcnt << ')';
|
|
|
|
NeedSpace = true;
|
|
|
|
}
|
|
|
|
|
2017-02-08 22:05:23 +08:00
|
|
|
if (Expcnt != getExpcntBitMask(ISA)) {
|
2014-09-26 09:09:46 +08:00
|
|
|
if (NeedSpace)
|
|
|
|
O << ' ';
|
|
|
|
O << "expcnt(" << Expcnt << ')';
|
|
|
|
NeedSpace = true;
|
|
|
|
}
|
|
|
|
|
2017-02-08 22:05:23 +08:00
|
|
|
if (Lgkmcnt != getLgkmcntBitMask(ISA)) {
|
2014-09-26 09:09:46 +08:00
|
|
|
if (NeedSpace)
|
|
|
|
O << ' ';
|
2014-09-22 01:27:28 +08:00
|
|
|
O << "lgkmcnt(" << Lgkmcnt << ')';
|
2014-09-26 09:09:46 +08:00
|
|
|
}
|
2013-10-14 01:56:28 +08:00
|
|
|
}
|
|
|
|
|
2016-04-25 22:13:51 +08:00
|
|
|
void AMDGPUInstPrinter::printHwreg(const MCInst *MI, unsigned OpNo,
|
2016-09-27 22:42:48 +08:00
|
|
|
const MCSubtargetInfo &STI, raw_ostream &O) {
|
2019-06-13 20:46:37 +08:00
|
|
|
unsigned Id;
|
|
|
|
unsigned Offset;
|
|
|
|
unsigned Width;
|
2016-05-27 01:00:33 +08:00
|
|
|
|
2019-06-13 20:46:37 +08:00
|
|
|
using namespace llvm::AMDGPU::Hwreg;
|
|
|
|
unsigned Val = MI->getOperand(OpNo).getImm();
|
|
|
|
decodeHwreg(Val, Id, Offset, Width);
|
|
|
|
StringRef HwRegName = getHwreg(Id, STI);
|
2016-04-25 22:13:51 +08:00
|
|
|
|
2016-04-27 23:17:03 +08:00
|
|
|
O << "hwreg(";
|
2019-06-13 20:46:37 +08:00
|
|
|
if (!HwRegName.empty()) {
|
|
|
|
O << HwRegName;
|
2016-05-27 01:00:33 +08:00
|
|
|
} else {
|
|
|
|
O << Id;
|
|
|
|
}
|
2019-06-13 20:46:37 +08:00
|
|
|
if (Width != WIDTH_DEFAULT_ || Offset != OFFSET_DEFAULT_) {
|
2016-04-27 23:17:03 +08:00
|
|
|
O << ", " << Offset << ", " << Width;
|
2016-04-25 22:13:51 +08:00
|
|
|
}
|
2016-04-27 23:17:03 +08:00
|
|
|
O << ')';
|
2016-04-25 22:13:51 +08:00
|
|
|
}
|
|
|
|
|
[AMDGPU] Add support for immediate operand for S_ENDPGM
Summary:
Add support for immediate operand in S_ENDPGM
Change-Id: I0c56a076a10980f719fb2a8f16407e9c301013f6
Reviewers: alexshap
Subscribers: qcolombet, arsenm, kzhuravl, jvesely, wdng, nhaehnle, yaxunl, tpr, t-tye, eraman, arphaman, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59213
llvm-svn: 355902
2019-03-12 17:52:58 +08:00
|
|
|
void AMDGPUInstPrinter::printEndpgm(const MCInst *MI, unsigned OpNo,
|
|
|
|
const MCSubtargetInfo &STI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
uint16_t Imm = MI->getOperand(OpNo).getImm();
|
|
|
|
if (Imm == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-14 21:26:29 +08:00
|
|
|
O << ' ' << formatDec(Imm);
|
[AMDGPU] Add support for immediate operand for S_ENDPGM
Summary:
Add support for immediate operand in S_ENDPGM
Change-Id: I0c56a076a10980f719fb2a8f16407e9c301013f6
Reviewers: alexshap
Subscribers: qcolombet, arsenm, kzhuravl, jvesely, wdng, nhaehnle, yaxunl, tpr, t-tye, eraman, arphaman, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59213
llvm-svn: 355902
2019-03-12 17:52:58 +08:00
|
|
|
}
|
|
|
|
|
2012-12-12 05:25:42 +08:00
|
|
|
#include "AMDGPUGenAsmWriter.inc"
|