[PATCH] R600/SI: Add assembler support for s_load_dword* instructions
Tom Stellard
thomas.stellard at amd.com
Fri Nov 14 03:35:06 PST 2014
---
docs/R600Usage.rst | 4 +
lib/Target/R600/AsmParser/AMDGPUAsmParser.cpp | 159 +++++++++++++++++++++++---
lib/Target/R600/SIInstrInfo.td | 4 +-
3 files changed, 153 insertions(+), 14 deletions(-)
diff --git a/docs/R600Usage.rst b/docs/R600Usage.rst
index 48a30c8..2282d54 100644
--- a/docs/R600Usage.rst
+++ b/docs/R600Usage.rst
@@ -15,6 +15,10 @@ Assembler
The assembler is currently a work in progress and not yet complete. Below
are the currently supported features.
+SMRD Instructions
+-----------------
+The assembler currently supports only the s_load_dword* SMRD instructions.
+
SOPP Instructions
-----------------
diff --git a/lib/Target/R600/AsmParser/AMDGPUAsmParser.cpp b/lib/Target/R600/AsmParser/AMDGPUAsmParser.cpp
index 205de5f..9f817bf 100644
--- a/lib/Target/R600/AsmParser/AMDGPUAsmParser.cpp
+++ b/lib/Target/R600/AsmParser/AMDGPUAsmParser.cpp
@@ -69,7 +69,8 @@ public:
class AMDGPUOperand : public MCParsedAsmOperand {
enum KindTy {
Token,
- Immediate
+ Immediate,
+ Register
} Kind;
public:
@@ -84,16 +85,21 @@ public:
int64_t Val;
};
+ struct RegOp {
+ unsigned RegNo;
+ };
+
union {
TokOp Tok;
ImmOp Imm;
+ RegOp Reg;
};
void addImmOperands(MCInst &Inst, unsigned N) const {
Inst.addOperand(MCOperand::CreateImm(getImm()));
}
void addRegOperands(MCInst &Inst, unsigned N) const {
- llvm_unreachable("addRegOperands");
+ Inst.addOperand(MCOperand::CreateReg(getReg()));
}
StringRef getToken() const {
return StringRef(Tok.Data, Tok.Length);
@@ -111,11 +117,11 @@ public:
}
bool isReg() const override {
- return false;
+ return Kind == Register;
}
unsigned getReg() const override {
- return 0;
+ return Reg.RegNo;
}
bool isMem() const override {
@@ -145,13 +151,125 @@ public:
return Res;
}
+ static std::unique_ptr<AMDGPUOperand> CreateReg(unsigned RegNo, SMLoc S,
+ SMLoc E) {
+ auto Op = llvm::make_unique<AMDGPUOperand>(Register);
+ Op->Reg.RegNo = RegNo;
+ return Op;
+ }
+
bool isSWaitCnt() const;
};
}
bool AMDGPUAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) {
- return true;
+ const AsmToken Tok = Parser.getTok();
+ StartLoc = Tok.getLoc();
+ EndLoc = Tok.getEndLoc();
+ const StringRef &RegName = Tok.getString();
+ RegNo = 0;
+
+ // Handle special cases
+ if (RegName.equals("vcc_lo"))
+ RegNo = AMDGPU::VCC_LO;
+ else if (RegName.equals("vcc_hi"))
+ RegNo = AMDGPU::VCC_HI;
+ else if (RegName.equals("VCC"))
+ RegNo = AMDGPU::VCC;
+ else if (RegName.equals("exec_lo"))
+ RegNo = AMDGPU::EXEC_LO;
+ else if (RegName.equals("exec_hi"))
+ RegNo = AMDGPU::EXEC_HI;
+ else if (RegName.equals("EXEC"))
+ RegNo = AMDGPU::EXEC;
+ else if (RegName.equals("M0"))
+ RegNo = AMDGPU::M0;
+ else if (RegName.equals("flat_scr_lo"))
+ RegNo = AMDGPU::FLAT_SCR_LO;
+ else if (RegName.equals("flat_scr_hi"))
+ RegNo = AMDGPU::FLAT_SCR_HI;
+ else if (RegName.equals("FLAT_SCR"))
+ RegNo = AMDGPU::FLAT_SCR;
+ else if (RegName.equals("SCC"))
+ RegNo = AMDGPU::SCC;
+
+ if (RegNo)
+ return false;
+
+ // Match vgprs and sgprs
+ if (RegName[0] != 's' && RegName[0] != 'v')
+ return true;
+
+ bool IsVgpr = RegName[0] == 'v';
+ unsigned RegWidth;
+ unsigned RegIndexInClass;
+ if (RegName.size() > 1) {
+ // We have a 32-bit register
+ RegWidth = 1;
+ APInt RegIndex;
+ if (RegName.substr(1).getAsInteger(10, RegIndex))
+ return true;
+ RegIndexInClass = RegIndex.getSExtValue();
+ Parser.Lex();
+ } else {
+ // We have a register greater than 32-bits.
+
+ int64_t RegLo, RegHi;
+ Parser.Lex();
+ if (getLexer().isNot(AsmToken::LBrac))
+ return true;
+
+ Parser.Lex();
+ if (getParser().parseAbsoluteExpression(RegLo))
+ return true;
+
+ if (getLexer().isNot(AsmToken::Colon))
+ return true;
+
+ Parser.Lex();
+ if (getParser().parseAbsoluteExpression(RegHi))
+ return true;
+
+ if (getLexer().isNot(AsmToken::RBrac))
+ return true;
+
+ Parser.Lex();
+ RegWidth = ((RegHi - RegLo) + 1);
+ if (IsVgpr) {
+ // VGPR registers aren't aligned.
+ RegIndexInClass = RegLo;
+ } else {
+ // SGPR registers are aligned. Max alignment is 4 dwords.
+ RegIndexInClass = RegLo / std::min((int)RegWidth, 4);
+ }
+ }
+
+ unsigned RC;
+ const MCRegisterInfo *TRC = getContext().getRegisterInfo();
+ if (IsVgpr) {
+ switch (RegWidth) {
+ default: llvm_unreachable("Unknown register width");
+ case 1: RC = AMDGPU::VGPR_32RegClassID; break;
+ case 2: RC = AMDGPU::VReg_64RegClassID; break;
+ case 3: RC = AMDGPU::VReg_96RegClassID; break;
+ case 4: RC = AMDGPU::VReg_128RegClassID; break;
+ case 8: RC = AMDGPU::VReg_256RegClassID; break;
+ case 16: RC = AMDGPU::VReg_512RegClassID; break;
+ }
+ } else {
+ switch (RegWidth) {
+ default: llvm_unreachable("Unknown register width");
+ case 1: RC = AMDGPU::SGPR_32RegClassID; break;
+ case 2: RC = AMDGPU::SGPR_64RegClassID; break;
+ case 4: RC = AMDGPU::SReg_128RegClassID; break;
+ case 8: RC = AMDGPU::SReg_256RegClassID; break;
+ case 16: RC = AMDGPU::SReg_512RegClassID; break;
+ }
+ }
+
+ RegNo = TRC->getRegClass(RC).getRegister(RegIndexInClass);
+ return false;
}
@@ -207,6 +325,14 @@ AMDGPUAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
Operands.push_back(AMDGPUOperand::CreateImm(IntVal));
return MatchOperand_Success;
}
+ case AsmToken::Identifier: {
+ SMLoc S, E;
+ unsigned RegNo;
+ if (ParseRegister(RegNo, S, E))
+ return MatchOperand_NoMatch;
+ Operands.push_back(AMDGPUOperand::CreateReg(RegNo, S, E));
+ return MatchOperand_Success;
+ }
default:
return MatchOperand_NoMatch;
}
@@ -218,16 +344,23 @@ bool AMDGPUAsmParser::ParseInstruction(ParseInstructionInfo &Info,
// Add the instruction mnemonic
Operands.push_back(AMDGPUOperand::CreateToken(Name, NameLoc));
- if (getLexer().is(AsmToken::EndOfStatement))
- return false;
+ while (!getLexer().is(AsmToken::EndOfStatement)) {
- AMDGPUAsmParser::OperandMatchResultTy Res = parseOperand(Operands, Name);
- switch (Res) {
- case MatchOperand_Success: return false;
- case MatchOperand_ParseFail: return Error(NameLoc,
- "Failed parsing operand");
- case MatchOperand_NoMatch: return Error(NameLoc, "Not a valid operand");
+ AMDGPUAsmParser::OperandMatchResultTy Res = parseOperand(Operands, Name);
+
+ // Eat the comma if there is one.
+ if (getLexer().is(AsmToken::Comma))
+ Parser.Lex();
+
+ switch (Res) {
+ case MatchOperand_Success: break;
+ case MatchOperand_ParseFail: return Error(getLexer().getLoc(),
+ "Failed parsing operand");
+ case MatchOperand_NoMatch: return Error(getLexer().getLoc(),
+ "Not a valid operand");
+ }
}
+ return false;
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Target/R600/SIInstrInfo.td b/lib/Target/R600/SIInstrInfo.td
index ec4ac9a..346a601 100644
--- a/lib/Target/R600/SIInstrInfo.td
+++ b/lib/Target/R600/SIInstrInfo.td
@@ -392,7 +392,9 @@ multiclass SMRD_m <bits<5> op, string opName, bit imm, dag outs, dag ins,
def "" : SMRD_Pseudo <opName, outs, ins, pattern>;
- def _si : SMRD_Real_si <op, opName, imm, outs, ins, asm>;
+ let isCodeGenOnly = 0 in {
+ def _si : SMRD_Real_si <op, opName, imm, outs, ins, asm>;
+ }
}
--
1.8.1.5
More information about the llvm-commits
mailing list