Skip to content

Commit

Permalink
[AMDGPU] Assembler: Support DPP instructions.
Browse files Browse the repository at this point in the history
Supprot DPP syntax as used in SP3 (except several operands syntax).
Added dpp-specific operands in td-files.
Added DPP flag to TSFlags to determine if instruction is dpp in InstPrinter.
Support for VOP2 DPP instructions in td-files.
Some tests for DPP instructions.

ToDo:
  - VOP2bInst:
    - vcc is considered as operand
    - AsmMatcher doesn't apply mnemonic aliases when parsing operands
  - v_mac_f32
  - v_nop
  - disable instructions with 64-bit operands
  - change dpp_ctrl assembler representation to conform sp3

Review: http://reviews.llvm.org/D17804

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263008 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
SamWot committed Mar 9, 2016
1 parent f9cb03f commit 6e4c55e
Show file tree
Hide file tree
Showing 11 changed files with 499 additions and 52 deletions.
6 changes: 3 additions & 3 deletions include/llvm/IR/IntrinsicsAMDGPU.td
Original file line number Diff line number Diff line change
Expand Up @@ -275,11 +275,11 @@ def int_amdgcn_buffer_wbinvl1_vol :
// VI Intrinsics
//===----------------------------------------------------------------------===//

// llvm.amdgcn.mov.dpp.i32 <src> <dpp_ctrl> <bound_ctrl> <bank_mask> <row_mask>
// llvm.amdgcn.mov.dpp.i32 <src> <dpp_ctrl> <row_mask> <bank_mask> <bound_ctrl>
def int_amdgcn_mov_dpp :
Intrinsic<[llvm_anyint_ty],
[LLVMMatchType<0>, llvm_i32_ty, llvm_i1_ty, llvm_i32_ty,
llvm_i32_ty], [IntrNoMem, IntrConvergent]>;
[LLVMMatchType<0>, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty,
llvm_i1_ty], [IntrNoMem, IntrConvergent]>;

def int_amdgcn_s_dcache_wb :
GCCBuiltin<"__builtin_amdgcn_s_dcache_wb">,
Expand Down
180 changes: 175 additions & 5 deletions lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ class AMDGPUOperand : public MCParsedAsmOperand {
ImmTyTFE,
ImmTyClamp,
ImmTyOMod,
ImmTyDppCtrl,
ImmTyDppRowMask,
ImmTyDppBankMask,
ImmTyDppBoundCtrl,
ImmTyDMask,
ImmTyUNorm,
ImmTyDA,
Expand Down Expand Up @@ -144,7 +148,8 @@ class AMDGPUOperand : public MCParsedAsmOperand {
bool defaultTokenHasSuffix() const {
StringRef Token(Tok.Data, Tok.Length);

return Token.endswith("_e32") || Token.endswith("_e64");
return Token.endswith("_e32") || Token.endswith("_e64") ||
Token.endswith("_dpp");
}

bool isToken() const override {
Expand Down Expand Up @@ -234,6 +239,18 @@ class AMDGPUOperand : public MCParsedAsmOperand {
bool isSLC() const { return isImmTy(ImmTySLC); }
bool isTFE() const { return isImmTy(ImmTyTFE); }

bool isBankMask() const {
return isImmTy(ImmTyDppBankMask);
}

bool isRowMask() const {
return isImmTy(ImmTyDppRowMask);
}

bool isBoundCtrl() const {
return isImmTy(ImmTyDppBoundCtrl);
}

void setModifiers(unsigned Mods) {
assert(isReg() || (isImm() && Imm.Modifiers == 0));
if (isReg())
Expand Down Expand Up @@ -391,6 +408,7 @@ class AMDGPUOperand : public MCParsedAsmOperand {
bool isMubufOffset() const;
bool isSMRDOffset() const;
bool isSMRDLiteralOffset() const;
bool isDPPCtrl() const;
};

class AMDGPUAsmParser : public MCTargetAsmParser {
Expand Down Expand Up @@ -438,7 +456,6 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
bool ParseSectionDirectiveHSADataGlobalProgram();
bool ParseSectionDirectiveHSARodataReadonlyAgent();

public:
public:
enum AMDGPUMatchResultTy {
Match_PreferE32 = FIRST_TARGET_MATCH_RESULT_TY
Expand Down Expand Up @@ -538,6 +555,12 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
void cvtMIMG(MCInst &Inst, const OperandVector &Operands);
void cvtMIMGAtomic(MCInst &Inst, const OperandVector &Operands);
OperandMatchResultTy parseVOP3OptionalOps(OperandVector &Operands);

OperandMatchResultTy parseDPPCtrlOps(OperandVector &Operands);
OperandMatchResultTy parseDPPOptionalOps(OperandVector &Operands);
void cvtDPP_mod(MCInst &Inst, const OperandVector &Operands);
void cvtDPP_nomod(MCInst &Inst, const OperandVector &Operands);
void cvtDPP(MCInst &Inst, const OperandVector &Operands, bool HasMods);
};

struct OptionalOperand {
Expand Down Expand Up @@ -1147,7 +1170,6 @@ bool AMDGPUAsmParser::ParseInstruction(ParseInstructionInfo &Info,
AMDGPUAsmParser::OperandMatchResultTy
AMDGPUAsmParser::parseIntWithPrefix(const char *Prefix, int64_t &Int,
int64_t Default) {

// We are at the end of the statement, and this is a default argument, so
// use a default value.
if (getLexer().is(AsmToken::EndOfStatement)) {
Expand Down Expand Up @@ -1227,13 +1249,15 @@ AMDGPUAsmParser::parseNamedBit(const char *Name, OperandVector &Operands,

typedef std::map<enum AMDGPUOperand::ImmTy, unsigned> OptionalImmIndexMap;

void addOptionalImmOperand(MCInst& Inst, const OperandVector& Operands, OptionalImmIndexMap& OptionalIdx, enum AMDGPUOperand::ImmTy ImmT) {
void addOptionalImmOperand(MCInst& Inst, const OperandVector& Operands,
OptionalImmIndexMap& OptionalIdx,
enum AMDGPUOperand::ImmTy ImmT, int64_t Default = 0) {
auto i = OptionalIdx.find(ImmT);
if (i != OptionalIdx.end()) {
unsigned Idx = i->second;
((AMDGPUOperand &)*Operands[Idx]).addImmOperands(Inst, 1);
} else {
Inst.addOperand(MCOperand::createImm(0));
Inst.addOperand(MCOperand::createImm(Default));
}
}

Expand Down Expand Up @@ -1896,6 +1920,152 @@ void AMDGPUAsmParser::cvtMIMGAtomic(MCInst &Inst, const OperandVector &Operands)
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySLC);
}

//===----------------------------------------------------------------------===//
// dpp
//===----------------------------------------------------------------------===//

bool AMDGPUOperand::isDPPCtrl() const {
bool result = isImm() && getImmTy() == ImmTyDppCtrl && isUInt<9>(getImm());
if (result) {
int64_t Imm = getImm();
return ((Imm >= 0x000) && (Imm <= 0x0ff)) ||
((Imm >= 0x101) && (Imm <= 0x10f)) ||
((Imm >= 0x111) && (Imm <= 0x11f)) ||
((Imm >= 0x121) && (Imm <= 0x12f)) ||
(Imm == 0x130) ||
(Imm == 0x134) ||
(Imm == 0x138) ||
(Imm == 0x13c) ||
(Imm == 0x140) ||
(Imm == 0x141) ||
(Imm == 0x142) ||
(Imm == 0x143);
}
return false;
}

AMDGPUAsmParser::OperandMatchResultTy
AMDGPUAsmParser::parseDPPCtrlOps(OperandVector &Operands) {
// ToDo: use same syntax as sp3 for dpp_ctrl
SMLoc S = Parser.getTok().getLoc();
StringRef Prefix;
int64_t Int;

switch(getLexer().getKind()) {
default: return MatchOperand_NoMatch;
case AsmToken::Identifier: {
Prefix = Parser.getTok().getString();

Parser.Lex();
if (getLexer().isNot(AsmToken::Colon))
return MatchOperand_ParseFail;

Parser.Lex();
if (getLexer().isNot(AsmToken::Integer))
return MatchOperand_ParseFail;

if (getParser().parseAbsoluteExpression(Int))
return MatchOperand_ParseFail;
break;
}
}

if (Prefix.equals("row_shl")) {
Int |= 0x100;
} else if (Prefix.equals("row_shr")) {
Int |= 0x110;
} else if (Prefix.equals("row_ror")) {
Int |= 0x120;
} else if (Prefix.equals("wave_shl")) {
Int = 0x130;
} else if (Prefix.equals("wave_rol")) {
Int = 0x134;
} else if (Prefix.equals("wave_shr")) {
Int = 0x138;
} else if (Prefix.equals("wave_ror")) {
Int = 0x13C;
} else if (Prefix.equals("row_mirror")) {
Int = 0x140;
} else if (Prefix.equals("row_half_mirror")) {
Int = 0x141;
} else if (Prefix.equals("row_bcast")) {
if (Int == 15) {
Int = 0x142;
} else if (Int == 31) {
Int = 0x143;
}
} else if (!Prefix.equals("quad_perm")) {
return MatchOperand_NoMatch;
}
Operands.push_back(AMDGPUOperand::CreateImm(Int, S,
AMDGPUOperand::ImmTyDppCtrl));
return MatchOperand_Success;
}

static const OptionalOperand DPPOptionalOps [] = {
{"row_mask", AMDGPUOperand::ImmTyDppRowMask, false, 0xf, nullptr},
{"bank_mask", AMDGPUOperand::ImmTyDppBankMask, false, 0xf, nullptr},
{"bound_ctrl", AMDGPUOperand::ImmTyDppBoundCtrl, false, -1, nullptr}
};

AMDGPUAsmParser::OperandMatchResultTy
AMDGPUAsmParser::parseDPPOptionalOps(OperandVector &Operands) {
SMLoc S = Parser.getTok().getLoc();
OperandMatchResultTy Res = parseOptionalOps(DPPOptionalOps, Operands);
// XXX - sp3 use syntax "bound_ctrl:0" to indicate that bound_ctrl bit was set
if (Res == MatchOperand_Success) {
AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands.back());
// If last operand was parsed as bound_ctrl we should replace it with correct value (1)
if (Op.isImmTy(AMDGPUOperand::ImmTyDppBoundCtrl)) {
Operands.pop_back();
Operands.push_back(
AMDGPUOperand::CreateImm(1, S, AMDGPUOperand::ImmTyDppBoundCtrl));
return MatchOperand_Success;
}
}
return Res;
}

void AMDGPUAsmParser::cvtDPP_mod(MCInst &Inst, const OperandVector &Operands) {
cvtDPP(Inst, Operands, true);
}

void AMDGPUAsmParser::cvtDPP_nomod(MCInst &Inst, const OperandVector &Operands) {
cvtDPP(Inst, Operands, false);
}

void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands,
bool HasMods) {
OptionalImmIndexMap OptionalIdx;

unsigned I = 1;
const MCInstrDesc &Desc = MII.get(Inst.getOpcode());
for (unsigned J = 0; J < Desc.getNumDefs(); ++J) {
((AMDGPUOperand &)*Operands[I++]).addRegOperands(Inst, 1);
}

for (unsigned E = Operands.size(); I != E; ++I) {
AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[I]);
// Add the register arguments
if (!HasMods && Op.isReg()) {
Op.addRegOperands(Inst, 1);
} else if (HasMods && Op.isRegOrImmWithInputMods()) {
Op.addRegOrImmWithInputModsOperands(Inst, 2);
} else if (Op.isDPPCtrl()) {
Op.addImmOperands(Inst, 1);
} else if (Op.isImm()) {
// Handle optional arguments
OptionalIdx[Op.getImmTy()] = I;
} else {
llvm_unreachable("Invalid operand type");
}
}

// ToDo: fix default values for row_mask and bank_mask
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppRowMask, 0xf);
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppBankMask, 0xf);
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppBoundCtrl);
}


/// Force static initialization.
Expand Down
69 changes: 69 additions & 0 deletions lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ void AMDGPUInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
printAnnotation(OS, Annot);
}

void AMDGPUInstPrinter::printU4ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
O << formatHex(MI->getOperand(OpNo).getImm() & 0xf);
}

void AMDGPUInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
O << formatHex(MI->getOperand(OpNo).getImm() & 0xff);
Expand All @@ -43,6 +48,11 @@ void AMDGPUInstPrinter::printU32ImmOperand(const MCInst *MI, unsigned OpNo,
O << formatHex(MI->getOperand(OpNo).getImm() & 0xffffffff);
}

void AMDGPUInstPrinter::printU4ImmDecOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
O << formatDec(MI->getOperand(OpNo).getImm() & 0xf);
}

void AMDGPUInstPrinter::printU8ImmDecOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
O << formatDec(MI->getOperand(OpNo).getImm() & 0xff);
Expand Down Expand Up @@ -251,6 +261,8 @@ void AMDGPUInstPrinter::printVOPDst(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (MII.get(MI->getOpcode()).TSFlags & SIInstrFlags::VOP3)
O << "_e64 ";
else if (MII.get(MI->getOpcode()).TSFlags & SIInstrFlags::DPP)
O << "_dpp ";
else
O << "_e32 ";

Expand Down Expand Up @@ -388,6 +400,63 @@ void AMDGPUInstPrinter::printOperandAndMods(const MCInst *MI, unsigned OpNo,
O << '|';
}


void AMDGPUInstPrinter::printDPPCtrlOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned Imm = MI->getOperand(OpNo).getImm();
if ((Imm >= 0x000) && (Imm <= 0x0ff)) {
O << " quad_perm:";
printU8ImmDecOperand(MI, OpNo, O);
} else if ((Imm >= 0x101) && (Imm <= 0x10f)) {
O << " row_shl:";
printU4ImmDecOperand(MI, OpNo, O);
} else if ((Imm >= 0x111) && (Imm <= 0x11f)) {
O << " row_shr:";
printU4ImmDecOperand(MI, OpNo, O);
} else if ((Imm >= 0x121) && (Imm <= 0x12f)) {
O << " row_ror:";
printU4ImmDecOperand(MI, OpNo, O);
} else if (Imm == 0x130) {
O << " wave_shl:1";
} else if (Imm == 0x134) {
O << " wave_rol:1";
} else if (Imm == 0x138) {
O << " wave_shr:1";
} else if (Imm == 0x13c) {
O << " wave_ror:1";
} else if (Imm == 0x140) {
O << " row_mirror:1";
} else if (Imm == 0x141) {
O << " row_half_mirror:1";
} else if (Imm == 0x142) {
O << " row_bcast:15";
} else if (Imm == 0x143) {
O << " row_bcast:31";
} else {
llvm_unreachable("Invalid dpp_ctrl value");
}
}

void AMDGPUInstPrinter::printRowMaskOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
O << " row_mask:";
printU4ImmOperand(MI, OpNo, O);
}

void AMDGPUInstPrinter::printBankMaskOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
O << " bank_mask:";
printU4ImmOperand(MI, OpNo, O);
}

void AMDGPUInstPrinter::printBoundCtrlOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned Imm = MI->getOperand(OpNo).getImm();
if (Imm) {
O << " bound_ctrl:0"; // XXX - this syntax is used in sp3
}
}

void AMDGPUInstPrinter::printInterpSlot(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {
unsigned Imm = MI->getOperand(OpNum).getImm();
Expand Down
6 changes: 6 additions & 0 deletions lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ class AMDGPUInstPrinter : public MCInstPrinter {
const MCRegisterInfo &MRI);

private:
void printU4ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU8ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU4ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU8ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU16ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU32ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
Expand All @@ -61,6 +63,10 @@ class AMDGPUInstPrinter : public MCInstPrinter {
void printImmediate64(uint64_t I, raw_ostream &O);
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printOperandAndMods(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printDPPCtrlOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printRowMaskOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printBankMaskOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printBoundCtrlOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
static void printInterpSlot(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printMemOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
static void printIfSet(const MCInst *MI, unsigned OpNo, raw_ostream &O,
Expand Down
Loading

0 comments on commit 6e4c55e

Please sign in to comment.