[AMDGPU] AsmParser: Support for sext() modifier in SDWA. Some code cleaning in AMDGPUOperand.

Summary:
sext() modifier is supported in SDWA instructions only for integer operands. Spec is unclear should integer operands support abs and neg modifiers with sext - for now they are not supported.
Renamed InputModsWithNoDefault to FloatInputMods. Added SextInputMods for operands that support sext() modifier.
Added AMDGPUOperand::Modifier struct to handle register and immediate modifiers.
Code cleaning in AMDGPUOperand class: organize method in groups (render-, predicate-methods...).

Reviewers: vpykhtin, artem.tamazov, tstellarAMD

Subscribers: arsenm, kzhuravl

Differential Revision: http://reviews.llvm.org/D20968

llvm-svn: 272384
This commit is contained in:
Sam Kolton 2016-06-10 09:57:59 +00:00
parent 9a6ac0909a
commit 4f6d8a41f5
6 changed files with 362 additions and 263 deletions

View File

@ -64,6 +64,43 @@ public:
typedef std::unique_ptr<AMDGPUOperand> Ptr;
struct Modifiers {
bool Abs;
bool Neg;
bool Sext;
bool hasFPModifiers() const { return Abs || Neg; }
bool hasIntModifiers() const { return Sext; }
bool hasModifiers() const { return hasFPModifiers() || hasIntModifiers(); }
int64_t getFPModifiersOperand() const {
int64_t Operand = 0;
Operand |= Abs ? SISrcMods::ABS : 0;
Operand |= Neg ? SISrcMods::NEG : 0;
return Operand;
}
int64_t getIntModifiersOperand() const {
int64_t Operand = 0;
Operand |= Sext ? SISrcMods::SEXT : 0;
return Operand;
}
int64_t getModifiersOperand() const {
assert(!(hasFPModifiers() && hasIntModifiers())
&& "fp and int modifiers should not be used simultaneously");
if (hasFPModifiers()) {
return getFPModifiersOperand();
} else if (hasIntModifiers()) {
return getIntModifiersOperand();
} else {
return 0;
}
}
friend raw_ostream &operator <<(raw_ostream &OS, AMDGPUOperand::Modifiers Mods);
};
enum ImmTy {
ImmTyNone,
ImmTyGDS,
@ -104,12 +141,12 @@ public:
bool IsFPImm;
ImmTy Type;
int64_t Val;
int Modifiers;
Modifiers Mods;
};
struct RegOp {
unsigned RegNo;
int Modifiers;
Modifiers Mods;
const MCRegisterInfo *TRI;
const MCSubtargetInfo *STI;
bool IsForcedVOP3;
@ -122,65 +159,6 @@ public:
const MCExpr *Expr;
};
void addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers = true) const {
if (Imm.Type == ImmTyNone && ApplyModifiers && Imm.Modifiers != 0) {
// Apply modifiers to immediate value
int64_t Val = Imm.Val;
bool Negate = Imm.Modifiers & 0x1;
bool Abs = Imm.Modifiers & 0x2;
if (Imm.IsFPImm) {
APFloat F(BitsToFloat(Val));
if (Abs) {
F.clearSign();
}
if (Negate) {
F.changeSign();
}
Val = F.bitcastToAPInt().getZExtValue();
} else {
Val = Abs ? std::abs(Val) : Val;
Val = Negate ? -Val : Val;
}
Inst.addOperand(MCOperand::createImm(Val));
} else {
Inst.addOperand(MCOperand::createImm(getImm()));
}
}
StringRef getToken() const {
return StringRef(Tok.Data, Tok.Length);
}
void addRegOperands(MCInst &Inst, unsigned N) const {
Inst.addOperand(MCOperand::createReg(AMDGPU::getMCReg(getReg(), *Reg.STI)));
}
void addRegOrImmOperands(MCInst &Inst, unsigned N) const {
if (isRegKind())
addRegOperands(Inst, N);
else
addImmOperands(Inst, N);
}
void addRegOrImmWithInputModsOperands(MCInst &Inst, unsigned N) const {
if (isRegKind()) {
Inst.addOperand(MCOperand::createImm(Reg.Modifiers));
addRegOperands(Inst, N);
} else {
Inst.addOperand(MCOperand::createImm(Imm.Modifiers));
addImmOperands(Inst, N, false);
}
}
void addSoppBrTargetOperands(MCInst &Inst, unsigned N) const {
if (isImm())
addImmOperands(Inst, N);
else {
assert(isExpr());
Inst.addOperand(MCOperand::createExpr(Expr));
}
}
bool isToken() const override {
return Kind == Token;
}
@ -190,9 +168,10 @@ public:
}
bool isInlinableImm() const {
if (!isImm() || Imm.Type != AMDGPUOperand::ImmTyNone /* Only plain
immediates are inlinable (e.g. "clamp" attribute is not) */ )
if (!isImmTy(ImmTyNone)) {
// Only plain immediates are inlinable (e.g. "clamp" attribute is not)
return false;
}
// TODO: We should avoid using host float here. It would be better to
// check the float bit values which is what a few other places do.
// We've had bot failures before due to weird NaN support on mips hosts.
@ -203,56 +182,33 @@ public:
F == 2.0 || F == -2.0 || F == 4.0 || F == -4.0);
}
int64_t getImm() const {
return Imm.Val;
}
enum ImmTy getImmTy() const {
assert(isImm());
return Imm.Type;
}
bool isRegKind() const {
return Kind == Register;
}
bool isReg() const override {
return Kind == Register && Reg.Modifiers == 0;
return isRegKind() && !Reg.Mods.hasModifiers();
}
bool isRegOrImmWithInputMods() const {
return Kind == Register || isInlinableImm();
return isRegKind() || isInlinableImm();
}
bool isImmTy(ImmTy ImmT) const {
return isImm() && Imm.Type == ImmT;
}
bool isClampSI() const {
return isImmTy(ImmTyClampSI);
}
bool isOModSI() const {
return isImmTy(ImmTyOModSI);
}
bool isImmModifier() const {
return Kind == Immediate && Imm.Type != ImmTyNone;
return isImm() && Imm.Type != ImmTyNone;
}
bool isDMask() const {
return isImmTy(ImmTyDMask);
}
bool isClampSI() const { return isImmTy(ImmTyClampSI); }
bool isOModSI() const { return isImmTy(ImmTyOModSI); }
bool isDMask() const { return isImmTy(ImmTyDMask); }
bool isUNorm() const { return isImmTy(ImmTyUNorm); }
bool isDA() const { return isImmTy(ImmTyDA); }
bool isR128() const { return isImmTy(ImmTyUNorm); }
bool isLWE() const { return isImmTy(ImmTyLWE); }
bool isMod() const {
return isClampSI() || isOModSI();
}
bool isOffen() const { return isImmTy(ImmTyOffen); }
bool isIdxen() const { return isImmTy(ImmTyIdxen); }
bool isAddr64() const { return isImmTy(ImmTyAddr64); }
@ -263,50 +219,16 @@ public:
bool isGLC() const { return isImmTy(ImmTyGLC); }
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);
}
bool isSDWADstSel() const {
return isImmTy(ImmTySdwaDstSel);
}
bool isSDWASrc0Sel() const {
return isImmTy(ImmTySdwaSrc0Sel);
}
bool isSDWASrc1Sel() const {
return isImmTy(ImmTySdwaSrc1Sel);
}
bool isSDWADstUnused() const {
return isImmTy(ImmTySdwaDstUnused);
}
void setModifiers(unsigned Mods) {
assert(isReg() || (isImm() && Imm.Modifiers == 0));
if (isReg())
Reg.Modifiers = Mods;
else
Imm.Modifiers = Mods;
}
bool hasModifiers() const {
assert(isRegKind() || isImm());
return isRegKind() ? Reg.Modifiers != 0 : Imm.Modifiers != 0;
}
unsigned getReg() const override {
return Reg.RegNo;
bool isBankMask() const { return isImmTy(ImmTyDppBankMask); }
bool isRowMask() const { return isImmTy(ImmTyDppRowMask); }
bool isBoundCtrl() const { return isImmTy(ImmTyDppBoundCtrl); }
bool isSDWADstSel() const { return isImmTy(ImmTySdwaDstSel); }
bool isSDWASrc0Sel() const { return isImmTy(ImmTySdwaSrc0Sel); }
bool isSDWASrc1Sel() const { return isImmTy(ImmTySdwaSrc1Sel); }
bool isSDWADstUnused() const { return isImmTy(ImmTySdwaDstUnused); }
bool isMod() const {
return isClampSI() || isOModSI();
}
bool isRegOrImm() const {
@ -368,6 +290,32 @@ public:
return isExpr() || isImm();
}
bool isSWaitCnt() const;
bool isHwreg() const;
bool isSendMsg() const;
bool isMubufOffset() const;
bool isSMRDOffset() const;
bool isSMRDLiteralOffset() const;
bool isDPPCtrl() const;
StringRef getToken() const {
return StringRef(Tok.Data, Tok.Length);
}
int64_t getImm() const {
assert(isImm());
return Imm.Val;
}
enum ImmTy getImmTy() const {
assert(isImm());
return Imm.Type;
}
unsigned getReg() const override {
return Reg.RegNo;
}
SMLoc getStartLoc() const override {
return StartLoc;
}
@ -376,6 +324,91 @@ public:
return EndLoc;
}
Modifiers getModifiers() const {
assert(isRegKind() || isImmTy(ImmTyNone));
return isRegKind() ? Reg.Mods : Imm.Mods;
}
void setModifiers(Modifiers Mods) {
assert(isRegKind() || isImmTy(ImmTyNone));
if (isRegKind())
Reg.Mods = Mods;
else
Imm.Mods = Mods;
}
bool hasModifiers() const {
return getModifiers().hasModifiers();
}
bool hasFPModifiers() const {
return getModifiers().hasFPModifiers();
}
bool hasIntModifiers() const {
return getModifiers().hasIntModifiers();
}
void addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers = true) const {
if (isImmTy(ImmTyNone) && ApplyModifiers && Imm.Mods.hasFPModifiers()) {
// Apply modifiers to immediate value
int64_t Val = Imm.Val;
bool Negate = Imm.Mods.Neg; // Only negate can get here
if (Imm.IsFPImm) {
APFloat F(BitsToFloat(Val));
if (Negate) {
F.changeSign();
}
Val = F.bitcastToAPInt().getZExtValue();
} else {
Val = Negate ? -Val : Val;
}
Inst.addOperand(MCOperand::createImm(Val));
} else {
Inst.addOperand(MCOperand::createImm(getImm()));
}
}
void addRegOperands(MCInst &Inst, unsigned N) const {
Inst.addOperand(MCOperand::createReg(AMDGPU::getMCReg(getReg(), *Reg.STI)));
}
void addRegOrImmOperands(MCInst &Inst, unsigned N) const {
if (isRegKind())
addRegOperands(Inst, N);
else
addImmOperands(Inst, N);
}
void addRegOrImmWithInputModsOperands(MCInst &Inst, unsigned N) const {
Modifiers Mods = getModifiers();
Inst.addOperand(MCOperand::createImm(Mods.getModifiersOperand()));
if (isRegKind()) {
addRegOperands(Inst, N);
} else {
addImmOperands(Inst, N, false);
}
}
void addRegOrImmWithFPInputModsOperands(MCInst &Inst, unsigned N) const {
assert(!hasIntModifiers());
addRegOrImmWithInputModsOperands(Inst, N);
}
void addRegOrImmWithIntInputModsOperands(MCInst &Inst, unsigned N) const {
assert(!hasFPModifiers());
addRegOrImmWithInputModsOperands(Inst, N);
}
void addSoppBrTargetOperands(MCInst &Inst, unsigned N) const {
if (isImm())
addImmOperands(Inst, N);
else {
assert(isExpr());
Inst.addOperand(MCOperand::createExpr(Expr));
}
}
void printImmTy(raw_ostream& OS, ImmTy Type) const {
switch (Type) {
case ImmTyNone: OS << "None"; break;
@ -412,14 +445,14 @@ public:
void print(raw_ostream &OS) const override {
switch (Kind) {
case Register:
OS << "<register " << getReg() << " mods: " << Reg.Modifiers << '>';
OS << "<register " << getReg() << " mods: " << Reg.Mods << '>';
break;
case Immediate:
OS << '<' << getImm();
if (getImmTy() != ImmTyNone) {
OS << " type: "; printImmTy(OS, getImmTy());
}
OS << " mods: " << Imm.Modifiers << '>';
OS << " mods: " << Imm.Mods << '>';
break;
case Token:
OS << '\'' << getToken() << '\'';
@ -437,7 +470,7 @@ public:
Op->Imm.Val = Val;
Op->Imm.IsFPImm = IsFPImm;
Op->Imm.Type = Type;
Op->Imm.Modifiers = 0;
Op->Imm.Mods = {false, false, false};
Op->StartLoc = Loc;
Op->EndLoc = Loc;
return Op;
@ -462,7 +495,7 @@ public:
Op->Reg.RegNo = RegNo;
Op->Reg.TRI = TRI;
Op->Reg.STI = STI;
Op->Reg.Modifiers = 0;
Op->Reg.Mods = {false, false, false};
Op->Reg.IsForcedVOP3 = ForceVOP3;
Op->StartLoc = S;
Op->EndLoc = E;
@ -476,16 +509,13 @@ public:
Op->EndLoc = S;
return Op;
}
bool isSWaitCnt() const;
bool isHwreg() const;
bool isSendMsg() const;
bool isMubufOffset() const;
bool isSMRDOffset() const;
bool isSMRDLiteralOffset() const;
bool isDPPCtrl() const;
};
raw_ostream &operator <<(raw_ostream &OS, AMDGPUOperand::Modifiers Mods) {
OS << "abs:" << Mods.Abs << " neg: " << Mods.Neg << " sext:" << Mods.Sext;
return OS;
}
class AMDGPUAsmParser : public MCTargetAsmParser {
const MCInstrInfo &MII;
MCAsmParser &Parser;
@ -598,7 +628,8 @@ public:
OperandMatchResultTy parseImm(OperandVector &Operands);
OperandMatchResultTy parseRegOrImm(OperandVector &Operands);
OperandMatchResultTy parseRegOrImmWithInputMods(OperandVector &Operands);
OperandMatchResultTy parseRegOrImmWithFPInputMods(OperandVector &Operands);
OperandMatchResultTy parseRegOrImmWithIntInputMods(OperandVector &Operands);
void cvtDSOffset01(MCInst &Inst, const OperandVector &Operands);
void cvtDS(MCInst &Inst, const OperandVector &Operands);
@ -665,12 +696,9 @@ public:
AMDGPUOperand::Ptr defaultSDWASrc0Sel() const;
AMDGPUOperand::Ptr defaultSDWASrc1Sel() const;
AMDGPUOperand::Ptr defaultSDWADstUnused() const;
void cvtSdwaVop1_mod(MCInst &Inst, const OperandVector &Operands);
void cvtSdwaVop1_nomod(MCInst &Inst, const OperandVector &Operands);
void cvtSdwaVop2_mod(MCInst &Inst, const OperandVector &Operands);
void cvtSdwaVop2_nomod(MCInst &Inst, const OperandVector &Operands);
void cvtSDWA(MCInst &Inst, const OperandVector &Operands, bool HasMods,
bool IsVOP1);
void cvtSdwaVOP1(MCInst &Inst, const OperandVector &Operands);
void cvtSdwaVOP2(MCInst &Inst, const OperandVector &Operands);
void cvtSDWA(MCInst &Inst, const OperandVector &Operands, bool IsVOP1);
};
struct OptionalOperand {
@ -969,7 +997,7 @@ AMDGPUAsmParser::parseRegOrImm(OperandVector &Operands) {
}
AMDGPUAsmParser::OperandMatchResultTy
AMDGPUAsmParser::parseRegOrImmWithInputMods(OperandVector &Operands) {
AMDGPUAsmParser::parseRegOrImmWithFPInputMods(OperandVector &Operands) {
// XXX: During parsing we can't determine if minus sign means
// negate-modifier or negative immediate value.
// By default we suppose it is modifier.
@ -1004,9 +1032,9 @@ AMDGPUAsmParser::parseRegOrImmWithInputMods(OperandVector &Operands) {
return Res;
}
unsigned Modifiers = 0;
AMDGPUOperand::Modifiers Mods = {false, false, false};
if (Negate) {
Modifiers |= 0x1;
Mods.Neg = true;
}
if (Abs) {
if (getLexer().getKind() != AsmToken::Pipe) {
@ -1014,7 +1042,7 @@ AMDGPUAsmParser::parseRegOrImmWithInputMods(OperandVector &Operands) {
return MatchOperand_ParseFail;
}
Parser.Lex();
Modifiers |= 0x2;
Mods.Abs = true;
}
if (Abs2) {
if (getLexer().isNot(AsmToken::RParen)) {
@ -1022,16 +1050,56 @@ AMDGPUAsmParser::parseRegOrImmWithInputMods(OperandVector &Operands) {
return MatchOperand_ParseFail;
}
Parser.Lex();
Modifiers |= 0x2;
Mods.Abs = true;
}
if (Modifiers) {
if (Mods.hasFPModifiers()) {
AMDGPUOperand &Op = static_cast<AMDGPUOperand &>(*Operands.back());
Op.setModifiers(Modifiers);
Op.setModifiers(Mods);
}
return MatchOperand_Success;
}
AMDGPUAsmParser::OperandMatchResultTy
AMDGPUAsmParser::parseRegOrImmWithIntInputMods(OperandVector &Operands) {
bool Sext = false;
if (getLexer().getKind() == AsmToken::Identifier && Parser.getTok().getString() == "sext") {
Parser.Lex();
Sext = true;
if (getLexer().isNot(AsmToken::LParen)) {
Error(Parser.getTok().getLoc(), "expected left paren after sext");
return MatchOperand_ParseFail;
}
Parser.Lex();
}
auto Res = parseRegOrImm(Operands);
if (Res != MatchOperand_Success) {
return Res;
}
AMDGPUOperand &Op = static_cast<AMDGPUOperand &>(*Operands.back());
if (Op.isImm() && Op.Imm.IsFPImm) {
Error(Parser.getTok().getLoc(), "floating point operands not allowed with sext() modifier");
return MatchOperand_ParseFail;
}
AMDGPUOperand::Modifiers Mods = {false, false, false};
if (Sext) {
if (getLexer().isNot(AsmToken::RParen)) {
Error(Parser.getTok().getLoc(), "expected closing parentheses");
return MatchOperand_ParseFail;
}
Parser.Lex();
Mods.Sext = true;
}
if (Mods.hasIntModifiers()) {
Op.setModifiers(Mods);
}
return MatchOperand_Success;
}
unsigned AMDGPUAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
@ -2338,7 +2406,8 @@ void AMDGPUAsmParser::cvtVOP3(MCInst &Inst, const OperandVector &Operands) {
for (unsigned E = Operands.size(); I != E; ++I) {
AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[I]);
if (Op.isRegOrImmWithInputMods()) {
Op.addRegOrImmWithInputModsOperands(Inst, 2);
// only fp modifiers allowed in VOP3
Op.addRegOrImmWithFPInputModsOperands(Inst, 2);
} else if (Op.isImm()) {
OptionalIdx[Op.getImmTy()] = I;
} else {
@ -2511,8 +2580,8 @@ void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) {
AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[I]);
// Add the register arguments
if (Op.isRegOrImmWithInputMods()) {
// We convert only instructions with modifiers
Op.addRegOrImmWithInputModsOperands(Inst, 2);
// Only float modifiers supported in DPP
Op.addRegOrImmWithFPInputModsOperands(Inst, 2);
} else if (Op.isDPPCtrl()) {
Op.addImmOperands(Inst, 1);
} else if (Op.isImm()) {
@ -2612,24 +2681,16 @@ AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSDWADstUnused() const {
return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTySdwaDstUnused);
}
void AMDGPUAsmParser::cvtSdwaVop1_mod(MCInst &Inst, const OperandVector &Operands) {
cvtSDWA(Inst, Operands, true, true);
void AMDGPUAsmParser::cvtSdwaVOP1(MCInst &Inst, const OperandVector &Operands) {
cvtSDWA(Inst, Operands, true);
}
void AMDGPUAsmParser::cvtSdwaVop1_nomod(MCInst &Inst, const OperandVector &Operands) {
cvtSDWA(Inst, Operands, false, true);
}
void AMDGPUAsmParser::cvtSdwaVop2_mod(MCInst &Inst, const OperandVector &Operands) {
cvtSDWA(Inst, Operands, true, false);
}
void AMDGPUAsmParser::cvtSdwaVop2_nomod(MCInst &Inst, const OperandVector &Operands) {
cvtSDWA(Inst, Operands, false, false);
void AMDGPUAsmParser::cvtSdwaVOP2(MCInst &Inst, const OperandVector &Operands) {
cvtSDWA(Inst, Operands, false);
}
void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands,
bool HasMods, bool IsVOP1) {
bool IsVOP1) {
OptionalImmIndexMap OptionalIdx;
unsigned I = 1;
@ -2641,10 +2702,8 @@ void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands,
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);
if (Op.isRegOrImmWithInputMods()) {
Op.addRegOrImmWithInputModsOperands(Inst, 2);
} else if (Op.isImm()) {
// Handle optional arguments
OptionalIdx[Op.getImmTy()] = I;
@ -2653,9 +2712,8 @@ void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands,
}
}
if (HasMods) {
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI, 0);
}
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI, 0);
if (Inst.getOpcode() == AMDGPU::V_NOP_sdwa) {
// V_NOP_sdwa has no optional sdwa arguments
return;

View File

@ -423,8 +423,9 @@ void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
}
}
void AMDGPUInstPrinter::printOperandAndMods(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
void AMDGPUInstPrinter::printOperandAndFPInputMods(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
unsigned InputModifiers = MI->getOperand(OpNo).getImm();
if (InputModifiers & SISrcMods::NEG)
O << '-';
@ -435,6 +436,17 @@ void AMDGPUInstPrinter::printOperandAndMods(const MCInst *MI, unsigned OpNo,
O << '|';
}
void AMDGPUInstPrinter::printOperandAndIntInputMods(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
unsigned InputModifiers = MI->getOperand(OpNo).getImm();
if (InputModifiers & SISrcMods::SEXT)
O << "sext(";
printOperand(MI, OpNo + 1, O);
if (InputModifiers & SISrcMods::SEXT)
O << ')';
}
void AMDGPUInstPrinter::printDPPCtrl(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {

View File

@ -64,7 +64,8 @@ private:
void printImmediate32(uint32_t I, raw_ostream &O);
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 printOperandAndFPInputMods(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printOperandAndIntInputMods(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printDPPCtrl(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printRowMask(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printBankMask(const MCInst *MI, unsigned OpNo, raw_ostream &O);

View File

@ -79,10 +79,13 @@ namespace SIInstrFlags {
};
}
// Input operand modifiers bit-masks
// NEG and SEXT share same bit-mask because they can't be set simultaneously.
namespace SISrcMods {
enum {
NEG = 1 << 0,
ABS = 1 << 1
NEG = 1 << 0, // Floating-point negate modifier
ABS = 1 << 1, // Floating-point absolute modifier
SEXT = 1 << 0 // Integer sign-extend modifier
};
}

View File

@ -560,6 +560,28 @@ def hwreg : NamedOperandU16<"Hwreg", NamedMatchClass<"Hwreg", 0>>;
def VOPDstS64 : VOPDstOperand <SReg_64>;
def FPInputModsMatchClass : AsmOperandClass {
let Name = "RegOrImmWithFPInputMods";
let ParserMethod = "parseRegOrImmWithFPInputMods";
let PredicateMethod = "isRegOrImmWithInputMods";
}
def FPInputMods : Operand <i32> {
let PrintMethod = "printOperandAndFPInputMods";
let ParserMatchClass = FPInputModsMatchClass;
}
def IntInputModsMatchClass : AsmOperandClass {
let Name = "RegOrImmWithIntInputMods";
let ParserMethod = "parseRegOrImmWithIntInputMods";
let PredicateMethod = "isRegOrImmWithInputMods";
}
def IntInputMods: Operand <i32> {
let PrintMethod = "printOperandAndIntInputMods";
let ParserMatchClass = IntInputModsMatchClass;
}
//===----------------------------------------------------------------------===//
// Complex patterns
//===----------------------------------------------------------------------===//
@ -1093,21 +1115,6 @@ multiclass SMRD_Helper <smrd op, string opName, RegisterClass baseClass,
// Vector ALU classes
//===----------------------------------------------------------------------===//
// This must always be right before the operand being input modified.
def InputMods : OperandWithDefaultOps <i32, (ops (i32 0))> {
let PrintMethod = "printOperandAndMods";
}
def InputModsMatchClass : AsmOperandClass {
let Name = "RegOrImmWithInputMods";
let ParserMethod = "parseRegOrImmWithInputMods";
}
def InputModsNoDefault : Operand <i32> {
let PrintMethod = "printOperandAndMods";
let ParserMatchClass = InputModsMatchClass;
}
class getNumSrcArgs<ValueType Src0, ValueType Src1, ValueType Src2> {
int ret =
!if (!eq(Src0.Value, untyped.Value), 0,
@ -1179,7 +1186,7 @@ class getIns64 <RegisterOperand Src0RC, RegisterOperand Src1RC,
!if (!eq(NumSrcArgs, 1),
!if (!eq(HasModifiers, 1),
// VOP1 with modifiers
(ins InputModsNoDefault:$src0_modifiers, Src0RC:$src0,
(ins FPInputMods:$src0_modifiers, Src0RC:$src0,
clampmod:$clamp, omod:$omod)
/* else */,
// VOP1 without modifiers
@ -1188,8 +1195,8 @@ class getIns64 <RegisterOperand Src0RC, RegisterOperand Src1RC,
!if (!eq(NumSrcArgs, 2),
!if (!eq(HasModifiers, 1),
// VOP 2 with modifiers
(ins InputModsNoDefault:$src0_modifiers, Src0RC:$src0,
InputModsNoDefault:$src1_modifiers, Src1RC:$src1,
(ins FPInputMods:$src0_modifiers, Src0RC:$src0,
FPInputMods:$src1_modifiers, Src1RC:$src1,
clampmod:$clamp, omod:$omod)
/* else */,
// VOP2 without modifiers
@ -1198,9 +1205,9 @@ class getIns64 <RegisterOperand Src0RC, RegisterOperand Src1RC,
/* NumSrcArgs == 3 */,
!if (!eq(HasModifiers, 1),
// VOP3 with modifiers
(ins InputModsNoDefault:$src0_modifiers, Src0RC:$src0,
InputModsNoDefault:$src1_modifiers, Src1RC:$src1,
InputModsNoDefault:$src2_modifiers, Src2RC:$src2,
(ins FPInputMods:$src0_modifiers, Src0RC:$src0,
FPInputMods:$src1_modifiers, Src1RC:$src1,
FPInputMods:$src2_modifiers, Src2RC:$src2,
clampmod:$clamp, omod:$omod)
/* else */,
// VOP3 without modifiers
@ -1218,7 +1225,7 @@ class getInsDPP <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
!if (!eq(NumSrcArgs, 1),
!if (!eq(HasModifiers, 1),
// VOP1_DPP with modifiers
(ins InputModsNoDefault:$src0_modifiers, Src0RC:$src0,
(ins FPInputMods:$src0_modifiers, Src0RC:$src0,
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl)
/* else */,
@ -1229,10 +1236,10 @@ class getInsDPP <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
/* NumSrcArgs == 2 */,
!if (!eq(HasModifiers, 1),
// VOP2_DPP with modifiers
(ins InputModsNoDefault:$src0_modifiers, Src0RC:$src0,
InputModsNoDefault:$src1_modifiers, Src1RC:$src1,
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl)
(ins FPInputMods:$src0_modifiers, Src0RC:$src0,
FPInputMods:$src1_modifiers, Src1RC:$src1,
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl)
/* else */,
// VOP2_DPP without modifiers
(ins Src0RC:$src0, Src1RC:$src1, dpp_ctrl:$dpp_ctrl,
@ -1242,34 +1249,35 @@ class getInsDPP <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
}
class getInsSDWA <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
bit HasModifiers> {
bit HasFloatModifiers> {
dag ret = !if (!eq(NumSrcArgs, 0),
// VOP1 without input operands (V_NOP)
(ins),
!if (!eq(NumSrcArgs, 1),
!if (!eq(HasModifiers, 1),
// VOP1_SDWA with modifiers
(ins InputModsNoDefault:$src0_fmodifiers, Src0RC:$src0,
!if (HasFloatModifiers,
// VOP1_SDWA with float modifiers
(ins FPInputMods:$src0_fmodifiers, Src0RC:$src0,
clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
src0_sel:$src0_sel)
/* else */,
// VOP1_SDWA without modifiers
// FIXME: sext() modifier is not supported yet
(ins Src0RC:$src0, dst_sel:$dst_sel, dst_unused:$dst_unused,
// VOP1_SDWA with sext modifier
(ins IntInputMods:$src0_imodifiers, Src0RC:$src0,
clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
src0_sel:$src0_sel)
/* endif */)
/* NumSrcArgs == 2 */,
!if (!eq(HasModifiers, 1),
// VOP2_SDWA with modifiers
(ins InputModsNoDefault:$src0_fmodifiers, Src0RC:$src0,
InputModsNoDefault:$src1_fmodifiers, Src1RC:$src1,
!if (HasFloatModifiers,
// VOP2_SDWA with float modifiers
(ins FPInputMods:$src0_fmodifiers, Src0RC:$src0,
FPInputMods:$src1_fmodifiers, Src1RC:$src1,
clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
src0_sel:$src0_sel, src1_sel:$src1_sel)
/* else */,
// VOP2_DPP without modifiers
(ins Src0RC:$src0, Src1RC:$src1,
dst_sel:$dst_sel, dst_unused:$dst_unused,
// VOP2_DPP with sext modifier
(ins IntInputMods:$src0_imodifiers, Src0RC:$src0,
IntInputMods:$src1_imodifiers, Src1RC:$src1,
clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
src0_sel:$src0_sel, src1_sel:$src1_sel)
/* endif */)));
}
@ -1328,19 +1336,22 @@ class getAsmDPP <bit HasDst, int NumSrcArgs, bit HasModifiers, ValueType DstVT =
string ret = dst#args#" $dpp_ctrl$row_mask$bank_mask$bound_ctrl";
}
class getAsmSDWA <bit HasDst, int NumSrcArgs, bit HasModifiers, ValueType DstVT = i32> {
string dst = !if(HasDst,
class getAsmSDWA <bit HasDst, int NumSrcArgs, bit HasFloatModifiers,
ValueType DstVT = i32> {
string dst = !if(HasDst,
!if(!eq(DstVT.Size, 1),
"$sdst",
"$sdst", // use $sdst for VOPC
"$vdst"),
""); // use $sdst for VOPC
string src0 = !if(!eq(NumSrcArgs, 1), "$src0_fmodifiers", "$src0_fmodifiers,");
string src1 = !if(!eq(NumSrcArgs, 1), "",
!if(!eq(NumSrcArgs, 2), " $src1_fmodifiers",
" $src1_fmodifiers,"));
string args = !if(!eq(HasModifiers, 0),
getAsm32<0, NumSrcArgs, DstVT>.ret,
", "#src0#src1#"$clamp");
"");
string src0 = !if(HasFloatModifiers, "$src0_fmodifiers", "$src0_imodifiers");
string src1 = !if(HasFloatModifiers, "$src1_fmodifiers", "$src1_imodifiers");
string args = !if(!eq(NumSrcArgs, 0),
"",
!if(!eq(NumSrcArgs, 1),
", "#src0#"$clamp",
", "#src0#", "#src1#"$clamp"
)
);
string sdwa = !if(!eq(NumSrcArgs, 0),
"",
!if(!eq(NumSrcArgs, 1),
@ -1518,7 +1529,7 @@ class VOPC_Profile<ValueType vt0, ValueType vt1 = vt0> : VOPProfile <[i1, vt0, v
}
class VOPC_Class_Profile<ValueType vt> : VOPC_Profile<vt, i32> {
let Ins64 = (ins InputModsNoDefault:$src0_modifiers, Src0RC64:$src0, Src1RC64:$src1);
let Ins64 = (ins FPInputMods:$src0_modifiers, Src0RC64:$src0, Src1RC64:$src1);
let Asm64 = "$sdst, $src0_modifiers, $src1";
}
@ -1549,13 +1560,13 @@ def VOP_MAC : VOPProfile <[f32, f32, f32, f32]> {
let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1, VGPR_32:$src2);
let Ins64 = getIns64<Src0RC64, Src1RC64, RegisterOperand<VGPR_32>, 3,
HasModifiers>.ret;
let InsDPP = (ins InputModsNoDefault:$src0_modifiers, Src0RC32:$src0,
InputModsNoDefault:$src1_modifiers, Src1RC32:$src1,
let InsDPP = (ins FPInputMods:$src0_modifiers, Src0RC32:$src0,
FPInputMods:$src1_modifiers, Src1RC32:$src1,
VGPR_32:$src2, // stub argument
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl);
let InsSDWA = (ins InputModsNoDefault:$src0_fmodifiers, Src0RC32:$src0,
InputModsNoDefault:$src1_fmodifiers, Src1RC32:$src1,
let InsSDWA = (ins FPInputMods:$src0_fmodifiers, Src0RC32:$src0,
FPInputMods:$src1_fmodifiers, Src1RC32:$src1,
VGPR_32:$src2, // stub argument
clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
src0_sel:$src0_sel, src1_sel:$src1_sel);
@ -1682,25 +1693,31 @@ class VOP1_DPP <vop1 op, string opName, VOPProfile p> :
class SDWADisableFields <VOPProfile p> {
bits<8> src0 = !if(!eq(p.NumSrcArgs, 0), 0, ?);
bits<3> src0_sel = !if(!eq(p.NumSrcArgs, 0), 6, ?);
bits<2> src0_fmodifiers = !if(p.HasModifiers, ?, 0);
bits<1> src0_imodifiers = 0; // FIXME: always 0 untill sext modifier is supported
bits<2> src0_fmodifiers = !if(!eq(p.NumSrcArgs, 0),
0,
!if(p.HasModifiers, ?, 0));
bits<1> src0_imodifiers = !if(!eq(p.NumSrcArgs, 0),
0,
!if(p.HasModifiers, 0, ?));
bits<3> src1_sel = !if(!eq(p.NumSrcArgs, 0), 6,
!if(!eq(p.NumSrcArgs, 1), 6,
?));
bits<2> src1_fmodifiers = !if(!eq(p.NumSrcArgs, 0), 0,
!if(!eq(p.NumSrcArgs, 1), 0,
!if(p.HasModifiers, ?, 0)));
bits<1> src1_imodifiers = 0;
bits<1> src1_imodifiers = !if(!eq(p.NumSrcArgs, 0), 0,
!if(!eq(p.NumSrcArgs, 1), 0,
!if(p.HasModifiers, 0, ?)));
bits<3> dst_sel = !if(p.HasDst, ?, 6);
bits<2> dst_unused = !if(p.HasDst, ?, 2);
bits<1> clamp = !if(p.HasModifiers, ?, 0);
bits<1> clamp = !if(!eq(p.NumSrcArgs, 0), 0, ?);
}
class VOP1_SDWA <vop1 op, string opName, VOPProfile p> :
VOP1_SDWAe <op.VI>,
VOP_SDWA <p.OutsSDWA, p.InsSDWA, opName#p.AsmSDWA, [], p.HasModifiers>,
SDWADisableFields <p> {
let AsmMatchConverter = !if(!eq(p.HasModifiers,1), "cvtSdwaVop1_mod", "cvtSdwaVop1_nomod");
let AsmMatchConverter = "cvtSdwaVOP1";
let AssemblerPredicates = !if(p.HasExt, [isVI], [DisableInst]);
let DecoderNamespace = "SDWA";
let DisableDecoder = DisableVIDecoder;
@ -1774,7 +1791,7 @@ class VOP2_SDWA <vop2 op, string opName, VOPProfile p> :
VOP2_SDWAe <op.VI>,
VOP_SDWA <p.OutsSDWA, p.InsSDWA, opName#p.AsmSDWA, [], p.HasModifiers>,
SDWADisableFields <p> {
let AsmMatchConverter = !if(!eq(p.HasModifiers,1), "cvtSdwaVop2_mod", "cvtSdwaVop2_nomod");
let AsmMatchConverter = "cvtSdwaVOP2";
let AssemblerPredicates = !if(p.HasExt, [isVI], [DisableInst]);
let DecoderNamespace = "SDWA";
let DisableDecoder = DisableVIDecoder;
@ -2397,9 +2414,9 @@ multiclass VOP3_VCC_Inst <vop3 op, string opName,
SDPatternOperator node = null_frag> : VOP3_Helper <
op, opName,
(outs P.DstRC.RegClass:$vdst),
(ins InputModsNoDefault:$src0_modifiers, P.Src0RC64:$src0,
InputModsNoDefault:$src1_modifiers, P.Src1RC64:$src1,
InputModsNoDefault:$src2_modifiers, P.Src2RC64:$src2,
(ins FPInputMods:$src0_modifiers, P.Src0RC64:$src0,
FPInputMods:$src1_modifiers, P.Src1RC64:$src1,
FPInputMods:$src2_modifiers, P.Src2RC64:$src2,
clampmod:$clamp,
omod:$omod),
"$vdst, $src0_modifiers, $src1_modifiers, $src2_modifiers"#"$clamp"#"$omod",

View File

@ -45,8 +45,8 @@ v_min_u32 v1, v1, v1 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:BYTE_0 src1_se
//---------------------------------------------------------------------------//
// NOSICI: error:
// VI: v_cvt_u32_f32_sdwa v0, v0 dst_sel:DWORD dst_unused:UNUSED_PRESERVE src0_sel:DWORD ; encoding: [0xf9,0x0e,0x00,0x7e,0x00,0x16,0x06,0x06]
v_cvt_u32_f32 v0, v0 dst_sel:DWORD
// VI: v_cvt_u32_f32_sdwa v0, v0 clamp dst_sel:DWORD dst_unused:UNUSED_PRESERVE src0_sel:DWORD ; encoding: [0xf9,0x0e,0x00,0x7e,0x00,0x36,0x06,0x06]
v_cvt_u32_f32 v0, v0 clamp dst_sel:DWORD
// NOSICI: error:
// VI: v_fract_f32_sdwa v0, v0 clamp dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD ; encoding: [0xf9,0x36,0x00,0x7e,0x00,0x26,0x06,0x06]
@ -57,8 +57,8 @@ v_fract_f32 v0, v0 clamp dst_sel:DWORD dst_unused:UNUSED_PAD
v_sin_f32 v0, v0 dst_unused:UNUSED_PAD src0_sel:WORD_1
// NOSICI: error:
// VI: v_mov_b32_sdwa v1, v0 dst_sel:DWORD dst_unused:UNUSED_PRESERVE src0_sel:WORD_1 ; encoding: [0xf9,0x02,0x02,0x7e,0x00,0x16,0x05,0x06]
v_mov_b32 v1, v0 src0_sel:WORD_1
// VI: v_mov_b32_sdwa v1, v0 clamp dst_sel:DWORD dst_unused:UNUSED_PRESERVE src0_sel:WORD_1 ; encoding: [0xf9,0x02,0x02,0x7e,0x00,0x36,0x05,0x06]
v_mov_b32 v1, v0 clamp src0_sel:WORD_1
// NOSICI: error:
// VI: v_trunc_f32_sdwa v1, v0 clamp dst_sel:DWORD dst_unused:UNUSED_PRESERVE src0_sel:WORD_1 ; encoding: [0xf9,0x38,0x02,0x7e,0x00,0x36,0x05,0x06]
@ -81,8 +81,8 @@ v_min_f32 v0, v0, v0 clamp dst_sel:DWORD src1_sel:BYTE_2
v_and_b32 v0, v0, v0 dst_unused:UNUSED_PAD src1_sel:BYTE_2
// NOSICI: error:
// VI: v_mul_i32_i24_sdwa v1, v2, v3 dst_sel:DWORD dst_unused:UNUSED_PRESERVE src0_sel:DWORD src1_sel:DWORD ; encoding: [0xf9,0x06,0x02,0x0c,0x02,0x16,0x06,0x06]
v_mul_i32_i24_sdwa v1, v2, v3
// VI: v_mul_i32_i24_sdwa v1, v2, v3 clamp dst_sel:DWORD dst_unused:UNUSED_PRESERVE src0_sel:DWORD src1_sel:DWORD ; encoding: [0xf9,0x06,0x02,0x0c,0x02,0x36,0x06,0x06]
v_mul_i32_i24_sdwa v1, v2, v3 clamp
//===----------------------------------------------------------------------===//
// Check modifiers
@ -104,6 +104,14 @@ v_add_f32 v0, -|v0|, -v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src
// VI: v_min_f32_sdwa v0, |v0|, -v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:BYTE_2 ; encoding: [0xf9,0x00,0x00,0x14,0x00,0x06,0x25,0x12]
v_min_f32 v0, abs(v0), -v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:BYTE_2
// NOSICI: error:
// VI: v_mov_b32_sdwa v1, sext(v0) dst_sel:DWORD dst_unused:UNUSED_PRESERVE src0_sel:DWORD ; encoding: [0xf9,0x02,0x02,0x7e,0x00,0x16,0x0e,0x06]
v_mov_b32_sdwa v1, sext(v0)
// NOSICI: error:
// VI: v_and_b32_sdwa v0, sext(v0), sext(v0) dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:BYTE_2 ; encoding: [0xf9,0x00,0x00,0x26,0x00,0x06,0x0e,0x0a]
v_and_b32 v0, sext(v0), sext(v0) dst_unused:UNUSED_PAD src1_sel:BYTE_2
//===----------------------------------------------------------------------===//
// Check VOP1 opcodes
//===----------------------------------------------------------------------===//