Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 8 additions & 18 deletions llvm/lib/Target/Sparc/SparcASITags.td
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,19 @@

include "llvm/TableGen/SearchableTable.td"

class ASITag<string name, string alt_name, bits<8> op> {
// Capstone edit:
// This is changed to a Searchable Table.
// Simply because emitting generic tables with the PrinterCapstone class
// is not implemented (and is annoying to do so).

class ASITag<string name, string alt_name, bits<8> op> : SearchableTable {
string Name = name;
// A maximum of one alias is supported right now.
string AltName = alt_name;
bits<8> Encoding = op;
}

def ASITagsList : GenericTable {
let FilterClass = "ASITag";
let Fields = ["Name", "AltName", "Encoding"];

let PrimaryKey = [ "Encoding" ];
let PrimaryKeyName = "lookupASITagByEncoding";
}

def lookupASITagByName : SearchIndex {
let Table = ASITagsList;
let Key = [ "Name" ];
}
let EnumValueField = "Encoding";

def lookupASITagByAltName : SearchIndex {
let Table = ASITagsList;
let Key = [ "AltName" ];
let SearchableFields = ["Name", "AltName", "Encoding"];
}

def : ASITag<"ASI_N", "ASI_NUCLEUS", 0x4>;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/Sparc/SparcInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern,
: Instruction {
field bits<32> Inst;

let Namespace = "SP";
let Namespace = "Sparc";
let Size = 4;

bits<2> op;
Expand Down
18 changes: 15 additions & 3 deletions llvm/lib/Target/Sparc/SparcInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ include "SparcInstrFormats.td"
def Is32Bit : Predicate<"!Subtarget->is64Bit()">;

// True when generating 64-bit code. This also implies HasV9.
def Is64Bit : Predicate<"Subtarget->is64Bit()">;
def Is64Bit : Predicate<"Subtarget->is64Bit()">,
AssemblerPredicate<(all_of FeatureV9)>;

def UseSoftMulDiv : Predicate<"Subtarget->useSoftMulDiv()">,
AssemblerPredicate<(all_of FeatureSoftMulDiv)>;
Expand Down Expand Up @@ -146,11 +147,13 @@ def MEMrr : Operand<iPTR> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops ptr_rc, ptr_rc);
let ParserMatchClass = SparcMEMrrAsmOperand;
let OperandType = "OPERAND_MEMORY";
}
def MEMri : Operand<iPTR> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops ptr_rc, i32imm);
let ParserMatchClass = SparcMEMriAsmOperand;
let OperandType = "OPERAND_MEMORY";
}

// Represents a tail relocation operand for instructions such as add, ld, call.
Expand Down Expand Up @@ -200,14 +203,20 @@ def ASITag : Operand<i32> {
// Branch targets have OtherVT type.
def brtarget : Operand<OtherVT> {
let EncoderMethod = "getBranchTargetOpValue";
let DecoderMethod = "DecodeDisp22";
let OperandType = "OPERAND_IMMEDIATE";
}

def bprtarget : Operand<OtherVT> {
let EncoderMethod = "getBranchPredTargetOpValue";
let DecoderMethod = "DecodeDisp19";
let OperandType = "OPERAND_IMMEDIATE";
}

def bprtarget16 : Operand<OtherVT> {
let EncoderMethod = "getBranchOnRegTargetOpValue";
let DecoderMethod = "DecodeDisp16";
let OperandType = "OPERAND_IMMEDIATE";
}

def SparcCallTargetAsmOperand : AsmOperandClass {
Expand Down Expand Up @@ -419,6 +428,7 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val, InstrItinClass itin = IIC_iu_i
itin>;
}

let mayLoad = 1 in {
// Load multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot.
multiclass Load<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode,
RegisterClass RC, ValueType Ty, InstrItinClass itin = IIC_iu_instr> {
Expand Down Expand Up @@ -470,7 +480,9 @@ let Predicates = [HasV9], Uses = [ASR3] in
def LDSTUBAri : F3_2<3, 0b011101, (outs IntRegs:$rd),
(ins (MEMri $rs1, $simm13):$addr),
"ldstuba [$addr] %asi, $rd", []>;
}

let mayStore = 1 in {
// Store multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot.
multiclass Store<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode,
RegisterClass RC, ValueType Ty, InstrItinClass itin = IIC_st> {
Expand Down Expand Up @@ -507,6 +519,7 @@ multiclass StoreA<string OpcStr, bits<6> Op3Val, bits<6> StoreAOp3Val,
Store<OpcStr, Op3Val, OpNode, RC, Ty> {
defm A : StoreASI<OpcStr, StoreAOp3Val, RC>;
}
}

//===----------------------------------------------------------------------===//
// Instructions
Expand Down Expand Up @@ -882,8 +895,7 @@ class BranchPredictAlways<dag ins, string asmstr, list<dag> pattern>
: F2_3<0b001, 0, 1, (outs), ins, asmstr, pattern>;
}

let cond = 8 in
def BA : BranchAlways<(ins brtarget:$imm22), "ba $imm22", [(br bb:$imm22)]>;
// Capstone: Remove BA which is already correctly defined as Alias.

let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in {

Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/Target/Sparc/SparcRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@

class SparcReg<bits<16> Enc, string n> : Register<n> {
let HWEncoding = Enc;
let Namespace = "SP";
let Namespace = "Sparc";
}

class SparcCtrlReg<bits<16> Enc, string n,
list<string> altNames = []>: Register<n, altNames> {
let HWEncoding = Enc;
let Namespace = "SP";
let Namespace = "Sparc";
}

let Namespace = "SP" in {
let Namespace = "Sparc" in {
def sub_even : SubRegIndex<32>;
def sub_odd : SubRegIndex<32, 32>;
def sub_even64 : SubRegIndex<64>;
def sub_odd64 : SubRegIndex<64, 64>;
}

let Namespace = "SP",
let Namespace = "Sparc",
FallbackRegAltNameIndex = NoRegAltName in {
def RegNamesStateReg : RegAltNameIndex;
}
Expand Down
87 changes: 69 additions & 18 deletions llvm/utils/TableGen/PrinterCapstone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,12 +303,12 @@ void PrinterCapstone::regInfoEmitRegUnitRoots(
}

static std::string getQualifiedNameCCS(const Record *R) {
std::string Namespace;
StringRef TargetName;
if (R->getValue("Namespace"))
Namespace = std::string(R->getValueAsString("Namespace"));
if (Namespace.empty())
TargetName = R->getValueAsString("Namespace");
if (TargetName.empty())
return std::string(R->getName());
return StringRef(Namespace).str() + "_" + R->getName().str();
return TargetName.str() + "_" + R->getName().str();
}

void PrinterCapstone::regInfoEmitRegClasses(
Expand Down Expand Up @@ -1116,7 +1116,7 @@ void PrinterCapstone::decoderEmitterEmitDecodeInstruction(
std::set<std::string> InsnBytesAsUint24 = {"Xtensa"};
std::set<std::string> InsnBytesAsUint32 = {"ARM", "AArch64", "LoongArch",
"Alpha", "Mips", "TriCore",
"ARC"};
"ARC", "Sparc"};
std::set<std::string> InsnBytesAsUint64 = {"SystemZ", "ARC"};
bool MacroDefined = false;
if (InsnBytesAsUint16.find(TargetName) != InsnBytesAsUint16.end()) {
Expand Down Expand Up @@ -1696,15 +1696,16 @@ void PrinterCapstone::asmWriterEmitRegAsmOffsets(
void PrinterCapstone::asmWriterEmitAltIdxSwitch(
bool HasAltNames, std::vector<Record *> const &AltNameIndices,
StringRef const &Namespace) const {
StringRef TargetName = Namespace;
if (HasAltNames) {
OS << " switch(AltIdx) {\n"
<< " default: CS_ASSERT_RET_VAL(0 && \"Invalid register alt name "
"index!\", NULL);\n";
for (const Record *R : AltNameIndices) {
StringRef const AltName = R->getName();
OS << " case ";
if (!Namespace.empty())
OS << Namespace << "_";
if (!TargetName.empty())
OS << TargetName << "_";
OS << AltName << ":\n";
if (R->isValueUnset("FallbackRegAltNameIndex"))
OS << " CS_ASSERT_RET_VAL(*(AsmStrs" << AltName << "+RegAsmOffset"
Expand All @@ -1714,8 +1715,8 @@ void PrinterCapstone::asmWriterEmitAltIdxSwitch(
OS << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName
<< "[RegNo-1]))\n"
<< " return getRegisterName(RegNo, ";
if (!Namespace.empty())
OS << Namespace << "_";
if (!TargetName.empty())
OS << TargetName << "_";
OS << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n";
}
OS << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName
Expand Down Expand Up @@ -2520,7 +2521,8 @@ void PrinterCapstone::instrInfoEmitGetOpMemSizeTbl(
std::string
PrinterCapstone::instrInfoGetInstMapEntry(StringRef const &Namespace,
StringRef const &InstrName) const {
return Namespace.str() + "_" + InstrName.str();
StringRef TargetName = Namespace;
return TargetName.str() + "_" + InstrName.str();
}

void PrinterCapstone::instrInfoEmitGetLogicalOpSizeHdr() const {}
Expand Down Expand Up @@ -2602,11 +2604,12 @@ void PrinterCapstone::instrInfoEmitEnums(
CodeGenTarget const &Target, StringRef const &Namespace,
CodeGenSchedModels const &SchedModels) const {
emitIncludeToggle("GET_INSTRINFO_ENUM", true);
StringRef TargetName = Namespace;

unsigned Num = 0;
OS << " enum {\n";
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue())
OS << " " << Namespace << "_" << Inst->TheDef->getName()
OS << " " << TargetName << "_" << Inst->TheDef->getName()
<< "\t= " << Num++ << ",\n";
OS << " INSTRUCTION_LIST_END = " << Num << "\n";
OS << " };\n\n";
Expand Down Expand Up @@ -2657,6 +2660,7 @@ normalizedMnemonic(StringRef const &Mn, const bool Upper = true,
// Each tuple is: Regex Pattern : Replacement char
static SmallVector<std::tuple<std::string, std::string>> Replacements = {
{"[.]", "_"},
{"[,]", "_"},
{"[|]", "_"},
{"[+]", "p"},
{"[-]", "m"},
Expand Down Expand Up @@ -2798,6 +2802,41 @@ std::string getArchSupplInfoPPC(StringRef const &TargetName,
return "{{ 0 }}";
}

std::string getArchSupplInfoSparc(StringRef const &TargetName,
CodeGenInstruction const *CGI,
raw_string_ostream &SparcFormatEnum) {
static std::set<std::string> Formats;
// Get instruction format
ArrayRef<std::pair<Record *, SMRange>> SCs = CGI->TheDef->getSuperClasses();
if (SCs.empty()) {
llvm_unreachable("A CGI without superclass should not exist.");
}

// Get base instruction format class "I"
const Record *PrevSC = nullptr;
// Superclasses are in post-order. So we go through them backwards.
// The class before the "I" class is the format class.
for (int I = SCs.size() - 1; I >= 0; --I) {
const Record *SC = SCs[I].first;
if (SC->getName() == "InstSP" || SC->getName() == "F2" || SC->getName() == "F3" || SC->getName() == "F4") {
// In this case of !PrevSC the instruction inherits directly from InstSP.
// In code they document this is a FOMRAT 1 instruction.
//
// If SC->getName() == "F2...4" we emit the format as well. Because there are many
// F2/F3/F4 encodings, not just one. F2/F3/F4 are the base.
std::string Format = "SPARC_INSN_FORM_" + (!PrevSC ? "F1" : PrevSC->getName().upper());
if (Formats.find(Format) == Formats.end()) {
SparcFormatEnum << Format + ",\n";
}
Formats.emplace(Format);
return "{ .sparc = { " + Format + " }}";
}
PrevSC = SC;
}
// Pseudo instructions
return "{{ 0 }}";
}

std::string getArchSupplInfoSystemZ(StringRef const &TargetName,
CodeGenInstruction const *CGI,
raw_string_ostream &PPCFormatEnum) {
Expand Down Expand Up @@ -2926,6 +2965,8 @@ std::string getArchSupplInfo(StringRef const &TargetName,
return getArchSupplInfoSystemZ(TargetName, CGI, FormatEnum);
} else if (StringRef(TargetName).upper() == "XTENSA") {
return getArchSupplInfoXtensa(TargetName, CGI, FormatEnum);
} else if (StringRef(TargetName).upper() == "SPARC") {
return getArchSupplInfoSparc(TargetName, CGI, FormatEnum);
}
return "{{ 0 }}";
}
Expand Down Expand Up @@ -3084,15 +3125,20 @@ bool opIsPartOfiPTRPattern(Record const *OpRec, StringRef const &OpName,
return false;
}

/// Some operands are wrongly defined as iPTR or other markers we use to identify memory operands.
static inline bool wrongMemClassification(StringRef const &TargetName, StringRef const &OpName) {
return (TargetName.compare_insensitive("Sparc") == 0 && OpName.compare_insensitive("simm13") == 0);
}

std::string getCSOperandType(
StringRef const &TargetName, CodeGenInstruction const *CGI,
Record const *OpRec, StringRef const &OpName,
std::map<std::string, std::vector<Record *>> const InsnPatternMap) {
std::string OperandType = getPrimaryCSOperandType(OpRec);

if ((StringRef(TargetName).upper() == "AARCH64") &&
if ((StringRef(TargetName).upper() == "AARCH64" || StringRef(TargetName).upper() == "SPARC") &&
OperandType != "CS_OP_MEM") {
// The definitions of AArch64 are so flawed, when it comes to memory
// The definitions of AArch64/Sparc are so flawed, when it comes to memory
// operands (they are not labeled as such), that we just search for the op
// name enclosed in [].
if (Regex("\\[[^]]*\\$" + OpName.str() + "[^[]*]").match(CGI->AsmString)) {
Expand All @@ -3107,6 +3153,9 @@ std::string getCSOperandType(
return OperandType += " | CS_OP_BOUND";
}
}
if (wrongMemClassification(TargetName, OpName)) {
return OperandType;
}

DagInit *PatternDag = nullptr;
if (OperandType == "CS_OP_MEM")
Expand Down Expand Up @@ -3711,7 +3760,7 @@ void PrinterCapstone::asmMatcherEmitMatchTable(CodeGenTarget const &Target,
InsnMapFilename = TName + "GenCSAliasMnemMap.inc";
writeFile(InsnMapFilename, AliasMnemMapStr);
if (TName == "PPC" || TName == "LoongArch" || TName == "SystemZ" ||
TName == "Xtensa") {
TName == "Xtensa" || TName == "Sparc") {
InsnMapFilename = TName + "GenCSInsnFormatsEnum.inc";
writeFile(InsnMapFilename, FormatEnumStr);
}
Expand Down Expand Up @@ -3856,7 +3905,7 @@ void PrinterCapstone::asmMatcherEmitComputeAssemblerAvailableFeatures(
AsmMatcherInfo &Info, StringRef const &ClassName) const {}

void PrinterCapstone::searchableTablesWriteFiles() const {
std::string Filename = TargetName + "GenSystemRegister.inc";
std::string Filename = TargetName + "GenSystemOperands.inc";
std::string HeaderStr;
raw_string_ostream Header(HeaderStr);
emitDefaultSourceFileHeader(Header);
Expand Down Expand Up @@ -4026,16 +4075,18 @@ std::string getTableNamespacePrefix(const GenericTable &Table,
{"ARMSysReg", "MClassSysReg"},
{"ARMBankedReg", "BankedReg"},
};
std::set<std::pair<std::string, std::string>> SparcNSTypePairs = {
{"Sparc_ASITag", "ASITag"},
};

std::set<std::pair<std::string, std::string>> *NSTable;

if (StringRef(TargetName).upper() != "AARCH64" && TargetName != "ARM")
return Table.CppTypeName + "_";

if (StringRef(TargetName).upper() == "AARCH64")
NSTable = &AArch64NSTypePairs;
else if (TargetName == "ARM")
NSTable = &ARMNSTypePairs;
else if (StringRef(TargetName).upper() == "SPARC")
NSTable = &SparcNSTypePairs;
else
PrintFatalNote("No Namespace Type table defined for target.");

Expand Down
15 changes: 13 additions & 2 deletions llvm/utils/TableGen/SearchableTableEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,12 +633,23 @@ void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
break;
case PRINTER_LANG_CAPSTONE_C:
Record *IDef = RK.getClass("I");
if (!IDef)
if (!IDef) {
// Sparc's lowest class is InstSP not I
IDef = RK.getClass("InstSP");
}
if (!IDef) {
// If this is reached we need to implement the search for other classes which have Namespace set.
llvm_unreachable("Base instruction class \"I\" does not exist for this target.");
llvm_unreachable("Root instruction class \"I\" does not exist for this target.");
}
if (!IDef->getValue("Namespace"))
llvm_unreachable("Field \"Namespace\" does not exist.");
std::string TName = IDef->getValueAsString("Namespace").str();
if (TName.empty()) {
llvm_unreachable("Field \"Namespace\" is empty, but should be the target name.");
} else if (TName == "SP") {
// Rename namespace nickname.
TName = "Sparc";
}
PI = new PrinterCapstone(FOS, TName);
break;
}
Expand Down
Loading