Skip to content

Commit af70618

Browse files
koachanbrad0
authored andcommitted
[SPARC][IAS] Add complete set of v9 ASI load, store & swap forms
This extends support for ASI-tagged loads, stores, and swaps with the new stored-ASI form ([reg+imm] %asi) introduced in v9. CAS instructions are handled differently by the (dis-)assembler, so it will be handled in a separate patch. Reviewed By: barannikov88 Differential Revision: https://reviews.llvm.org/D157233
1 parent 2f3a362 commit af70618

File tree

12 files changed

+362
-45
lines changed

12 files changed

+362
-45
lines changed

llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp

Lines changed: 94 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/ADT/STLExtras.h"
1313
#include "llvm/ADT/SmallVector.h"
1414
#include "llvm/ADT/StringRef.h"
15+
#include "llvm/MC/MCAsmMacro.h"
1516
#include "llvm/MC/MCContext.h"
1617
#include "llvm/MC/MCExpr.h"
1718
#include "llvm/MC/MCInst.h"
@@ -88,6 +89,8 @@ class SparcAsmParser : public MCTargetAsmParser {
8889

8990
OperandMatchResultTy parseMembarTag(OperandVector &Operands);
9091

92+
OperandMatchResultTy parseASITag(OperandVector &Operands);
93+
9194
template <TailRelocKind Kind>
9295
OperandMatchResultTy parseTailRelocSym(OperandVector &Operands);
9396

@@ -238,7 +241,8 @@ class SparcOperand : public MCParsedAsmOperand {
238241
k_Register,
239242
k_Immediate,
240243
k_MemoryReg,
241-
k_MemoryImm
244+
k_MemoryImm,
245+
k_ASITag
242246
} Kind;
243247

244248
SMLoc StartLoc, EndLoc;
@@ -268,6 +272,7 @@ class SparcOperand : public MCParsedAsmOperand {
268272
struct RegOp Reg;
269273
struct ImmOp Imm;
270274
struct MemOp Mem;
275+
unsigned ASI;
271276
};
272277

273278
public:
@@ -280,6 +285,7 @@ class SparcOperand : public MCParsedAsmOperand {
280285
bool isMEMrr() const { return Kind == k_MemoryReg; }
281286
bool isMEMri() const { return Kind == k_MemoryImm; }
282287
bool isMembarTag() const { return Kind == k_Immediate; }
288+
bool isASITag() const { return Kind == k_ASITag; }
283289
bool isTailRelocSym() const { return Kind == k_Immediate; }
284290

285291
bool isCallTarget() const {
@@ -359,6 +365,11 @@ class SparcOperand : public MCParsedAsmOperand {
359365
return Mem.Off;
360366
}
361367

368+
unsigned getASITag() const {
369+
assert((Kind == k_ASITag) && "Invalid access!");
370+
return ASI;
371+
}
372+
362373
/// getStartLoc - Get the location of the first token of this operand.
363374
SMLoc getStartLoc() const override {
364375
return StartLoc;
@@ -379,6 +390,9 @@ class SparcOperand : public MCParsedAsmOperand {
379390
OS << "Mem: " << getMemBase()
380391
<< "+" << *getMemOff()
381392
<< "\n"; break;
393+
case k_ASITag:
394+
OS << "ASI tag: " << getASITag() << "\n";
395+
break;
382396
}
383397
}
384398

@@ -430,6 +444,11 @@ class SparcOperand : public MCParsedAsmOperand {
430444
addExpr(Inst, Expr);
431445
}
432446

447+
void addASITagOperands(MCInst &Inst, unsigned N) const {
448+
assert(N == 1 && "Invalid number of operands!");
449+
Inst.addOperand(MCOperand::createImm(getASITag()));
450+
}
451+
433452
void addMembarTagOperands(MCInst &Inst, unsigned N) const {
434453
assert(N == 1 && "Invalid number of operands!");
435454
const MCExpr *Expr = getImm();
@@ -474,6 +493,15 @@ class SparcOperand : public MCParsedAsmOperand {
474493
return Op;
475494
}
476495

496+
static std::unique_ptr<SparcOperand> CreateASITag(unsigned Val, SMLoc S,
497+
SMLoc E) {
498+
auto Op = std::make_unique<SparcOperand>(k_ASITag);
499+
Op->ASI = Val;
500+
Op->StartLoc = S;
501+
Op->EndLoc = E;
502+
return Op;
503+
}
504+
477505
static bool MorphToIntPairReg(SparcOperand &Op) {
478506
unsigned Reg = Op.getReg();
479507
assert(Op.Reg.Kind == rk_IntReg);
@@ -1080,6 +1108,29 @@ OperandMatchResultTy SparcAsmParser::parseMembarTag(OperandVector &Operands) {
10801108
return MatchOperand_Success;
10811109
}
10821110

1111+
OperandMatchResultTy SparcAsmParser::parseASITag(OperandVector &Operands) {
1112+
SMLoc S = Parser.getTok().getLoc();
1113+
SMLoc E = Parser.getTok().getEndLoc();
1114+
int64_t ASIVal = 0;
1115+
1116+
if (getParser().parseAbsoluteExpression(ASIVal)) {
1117+
Error(
1118+
S,
1119+
is64Bit()
1120+
? "malformed ASI tag, must be %asi or a constant integer expression"
1121+
: "malformed ASI tag, must be a constant integer expression");
1122+
return MatchOperand_ParseFail;
1123+
}
1124+
1125+
if (!isUInt<8>(ASIVal)) {
1126+
Error(S, "invalid ASI number, must be between 0 and 255");
1127+
return MatchOperand_ParseFail;
1128+
}
1129+
1130+
Operands.push_back(SparcOperand::CreateASITag(ASIVal, S, E));
1131+
return MatchOperand_Success;
1132+
}
1133+
10831134
OperandMatchResultTy SparcAsmParser::parseCallTarget(OperandVector &Operands) {
10841135
SMLoc S = Parser.getTok().getLoc();
10851136
SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
@@ -1154,13 +1205,49 @@ SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
11541205
Parser.Lex(); // Eat the ]
11551206

11561207
// Parse an optional address-space identifier after the address.
1157-
if (getLexer().is(AsmToken::Integer)) {
1158-
std::unique_ptr<SparcOperand> Op;
1159-
ResTy = parseSparcAsmOperand(Op, false);
1160-
if (ResTy != MatchOperand_Success || !Op)
1161-
return MatchOperand_ParseFail;
1162-
Operands.push_back(std::move(Op));
1208+
// This will be either an immediate constant expression, or, on 64-bit
1209+
// processors, the %asi register.
1210+
if (is64Bit() && getLexer().is(AsmToken::Percent)) {
1211+
SMLoc S = Parser.getTok().getLoc();
1212+
Parser.Lex(); // Eat the %.
1213+
const AsmToken Tok = Parser.getTok();
1214+
if (Tok.is(AsmToken::Identifier) && Tok.getString() == "asi") {
1215+
// Here we patch the MEM operand from [base + %g0] into [base + 0]
1216+
// as memory operations with ASI tag stored in %asi register needs
1217+
// to use immediate offset. We need to do this because Reg addressing
1218+
// will be parsed as Reg+G0 initially.
1219+
// This allows forms such as `ldxa [%o0] %asi, %o0` to parse correctly.
1220+
SparcOperand &OldMemOp = (SparcOperand &)*Operands[Operands.size() - 2];
1221+
if (OldMemOp.isMEMrr()) {
1222+
if (OldMemOp.getMemOffsetReg() != Sparc::G0) {
1223+
Error(S, "invalid operand for instruction");
1224+
return MatchOperand_ParseFail;
1225+
}
1226+
Operands[Operands.size() - 2] = SparcOperand::MorphToMEMri(
1227+
OldMemOp.getMemBase(),
1228+
SparcOperand::CreateImm(MCConstantExpr::create(0, getContext()),
1229+
OldMemOp.getStartLoc(),
1230+
OldMemOp.getEndLoc()));
1231+
}
1232+
Parser.Lex(); // Eat the identifier.
1233+
// In this context, we convert the register operand into
1234+
// a plain "%asi" token since the register access is already
1235+
// implicit in the instruction definition and encoding.
1236+
// See LoadASI/StoreASI in SparcInstrInfo.td.
1237+
Operands.push_back(SparcOperand::CreateToken("%asi", S));
1238+
return MatchOperand_Success;
1239+
}
1240+
1241+
Error(S,
1242+
"malformed ASI tag, must be %asi or a constant integer expression");
1243+
return MatchOperand_ParseFail;
11631244
}
1245+
1246+
// If we're not at the end of statement and the next token is not a comma,
1247+
// then it is an immediate ASI value.
1248+
if (getLexer().isNot(AsmToken::EndOfStatement) &&
1249+
getLexer().isNot(AsmToken::Comma))
1250+
return parseASITag(Operands);
11641251
return MatchOperand_Success;
11651252
}
11661253

llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,10 @@ DecodeStatus SparcDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
306306
{
307307
Result = decodeInstruction(DecoderTableSparcV832, Instr, Insn, Address, this, STI);
308308
}
309-
if (Result != MCDisassembler::Fail)
309+
if (Result != MCDisassembler::Fail) {
310+
Size = 4;
310311
return Result;
312+
}
311313

312314
Result =
313315
decodeInstruction(DecoderTableSparc32, Instr, Insn, Address, this, STI);

llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,9 @@ void SparcInstPrinter::printMembarTag(const MCInst *MI, int opNum,
251251
}
252252
}
253253
}
254+
255+
void SparcInstPrinter::printASITag(const MCInst *MI, int opNum,
256+
const MCSubtargetInfo &STI, raw_ostream &O) {
257+
unsigned Imm = MI->getOperand(opNum).getImm();
258+
O << Imm;
259+
}

llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class SparcInstPrinter : public MCInstPrinter {
5454
raw_ostream &OS);
5555
void printMembarTag(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
5656
raw_ostream &O);
57+
void printASITag(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
58+
raw_ostream &O);
5759
};
5860
} // end namespace llvm
5961

llvm/lib/Target/Sparc/SparcInstr64Bit.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def UDIVXri : F3_2<2, 0b001101,
239239
let Predicates = [Is64Bit] in {
240240

241241
// 64-bit loads.
242-
defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>;
242+
defm LDX : LoadA<"ldx", 0b001011, 0b011011, load, I64Regs, i64>;
243243

244244
let mayLoad = 1, isAsmParserOnly = 1 in {
245245
def TLS_LDXrr : F3_1<3, 0b001011,
@@ -282,10 +282,10 @@ def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr ADDRrr:$addr)>;
282282
def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;
283283

284284
// Sign-extending load of i32 into i64 is a new SPARC v9 instruction.
285-
defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>;
285+
defm LDSW : LoadA<"ldsw", 0b001000, 0b011000, sextloadi32, I64Regs, i64>;
286286

287287
// 64-bit stores.
288-
defm STX : Store<"stx", 0b001110, store, I64Regs, i64>;
288+
defm STX : StoreA<"stx", 0b001110, 0b011110, store, I64Regs, i64>;
289289

290290
// Truncating stores from i64 are identical to the i32 stores.
291291
def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>;

0 commit comments

Comments
 (0)