mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-05 03:46:27 +00:00
[AMDGPU][llvm-mc] s_getreg/setreg* - Add hwreg(...) syntax.
Added hwreg(reg[,offset,width]) syntax. Default offset = 0, default width = 32. Possibility to specify 16-bit immediate kept. Added out-of-range checks. Disassembling is always to hwreg(...) format. Tests updated/added. Differential Revision: http://reviews.llvm.org/D19329 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@267410 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2eaeff8313
commit
2bc6d42753
@ -79,6 +79,7 @@ public:
|
|||||||
ImmTyDA,
|
ImmTyDA,
|
||||||
ImmTyR128,
|
ImmTyR128,
|
||||||
ImmTyLWE,
|
ImmTyLWE,
|
||||||
|
ImmTyHwreg,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TokOp {
|
struct TokOp {
|
||||||
@ -406,6 +407,7 @@ public:
|
|||||||
bool isDSOffset() const;
|
bool isDSOffset() const;
|
||||||
bool isDSOffset01() const;
|
bool isDSOffset01() const;
|
||||||
bool isSWaitCnt() const;
|
bool isSWaitCnt() const;
|
||||||
|
bool isHwreg() const;
|
||||||
bool isMubufOffset() const;
|
bool isMubufOffset() const;
|
||||||
bool isSMRDOffset() const;
|
bool isSMRDOffset() const;
|
||||||
bool isSMRDLiteralOffset() const;
|
bool isSMRDLiteralOffset() const;
|
||||||
@ -530,6 +532,8 @@ public:
|
|||||||
|
|
||||||
bool parseCnt(int64_t &IntVal);
|
bool parseCnt(int64_t &IntVal);
|
||||||
OperandMatchResultTy parseSWaitCntOps(OperandVector &Operands);
|
OperandMatchResultTy parseSWaitCntOps(OperandVector &Operands);
|
||||||
|
bool parseHwreg(int64_t &HwRegCode, int64_t &Offset, int64_t &Width);
|
||||||
|
OperandMatchResultTy parseHwregOp(OperandVector &Operands);
|
||||||
OperandMatchResultTy parseSOppBrTarget(OperandVector &Operands);
|
OperandMatchResultTy parseSOppBrTarget(OperandVector &Operands);
|
||||||
|
|
||||||
OperandMatchResultTy parseFlatOptionalOps(OperandVector &Operands);
|
OperandMatchResultTy parseFlatOptionalOps(OperandVector &Operands);
|
||||||
@ -1570,10 +1574,100 @@ AMDGPUAsmParser::parseSWaitCntOps(OperandVector &Operands) {
|
|||||||
return MatchOperand_Success;
|
return MatchOperand_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AMDGPUAsmParser::parseHwreg(int64_t &HwRegCode, int64_t &Offset, int64_t &Width) {
|
||||||
|
if (Parser.getTok().getString() != "hwreg")
|
||||||
|
return true;
|
||||||
|
Parser.Lex();
|
||||||
|
|
||||||
|
if (getLexer().isNot(AsmToken::LParen))
|
||||||
|
return true;
|
||||||
|
Parser.Lex();
|
||||||
|
|
||||||
|
if (getLexer().isNot(AsmToken::Integer))
|
||||||
|
return true;
|
||||||
|
if (getParser().parseAbsoluteExpression(HwRegCode))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (getLexer().is(AsmToken::RParen)) {
|
||||||
|
Parser.Lex();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional params
|
||||||
|
if (getLexer().isNot(AsmToken::Comma))
|
||||||
|
return true;
|
||||||
|
Parser.Lex();
|
||||||
|
|
||||||
|
if (getLexer().isNot(AsmToken::Integer))
|
||||||
|
return true;
|
||||||
|
if (getParser().parseAbsoluteExpression(Offset))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (getLexer().isNot(AsmToken::Comma))
|
||||||
|
return true;
|
||||||
|
Parser.Lex();
|
||||||
|
|
||||||
|
if (getLexer().isNot(AsmToken::Integer))
|
||||||
|
return true;
|
||||||
|
if (getParser().parseAbsoluteExpression(Width))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (getLexer().isNot(AsmToken::RParen))
|
||||||
|
return true;
|
||||||
|
Parser.Lex();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AMDGPUAsmParser::OperandMatchResultTy
|
||||||
|
AMDGPUAsmParser::parseHwregOp(OperandVector &Operands) {
|
||||||
|
int64_t Imm16Val = 0;
|
||||||
|
SMLoc S = Parser.getTok().getLoc();
|
||||||
|
|
||||||
|
switch(getLexer().getKind()) {
|
||||||
|
default: return MatchOperand_ParseFail;
|
||||||
|
case AsmToken::Integer:
|
||||||
|
// The operand can be an integer value.
|
||||||
|
if (getParser().parseAbsoluteExpression(Imm16Val))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
if (!isInt<16>(Imm16Val) && !isUInt<16>(Imm16Val)) {
|
||||||
|
Error(S, "invalid immediate: only 16-bit values are legal");
|
||||||
|
// Do not return error code, but create an imm operand anyway and proceed
|
||||||
|
// to the next operand, if any. That avoids unneccessary error messages.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AsmToken::Identifier: {
|
||||||
|
int64_t HwRegCode = 0;
|
||||||
|
int64_t Offset = 0; // default
|
||||||
|
int64_t Width = 32; // default
|
||||||
|
if (parseHwreg(HwRegCode, Offset, Width))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
// HwRegCode (6) [5:0]
|
||||||
|
// Offset (5) [10:6]
|
||||||
|
// WidthMinusOne (5) [15:11]
|
||||||
|
if (HwRegCode < 0 || HwRegCode > 63)
|
||||||
|
Error(S, "invalid code of hardware register: only 6-bit values are legal");
|
||||||
|
if (Offset < 0 || Offset > 31)
|
||||||
|
Error(S, "invalid bit offset: only 5-bit values are legal");
|
||||||
|
if (Width < 1 || Width > 32)
|
||||||
|
Error(S, "invalid bitfield width: only values from 1 to 32 are legal");
|
||||||
|
Imm16Val = HwRegCode | (Offset << 6) | ((Width-1) << 11);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Operands.push_back(AMDGPUOperand::CreateImm(Imm16Val, S, AMDGPUOperand::ImmTyHwreg));
|
||||||
|
return MatchOperand_Success;
|
||||||
|
}
|
||||||
|
|
||||||
bool AMDGPUOperand::isSWaitCnt() const {
|
bool AMDGPUOperand::isSWaitCnt() const {
|
||||||
return isImm();
|
return isImm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AMDGPUOperand::isHwreg() const {
|
||||||
|
return isImmTy(ImmTyHwreg);
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// sopp branch targets
|
// sopp branch targets
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -760,4 +760,18 @@ void AMDGPUInstPrinter::printWaitFlag(const MCInst *MI, unsigned OpNo,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AMDGPUInstPrinter::printHwreg(const MCInst *MI, unsigned OpNo,
|
||||||
|
raw_ostream &O) {
|
||||||
|
unsigned SImm16 = MI->getOperand(OpNo).getImm();
|
||||||
|
const unsigned HwRegCode = SImm16 & 0x3F;
|
||||||
|
const unsigned Offset = (SImm16 >> 6) & 0x1f;
|
||||||
|
const unsigned Width = ((SImm16 >> 11) & 0x1F) + 1;
|
||||||
|
|
||||||
|
if (Width == 32 && Offset == 0) {
|
||||||
|
O << "hwreg(" << HwRegCode << ')';
|
||||||
|
} else {
|
||||||
|
O << "hwreg(" << HwRegCode << ", " << Offset << ", " << Width << ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "AMDGPUGenAsmWriter.inc"
|
#include "AMDGPUGenAsmWriter.inc"
|
||||||
|
@ -91,6 +91,7 @@ private:
|
|||||||
static void printKCache(const MCInst *MI, unsigned OpNo, raw_ostream &O);
|
static void printKCache(const MCInst *MI, unsigned OpNo, raw_ostream &O);
|
||||||
static void printSendMsg(const MCInst *MI, unsigned OpNo, raw_ostream &O);
|
static void printSendMsg(const MCInst *MI, unsigned OpNo, raw_ostream &O);
|
||||||
static void printWaitFlag(const MCInst *MI, unsigned OpNo, raw_ostream &O);
|
static void printWaitFlag(const MCInst *MI, unsigned OpNo, raw_ostream &O);
|
||||||
|
static void printHwreg(const MCInst *MI, unsigned OpNo, raw_ostream &O);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace llvm
|
} // End namespace llvm
|
||||||
|
@ -603,6 +603,13 @@ class NamedBitOperand<string BitName> : Operand<i1> {
|
|||||||
let PrintMethod = "print"#BitName;
|
let PrintMethod = "print"#BitName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def HwregMatchClass : AsmOperandClass {
|
||||||
|
let Name = "Hwreg";
|
||||||
|
let PredicateMethod = "isHwreg";
|
||||||
|
let ParserMethod = "parseHwregOp";
|
||||||
|
let RenderMethod = "addImmOperands";
|
||||||
|
}
|
||||||
|
|
||||||
let OperandType = "OPERAND_IMMEDIATE" in {
|
let OperandType = "OPERAND_IMMEDIATE" in {
|
||||||
|
|
||||||
def offen : Operand<i1> {
|
def offen : Operand<i1> {
|
||||||
@ -730,6 +737,11 @@ def bound_ctrl : Operand <i1> {
|
|||||||
let ParserMatchClass = DPPOptionalMatchClass<"BoundCtrl">;
|
let ParserMatchClass = DPPOptionalMatchClass<"BoundCtrl">;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def hwreg : Operand <i16> {
|
||||||
|
let PrintMethod = "printHwreg";
|
||||||
|
let ParserMatchClass = HwregMatchClass;
|
||||||
|
}
|
||||||
|
|
||||||
} // End OperandType = "OPERAND_IMMEDIATE"
|
} // End OperandType = "OPERAND_IMMEDIATE"
|
||||||
|
|
||||||
|
|
||||||
|
@ -418,18 +418,21 @@ defm S_CBRANCH_I_FORK : SOPK_m <
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
let mayLoad = 1 in {
|
let mayLoad = 1 in {
|
||||||
defm S_GETREG_B32 : SOPK_32 <sopk<0x12, 0x11>, "s_getreg_b32", []>;
|
defm S_GETREG_B32 : SOPK_m <
|
||||||
|
sopk<0x12, 0x11>, "s_getreg_b32", (outs SReg_32:$sdst),
|
||||||
|
(ins hwreg:$simm16), " $sdst, $simm16"
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
defm S_SETREG_B32 : SOPK_m <
|
defm S_SETREG_B32 : SOPK_m <
|
||||||
sopk<0x13, 0x12>, "s_setreg_b32", (outs),
|
sopk<0x13, 0x12>, "s_setreg_b32", (outs),
|
||||||
(ins SReg_32:$sdst, u16imm:$simm16), " $simm16, $sdst"
|
(ins SReg_32:$sdst, hwreg:$simm16), " $simm16, $sdst"
|
||||||
>;
|
>;
|
||||||
// FIXME: Not on SI?
|
// FIXME: Not on SI?
|
||||||
//defm S_GETREG_REGRD_B32 : SOPK_32 <sopk<0x14, 0x13>, "s_getreg_regrd_b32", []>;
|
//defm S_GETREG_REGRD_B32 : SOPK_32 <sopk<0x14, 0x13>, "s_getreg_regrd_b32", []>;
|
||||||
defm S_SETREG_IMM32_B32 : SOPK_IMM32 <
|
defm S_SETREG_IMM32_B32 : SOPK_IMM32 <
|
||||||
sopk<0x15, 0x14>, "s_setreg_imm32_b32", (outs),
|
sopk<0x15, 0x14>, "s_setreg_imm32_b32", (outs),
|
||||||
(ins i32imm:$imm, u16imm:$simm16), " $simm16, $imm"
|
(ins i32imm:$imm, hwreg:$simm16), " $simm16, $imm"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
; RUN: llc -mtriple=amdgcn--amdhsa -mcpu=fiji -verify-machineinstrs < %s | FileCheck %s
|
; RUN: llc -mtriple=amdgcn--amdhsa -mcpu=fiji -verify-machineinstrs < %s | FileCheck %s
|
||||||
|
|
||||||
; FUNC-LABEL: {{^}}s_getreg_test:
|
; FUNC-LABEL: {{^}}s_getreg_test:
|
||||||
; CHECK: s_getreg_b32 s{{[0-9]+}}, 0xb206
|
; CHECK: s_getreg_b32 s{{[0-9]+}}, hwreg(6, 8, 23)
|
||||||
define void @s_getreg_test(i32 addrspace(1)* %out) { ; simm16=45574 for lds size.
|
define void @s_getreg_test(i32 addrspace(1)* %out) { ; simm16=45574 for lds size.
|
||||||
%lds_size_64dwords = call i32 @llvm.amdgcn.s.getreg(i32 45574) #0
|
%lds_size_64dwords = call i32 @llvm.amdgcn.s.getreg(i32 45574) #0
|
||||||
%lds_size_bytes = shl i32 %lds_size_64dwords, 8
|
%lds_size_bytes = shl i32 %lds_size_64dwords, 8
|
||||||
|
24
test/MC/AMDGPU/sopk-err.s
Normal file
24
test/MC/AMDGPU/sopk-err.s
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// RUN: not llvm-mc -arch=amdgcn %s 2>&1 | FileCheck -check-prefix=GCN %s
|
||||||
|
// RUN: not llvm-mc -arch=amdgcn -mcpu=tahiti %s 2>&1 | FileCheck -check-prefix=GCN -check-prefix=SI %s
|
||||||
|
// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga %s 2>&1 | FileCheck -check-prefix=GCN -check-prefix=VI %s
|
||||||
|
|
||||||
|
s_setreg_b32 0x1f803, s2
|
||||||
|
// GCN: error: invalid immediate: only 16-bit values are legal
|
||||||
|
|
||||||
|
s_setreg_b32 hwreg(0x40), s2
|
||||||
|
// GCN: error: invalid code of hardware register: only 6-bit values are legal
|
||||||
|
|
||||||
|
s_setreg_b32 hwreg(3,32,32), s2
|
||||||
|
// GCN: error: invalid bit offset: only 5-bit values are legal
|
||||||
|
|
||||||
|
s_setreg_b32 hwreg(3,0,33), s2
|
||||||
|
// GCN: error: invalid bitfield width: only values from 1 to 32 are legal
|
||||||
|
|
||||||
|
s_setreg_imm32_b32 0x1f803, 0xff
|
||||||
|
// GCN: error: invalid immediate: only 16-bit values are legal
|
||||||
|
|
||||||
|
s_setreg_imm32_b32 hwreg(3,0,33), 0xff
|
||||||
|
// GCN: error: invalid bitfield width: only values from 1 to 32 are legal
|
||||||
|
|
||||||
|
s_getreg_b32 s2, hwreg(3,32,32)
|
||||||
|
// GCN: error: invalid bit offset: only 5-bit values are legal
|
@ -74,13 +74,33 @@ s_cbranch_i_fork s[2:3], 0x6
|
|||||||
// VI: s_cbranch_i_fork s[2:3], 0x6 ; encoding: [0x06,0x00,0x02,0xb8]
|
// VI: s_cbranch_i_fork s[2:3], 0x6 ; encoding: [0x06,0x00,0x02,0xb8]
|
||||||
|
|
||||||
s_getreg_b32 s2, 0x6
|
s_getreg_b32 s2, 0x6
|
||||||
// SICI: s_getreg_b32 s2, 0x6 ; encoding: [0x06,0x00,0x02,0xb9]
|
// SICI: s_getreg_b32 s2, hwreg(6, 0, 1) ; encoding: [0x06,0x00,0x02,0xb9]
|
||||||
// VI: s_getreg_b32 s2, 0x6 ; encoding: [0x06,0x00,0x82,0xb8]
|
// VI: s_getreg_b32 s2, hwreg(6, 0, 1) ; encoding: [0x06,0x00,0x82,0xb8]
|
||||||
|
|
||||||
|
s_getreg_b32 s2, hwreg(5, 1, 31)
|
||||||
|
// SICI: s_getreg_b32 s2, hwreg(5, 1, 31) ; encoding: [0x45,0xf0,0x02,0xb9]
|
||||||
|
// VI: s_getreg_b32 s2, hwreg(5, 1, 31) ; encoding: [0x45,0xf0,0x82,0xb8]
|
||||||
|
|
||||||
s_setreg_b32 0x6, s2
|
s_setreg_b32 0x6, s2
|
||||||
// SICI: s_setreg_b32 0x6, s2 ; encoding: [0x06,0x00,0x82,0xb9]
|
// SICI: s_setreg_b32 hwreg(6, 0, 1), s2 ; encoding: [0x06,0x00,0x82,0xb9]
|
||||||
// VI: s_setreg_b32 0x6, s2 ; encoding: [0x06,0x00,0x02,0xb9]
|
// VI: s_setreg_b32 hwreg(6, 0, 1), s2 ; encoding: [0x06,0x00,0x02,0xb9]
|
||||||
|
|
||||||
|
s_setreg_b32 0xf803, s2
|
||||||
|
// SICI: s_setreg_b32 hwreg(3), s2 ; encoding: [0x03,0xf8,0x82,0xb9]
|
||||||
|
// VI: s_setreg_b32 hwreg(3), s2 ; encoding: [0x03,0xf8,0x02,0xb9]
|
||||||
|
|
||||||
|
s_setreg_b32 hwreg(4), s2
|
||||||
|
// SICI: s_setreg_b32 hwreg(4), s2 ; encoding: [0x04,0xf8,0x82,0xb9]
|
||||||
|
// VI: s_setreg_b32 hwreg(4), s2 ; encoding: [0x04,0xf8,0x02,0xb9]
|
||||||
|
|
||||||
|
s_setreg_b32 hwreg(5, 1, 31), s2
|
||||||
|
// SICI: s_setreg_b32 hwreg(5, 1, 31), s2 ; encoding: [0x45,0xf0,0x82,0xb9]
|
||||||
|
// VI: s_setreg_b32 hwreg(5, 1, 31), s2 ; encoding: [0x45,0xf0,0x02,0xb9]
|
||||||
|
|
||||||
s_setreg_imm32_b32 0x6, 0xff
|
s_setreg_imm32_b32 0x6, 0xff
|
||||||
// SICI: s_setreg_imm32_b32 0x6, 0xff ; encoding: [0x06,0x00,0x80,0xba,0xff,0x00,0x00,0x00]
|
// SICI: s_setreg_imm32_b32 hwreg(6, 0, 1), 0xff ; encoding: [0x06,0x00,0x80,0xba,0xff,0x00,0x00,0x00]
|
||||||
// VI: s_setreg_imm32_b32 0x6, 0xff ; encoding: [0x06,0x00,0x00,0xba,0xff,0x00,0x00,0x00]
|
// VI: s_setreg_imm32_b32 hwreg(6, 0, 1), 0xff ; encoding: [0x06,0x00,0x00,0xba,0xff,0x00,0x00,0x00]
|
||||||
|
|
||||||
|
s_setreg_imm32_b32 hwreg(5, 1, 31), 0xff
|
||||||
|
// SICI: s_setreg_imm32_b32 hwreg(5, 1, 31), 0xff ; encoding: [0x45,0xf0,0x80,0xba,0xff,0x00,0x00,0x00]
|
||||||
|
// VI: s_setreg_imm32_b32 hwreg(5, 1, 31), 0xff ; encoding: [0x45,0xf0,0x00,0xba,0xff,0x00,0x00,0x00]
|
||||||
|
@ -48,11 +48,11 @@
|
|||||||
# VI: s_cbranch_i_fork s[2:3], 0x6 ; encoding: [0x06,0x00,0x02,0xb8]
|
# VI: s_cbranch_i_fork s[2:3], 0x6 ; encoding: [0x06,0x00,0x02,0xb8]
|
||||||
0x06 0x00 0x02 0xb8
|
0x06 0x00 0x02 0xb8
|
||||||
|
|
||||||
# VI: s_getreg_b32 s2, 0x6 ; encoding: [0x06,0x00,0x82,0xb8]
|
# VI: s_getreg_b32 s2, hwreg(6) ; encoding: [0x06,0xf8,0x82,0xb8]
|
||||||
0x06 0x00 0x82 0xb8
|
0x06 0xf8 0x82 0xb8
|
||||||
|
|
||||||
# VI: s_setreg_b32 0x6, s2 ; encoding: [0x06,0x00,0x02,0xb9]
|
# VI: s_setreg_b32 hwreg(6, 0, 1), s2 ; encoding: [0x06,0x00,0x02,0xb9]
|
||||||
0x06 0x00 0x02 0xb9
|
0x06 0x00 0x02 0xb9
|
||||||
|
|
||||||
# VI: s_setreg_imm32_b32 0x6, 0xff ; encoding: [0x06,0x00,0x00,0xba,0xff,0x00,0x00,0x00]
|
# VI: s_setreg_imm32_b32 hwreg(5, 1, 31), 0xff ; encoding: [0x45,0xf0,0x00,0xba,0xff,0x00,0x00,0x00]
|
||||||
0x06 0x00 0x00 0xba 0xff 0x00 0x00 0x00
|
0x45 0xf0 0x00 0xba 0xff 0x00 0x00 0x00
|
||||||
|
Loading…
x
Reference in New Issue
Block a user