Skip to content

Commit

Permalink
[DPWBS-1120] feat(SystemOperands): add support for named CSFRs
Browse files Browse the repository at this point in the history
This commit adds support for using named system registers (e.g. $psw) in
instructions which support a uimm16 immediate operand. Named system
registers are parsed and printed as an immediate. MFCR, MTCR, MFDCR and
MTDCR print the system register names.

For these instructions an immediate input is interpreted and printed as
a named system register, if a register matching the encoding is known.

add assembler tests for named system register operands
  • Loading branch information
gargaroff committed Feb 6, 2020
1 parent 63783c1 commit 3466b4b
Show file tree
Hide file tree
Showing 23 changed files with 2,508 additions and 107 deletions.
2 changes: 1 addition & 1 deletion llvm/lib/Target/TriCore/AsmParser/LLVMBuild.txt
Expand Up @@ -18,5 +18,5 @@
type = Library
name = TriCoreAsmParser
parent = TriCore
required_libraries = MC MCParser TriCoreAsmPrinter TriCoreDesc TriCoreInfo Support
required_libraries = MC MCParser TriCoreAsmPrinter TriCoreDesc TriCoreInfo TriCoreUtils Support
add_to_library_groups = TriCore
140 changes: 129 additions & 11 deletions llvm/lib/Target/TriCore/AsmParser/TriCoreAsmParser.cpp
Expand Up @@ -10,6 +10,7 @@
#include "MCTargetDesc/TriCoreMCExpr.h"
#include "MCTargetDesc/TriCoreMCTargetDesc.h"
#include "TargetInfo/TriCoreTargetInfo.h"
#include "Utils/TriCoreBaseInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCContext.h"
Expand Down Expand Up @@ -47,6 +48,9 @@ class TriCoreAsmParser : public MCTargetAsmParser {

bool ParseDirective(AsmToken DirectiveID) override;

bool validateInstruction(MCInst &Inst, SMLoc &IDLoc,
SmallVectorImpl<SMLoc> &OpLoc);

// Auto-generated instruction matching functions
#define GET_ASSEMBLER_HEADER
#include "TriCoreGenAsmMatcher.inc"
Expand All @@ -55,6 +59,8 @@ class TriCoreAsmParser : public MCTargetAsmParser {
OperandMatchResultTy parseRegister(OperandVector &Operands);
OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands);
OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands);
OperandMatchResultTy parseSystemRegister(OperandVector &Operands,
const SMLoc &S, const SMLoc &E);

bool parseOperand(OperandVector &Operands);

Expand Down Expand Up @@ -372,8 +378,7 @@ struct TriCoreOperand : public MCParsedAsmOperand {
return IsValid && VK == TriCoreMCExpr::VK_TRICORE_None;
}

// checking if in the range of 16 bit unsigned immediate
bool isUImm16Shift3() const {
template <unsigned S> bool isUImm16ShiftS() const {
int64_t Imm;
TriCoreMCExpr::VariantKind VK = TriCoreMCExpr::VK_TRICORE_None;
bool IsValid;
Expand All @@ -386,11 +391,17 @@ struct TriCoreOperand : public MCParsedAsmOperand {
if (!IsConstantImm)
IsValid = false; // symbols for this operand type is not allowed yet
else
IsValid = isShiftedUInt<13, 3>(Imm);
IsValid = isShiftedUInt<16 - S, S>(Imm);

return IsValid && VK == TriCoreMCExpr::VK_TRICORE_None;
}

// checking if in the range of 16 bit unsigned immediate
bool isSysReg() const { return isUImm16ShiftS<2>(); }

// checking if in the range of 16 bit unsigned immediate
bool isDoubleSysReg() const { return isUImm16ShiftS<3>(); }

// checking if in the range of 2 bit unsigned immediate
bool isUImm2_l() const {
int64_t Imm;
Expand Down Expand Up @@ -517,6 +528,63 @@ bool TriCoreAsmParser::generateImmOutOfRangeError(
return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
}

bool isReadableSysReg(uint16_t Encoding) {
const auto *SysReg = TriCoreSysReg::lookupSysRegByEncoding(Encoding);

// Cannot say anything if unnamed system register
if (!SysReg)
return true;

return SysReg->Readable;
}

bool isWriteableSysReg(uint16_t Encoding) {
const auto *SysReg = TriCoreSysReg::lookupSysRegByEncoding(Encoding);

// Cannot say anything if unnamed system register
if (!SysReg)
return true;

return SysReg->Writeable;
}

bool TriCoreAsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc,
SmallVectorImpl<SMLoc> &OpLoc) {
const unsigned OpCode = Inst.getOpcode();
switch (OpCode) {
default:
return false;
case TriCore::MFCR_dc:
case TriCore::MTCR_dc:
case TriCore::MFDCR_ec:
case TriCore::MTDCR_ce: {
const bool ReadsReg =
OpCode == TriCore::MFCR_dc || OpCode == TriCore::MFDCR_ec;
const bool IsDouble =
OpCode == TriCore::MFDCR_ec || OpCode == TriCore::MTDCR_ce;

const unsigned ImmIdx = ReadsReg ? 1 : 0;
const unsigned Encoding = Inst.getOperand(ImmIdx).getImm();

// Check if the immediate operand is a readable/writeable system register
for (unsigned i = 0, e = IsDouble ? 4 : 0; i <= e; i += 4) {
if (ReadsReg && !isReadableSysReg(Encoding + i))
return Error(
OpLoc[ImmIdx],
"MFCR instructions require system register to be readable");

if (!ReadsReg && !isWriteableSysReg(Encoding + i))
return Error(
OpLoc[ImmIdx],
"MTCR instructions require system register to be writeable");
}

// All operands valid
return false;
}
}
}

bool TriCoreAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
MCStreamer &Out,
Expand All @@ -528,14 +596,24 @@ bool TriCoreAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
default:
break;
case Match_Success:
case Match_Success: {
// Perform semantic validations
SmallVector<SMLoc, 8> OperandLocs;
const unsigned NumOperands = Operands.size();
for (unsigned i = 1; i < NumOperands; ++i)
OperandLocs.push_back(Operands[i]->getStartLoc());

if (validateInstruction(Inst, IDLoc, OperandLocs))
return true;

Inst.setLoc(IDLoc);
Out.EmitInstruction(Inst, getSTI());
if (!(getSTI().getFeatureBits()[TriCore::Only32BitInstructions])) {
setFeatureBits(TriCore::Allow16BitInstructions, "allow-16bit");
setFeatureBits(TriCore::Allow32BitInstructions, "allow-32bit");
}
return false;
}
case Match_MissingFeature:
return Error(IDLoc, "instruction use requires an option to be enabled");
case Match_MnemonicFail:
Expand Down Expand Up @@ -606,10 +684,16 @@ bool TriCoreAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
Operands, ErrorInfo, -(1 << 4), (1 << 4) - 1,
"Operand prefixes and symbol expressions are not allowed for this "
"operand and it must be in the integer range");
case Match_InvalidUImm16Shift3:
case Match_InvalidSysReg:
return generateImmOutOfRangeError(
Operands, ErrorInfo, 0, (1 << 16) - 4,
"Operand must be a valid system register or a 4-aligned integer and "
"in the range");
case Match_InvalidDoubleSysReg:
return generateImmOutOfRangeError(
Operands, ErrorInfo, 0, (1 << 16) - 8,
"Operand must be an 8-aligned integer and in the range");
"Operand must be a valid system register or an 8-aligned integer and "
"in the range");
case Match_InvalidSImm10:
return generateImmOutOfRangeError(
Operands, ErrorInfo, -(1 << 9), (1 << 9) - 1,
Expand All @@ -625,11 +709,6 @@ bool TriCoreAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
Operands, ErrorInfo, -(1 << 15), (1 << 15) - 1,
"Operand must be a valid symbol with optional operand prefix lo or hi "
"OR it must be an the integer in the range");
case Match_InvalidUImm16_RLC:
return generateImmOutOfRangeError(
Operands, ErrorInfo, 0, (1 << 16) - 1,
"Operand must be a valid symbol with optional operand prefix lo or hi "
"OR it must be an the integer in the range");
case Match_InvalidUImm4_Lsb1:
return generateImmOutOfRangeError(
Operands, ErrorInfo, 0, ((1 << 4) - 1) * 2,
Expand Down Expand Up @@ -754,6 +833,41 @@ OperandMatchResultTy TriCoreAsmParser::parseRegister(OperandVector &Operands) {
return MatchOperand_Success;
}

// $<identifier>, e.g. $psw
OperandMatchResultTy
TriCoreAsmParser::parseSystemRegister(OperandVector &Operands, const SMLoc &S,
const SMLoc &E) {
if (getLexer().peekTok(false).isNot(AsmToken::Identifier))
return MatchOperand_NoMatch;

// Consume $
getLexer().Lex();

assert(getLexer().getTok().is(AsmToken::Identifier));
StringRef Identifier;
if (getParser().parseIdentifier(Identifier))
return MatchOperand_ParseFail;

// Try to find a system register by this name, ignoring case
const auto *SysReg = TriCoreSysReg::lookupSysRegByName(Identifier.lower());

// Error if no system register by this name is known
if (!SysReg) {
Error(S, "operand must be a valid system register name or an immediate");
return MatchOperand_ParseFail;
}

// Check if required features are available
if (!SysReg->haveFeatures(getSTI().getFeatureBits())) {
Error(S, "system register use requires an option to be enabled");
return MatchOperand_ParseFail;
}

const auto *CE = MCConstantExpr::create(SysReg->Encoding, getContext(), true);
Operands.push_back(TriCoreOperand::createImm(CE, S, E));
return MatchOperand_Success;
}

OperandMatchResultTy TriCoreAsmParser::parseImmediate(OperandVector &Operands) {
const MCExpr *IdVal;
SMLoc S = getLoc();
Expand All @@ -772,6 +886,10 @@ OperandMatchResultTy TriCoreAsmParser::parseImmediate(OperandVector &Operands) {
if (!parseOperandWithModifier(Operands))
return MatchOperand_Success;
break;
case AsmToken::Dollar:
// System registers begin with a dollar sign and are short-hands for
// immediates. Try to parse one
return parseSystemRegister(Operands, S, E);
}

if (getParser().parseExpression(IdVal))
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Target/TriCore/CMakeLists.txt
Expand Up @@ -10,6 +10,7 @@ tablegen(LLVM TriCoreGenGlobalISel.inc -gen-global-isel)
tablegen(LLVM TriCoreGenRegisterBank.inc -gen-register-bank)
tablegen(LLVM TriCoreGenCallingConv.inc -gen-callingconv)
tablegen(LLVM TriCoreGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM TriCoreGenSystemOperands.inc -gen-searchable-tables)

add_public_tablegen_target(TriCoreCommonTableGen)

Expand All @@ -33,4 +34,5 @@ add_subdirectory(AsmParser)
add_subdirectory(Disassembler)
add_subdirectory(InstPrinter)
add_subdirectory(MCTargetDesc)
add_subdirectory(TargetInfo)
add_subdirectory(TargetInfo)
add_subdirectory(Utils)
10 changes: 5 additions & 5 deletions llvm/lib/Target/TriCore/Disassembler/TriCoreDisassembler.cpp
Expand Up @@ -78,10 +78,10 @@ static DecodeStatus decodeSImm9Shift(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder);

static DecodeStatus decodeSImm9Shift5(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder);
int64_t Address, const void *Decoder);

static DecodeStatus decodeUImm16Shift3(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder);
static DecodeStatus decodeSysReg(MCInst &Inst, uint64_t Imm, int64_t Address,
const void *Decoder);

static DecodeStatus decodeOff18Abs(MCInst &Inst, uint64_t Imm, int64_t Address,
const void *Decoder);
Expand Down Expand Up @@ -295,8 +295,8 @@ static DecodeStatus decodeSImm9Shift5(MCInst &Inst, uint64_t Imm,
return MCDisassembler::Success;
}

static DecodeStatus decodeUImm16Shift3(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
static DecodeStatus decodeSysReg(MCInst &Inst, uint64_t Imm, int64_t Address,
const void *Decoder) {
assert(isUInt<16>(Imm) && "Invalid unsigned 16 bit shift value");
Inst.addOperand(MCOperand::createImm(Imm));
return MCDisassembler::Success;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/TriCore/InstPrinter/LLVMBuild.txt
Expand Up @@ -18,5 +18,5 @@
type = Library
name = TriCoreAsmPrinter
parent = TriCore
required_libraries = MC Support
required_libraries = MC Support TriCoreUtils
add_to_library_groups = TriCore
17 changes: 15 additions & 2 deletions llvm/lib/Target/TriCore/InstPrinter/TriCoreInstPrinter.cpp
Expand Up @@ -12,15 +12,16 @@
//===----------------------------------------------------------------------===//

#include "TriCoreInstPrinter.h"
#include "Utils/TriCoreBaseInfo.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"

using namespace llvm;

#define DEBUG_TYPE "asm-printer"
Expand Down Expand Up @@ -57,4 +58,16 @@ void TriCoreInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,

assert(MO.isExpr() && "Unknown operand kind in printOperand");
MO.getExpr()->print(O, &MAI);
}
}

void TriCoreInstPrinter::printSystemRegister(const MCInst *MI,
unsigned int OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
const unsigned Imm = MI->getOperand(OpNo).getImm();
const auto *SysReg = TriCoreSysReg::lookupSysRegByEncoding(Imm);
if (SysReg && SysReg->haveFeatures(STI.getFeatureBits()))
O << '$' << SysReg->Name;
else
O << Imm;
}
3 changes: 3 additions & 0 deletions llvm/lib/Target/TriCore/InstPrinter/TriCoreInstPrinter.h
Expand Up @@ -33,6 +33,9 @@ class TriCoreInstPrinter : public MCInstPrinter {
void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
raw_ostream &O, const char *Modifier = nullptr);

void printSystemRegister(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);

// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, uint64_t Address,
const MCSubtargetInfo &STI, raw_ostream &O);
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/TriCore/LLVMBuild.txt
Expand Up @@ -15,7 +15,7 @@
;===------------------------------------------------------------------------===;

[common]
subdirectories = AsmParser Disassembler InstPrinter TargetInfo MCTargetDesc
subdirectories = AsmParser Disassembler InstPrinter TargetInfo MCTargetDesc Utils

[component_0]
type = TargetGroup
Expand All @@ -29,5 +29,5 @@ has_disassembler = 1
type = Library
name = TriCoreCodeGen
parent = TriCore
required_libraries = AsmPrinter Core CodeGen MC TriCoreAsmPrinter TriCoreDesc TriCoreInfo Support Target SelectionDAG GlobalISel
required_libraries = AsmPrinter Core CodeGen MC TriCoreAsmPrinter TriCoreDesc TriCoreInfo TriCoreUtils Support Target SelectionDAG GlobalISel
add_to_library_groups = TriCore
6 changes: 6 additions & 0 deletions llvm/lib/Target/TriCore/TriCore.td
Expand Up @@ -25,6 +25,12 @@ include "TriCoreGISelPattern.td"

def TriCoreInstrInfo : InstrInfo;

//===----------------------------------------------------------------------===//
// Named operands for instructions using system registers.
//===----------------------------------------------------------------------===//

include "TriCoreSystemOperands.td"

//===----------------------------------------------------------------------===//
// Assembly parser.
//===----------------------------------------------------------------------===//
Expand Down
16 changes: 12 additions & 4 deletions llvm/lib/Target/TriCore/TriCoreInstrInfoOperands.td
Expand Up @@ -90,9 +90,17 @@ def uimm2_l : Operand<OtherVT> {
def uimm3 : GenericUnsignedImmediate<3>;

// A 16 bit unsigned immediate left-shifted by 3
def uimm16_shift3 : Operand<OtherVT> {
let ParserMatchClass = GenericImmOperand<"UImm16Shift3">;
let DecoderMethod = "decodeUImm16Shift3";
def sysreg : Operand<OtherVT> {
let ParserMatchClass = GenericImmOperand<"SysReg">;
let DecoderMethod = "decodeSysReg";
let PrintMethod = "printSystemRegister";
}

// A 16 bit unsigned immediate left-shifted by 3
def double_sysreg : Operand<OtherVT> {
let ParserMatchClass = GenericImmOperand<"DoubleSysReg">;
let DecoderMethod = "decodeSysReg";
let PrintMethod = "printSystemRegister";
}

// A 4-bit signed immediate.
Expand Down Expand Up @@ -211,4 +219,4 @@ def disp24_abs : Operand<OtherVT> {
let ParserMatchClass = GenericImmOperand<"Disp24Abs">;
let EncoderMethod = "getDisp24Abs";
let DecoderMethod = "decodeDisp24Abs";
}
}

0 comments on commit 3466b4b

Please sign in to comment.