[llvm] af70618 - [SPARC][IAS] Add complete set of v9 ASI load, store & swap forms
Brad Smith via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 5 01:51:26 PDT 2023
Author: Koakuma
Date: 2023-09-05T04:37:19-04:00
New Revision: af70618e968f17e6c91c425db8bc52bdc81c3a45
URL: https://github.com/llvm/llvm-project/commit/af70618e968f17e6c91c425db8bc52bdc81c3a45
DIFF: https://github.com/llvm/llvm-project/commit/af70618e968f17e6c91c425db8bc52bdc81c3a45.diff
LOG: [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
Added:
llvm/test/MC/Disassembler/Sparc/sparc-mem-v9.txt
llvm/test/MC/Sparc/sparc-mem-asi-instructions.s
Modified:
llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp
llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h
llvm/lib/Target/Sparc/SparcInstr64Bit.td
llvm/lib/Target/Sparc/SparcInstrInfo.td
llvm/test/MC/Sparc/sparc-atomic-instructions.s
llvm/test/MC/Sparc/sparc-mem-instructions.s
llvm/test/MC/Sparc/sparcv9-atomic-instructions.s
llvm/test/MC/Sparc/sparcv9-instructions.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
index 4d64c394f2c6471..69476129abbff5e 100644
--- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -12,6 +12,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCAsmMacro.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
@@ -88,6 +89,8 @@ class SparcAsmParser : public MCTargetAsmParser {
OperandMatchResultTy parseMembarTag(OperandVector &Operands);
+ OperandMatchResultTy parseASITag(OperandVector &Operands);
+
template <TailRelocKind Kind>
OperandMatchResultTy parseTailRelocSym(OperandVector &Operands);
@@ -238,7 +241,8 @@ class SparcOperand : public MCParsedAsmOperand {
k_Register,
k_Immediate,
k_MemoryReg,
- k_MemoryImm
+ k_MemoryImm,
+ k_ASITag
} Kind;
SMLoc StartLoc, EndLoc;
@@ -268,6 +272,7 @@ class SparcOperand : public MCParsedAsmOperand {
struct RegOp Reg;
struct ImmOp Imm;
struct MemOp Mem;
+ unsigned ASI;
};
public:
@@ -280,6 +285,7 @@ class SparcOperand : public MCParsedAsmOperand {
bool isMEMrr() const { return Kind == k_MemoryReg; }
bool isMEMri() const { return Kind == k_MemoryImm; }
bool isMembarTag() const { return Kind == k_Immediate; }
+ bool isASITag() const { return Kind == k_ASITag; }
bool isTailRelocSym() const { return Kind == k_Immediate; }
bool isCallTarget() const {
@@ -359,6 +365,11 @@ class SparcOperand : public MCParsedAsmOperand {
return Mem.Off;
}
+ unsigned getASITag() const {
+ assert((Kind == k_ASITag) && "Invalid access!");
+ return ASI;
+ }
+
/// getStartLoc - Get the location of the first token of this operand.
SMLoc getStartLoc() const override {
return StartLoc;
@@ -379,6 +390,9 @@ class SparcOperand : public MCParsedAsmOperand {
OS << "Mem: " << getMemBase()
<< "+" << *getMemOff()
<< "\n"; break;
+ case k_ASITag:
+ OS << "ASI tag: " << getASITag() << "\n";
+ break;
}
}
@@ -430,6 +444,11 @@ class SparcOperand : public MCParsedAsmOperand {
addExpr(Inst, Expr);
}
+ void addASITagOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(getASITag()));
+ }
+
void addMembarTagOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCExpr *Expr = getImm();
@@ -474,6 +493,15 @@ class SparcOperand : public MCParsedAsmOperand {
return Op;
}
+ static std::unique_ptr<SparcOperand> CreateASITag(unsigned Val, SMLoc S,
+ SMLoc E) {
+ auto Op = std::make_unique<SparcOperand>(k_ASITag);
+ Op->ASI = Val;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
static bool MorphToIntPairReg(SparcOperand &Op) {
unsigned Reg = Op.getReg();
assert(Op.Reg.Kind == rk_IntReg);
@@ -1080,6 +1108,29 @@ OperandMatchResultTy SparcAsmParser::parseMembarTag(OperandVector &Operands) {
return MatchOperand_Success;
}
+OperandMatchResultTy SparcAsmParser::parseASITag(OperandVector &Operands) {
+ SMLoc S = Parser.getTok().getLoc();
+ SMLoc E = Parser.getTok().getEndLoc();
+ int64_t ASIVal = 0;
+
+ if (getParser().parseAbsoluteExpression(ASIVal)) {
+ Error(
+ S,
+ is64Bit()
+ ? "malformed ASI tag, must be %asi or a constant integer expression"
+ : "malformed ASI tag, must be a constant integer expression");
+ return MatchOperand_ParseFail;
+ }
+
+ if (!isUInt<8>(ASIVal)) {
+ Error(S, "invalid ASI number, must be between 0 and 255");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(SparcOperand::CreateASITag(ASIVal, S, E));
+ return MatchOperand_Success;
+}
+
OperandMatchResultTy SparcAsmParser::parseCallTarget(OperandVector &Operands) {
SMLoc S = Parser.getTok().getLoc();
SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
@@ -1154,13 +1205,49 @@ SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
Parser.Lex(); // Eat the ]
// Parse an optional address-space identifier after the address.
- if (getLexer().is(AsmToken::Integer)) {
- std::unique_ptr<SparcOperand> Op;
- ResTy = parseSparcAsmOperand(Op, false);
- if (ResTy != MatchOperand_Success || !Op)
- return MatchOperand_ParseFail;
- Operands.push_back(std::move(Op));
+ // This will be either an immediate constant expression, or, on 64-bit
+ // processors, the %asi register.
+ if (is64Bit() && getLexer().is(AsmToken::Percent)) {
+ SMLoc S = Parser.getTok().getLoc();
+ Parser.Lex(); // Eat the %.
+ const AsmToken Tok = Parser.getTok();
+ if (Tok.is(AsmToken::Identifier) && Tok.getString() == "asi") {
+ // Here we patch the MEM operand from [base + %g0] into [base + 0]
+ // as memory operations with ASI tag stored in %asi register needs
+ // to use immediate offset. We need to do this because Reg addressing
+ // will be parsed as Reg+G0 initially.
+ // This allows forms such as `ldxa [%o0] %asi, %o0` to parse correctly.
+ SparcOperand &OldMemOp = (SparcOperand &)*Operands[Operands.size() - 2];
+ if (OldMemOp.isMEMrr()) {
+ if (OldMemOp.getMemOffsetReg() != Sparc::G0) {
+ Error(S, "invalid operand for instruction");
+ return MatchOperand_ParseFail;
+ }
+ Operands[Operands.size() - 2] = SparcOperand::MorphToMEMri(
+ OldMemOp.getMemBase(),
+ SparcOperand::CreateImm(MCConstantExpr::create(0, getContext()),
+ OldMemOp.getStartLoc(),
+ OldMemOp.getEndLoc()));
+ }
+ Parser.Lex(); // Eat the identifier.
+ // In this context, we convert the register operand into
+ // a plain "%asi" token since the register access is already
+ // implicit in the instruction definition and encoding.
+ // See LoadASI/StoreASI in SparcInstrInfo.td.
+ Operands.push_back(SparcOperand::CreateToken("%asi", S));
+ return MatchOperand_Success;
+ }
+
+ Error(S,
+ "malformed ASI tag, must be %asi or a constant integer expression");
+ return MatchOperand_ParseFail;
}
+
+ // If we're not at the end of statement and the next token is not a comma,
+ // then it is an immediate ASI value.
+ if (getLexer().isNot(AsmToken::EndOfStatement) &&
+ getLexer().isNot(AsmToken::Comma))
+ return parseASITag(Operands);
return MatchOperand_Success;
}
diff --git a/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp b/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
index ace59ee4d743c94..f1f7a171c9eaf7d 100644
--- a/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
+++ b/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
@@ -306,8 +306,10 @@ DecodeStatus SparcDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
{
Result = decodeInstruction(DecoderTableSparcV832, Instr, Insn, Address, this, STI);
}
- if (Result != MCDisassembler::Fail)
+ if (Result != MCDisassembler::Fail) {
+ Size = 4;
return Result;
+ }
Result =
decodeInstruction(DecoderTableSparc32, Instr, Insn, Address, this, STI);
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp
index 929c755e4821f69..c3150f4a72d04b0 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp
@@ -251,3 +251,9 @@ void SparcInstPrinter::printMembarTag(const MCInst *MI, int opNum,
}
}
}
+
+void SparcInstPrinter::printASITag(const MCInst *MI, int opNum,
+ const MCSubtargetInfo &STI, raw_ostream &O) {
+ unsigned Imm = MI->getOperand(opNum).getImm();
+ O << Imm;
+}
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h
index cccdeadd816c7b5..5cc79a21943f467 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h
@@ -54,6 +54,8 @@ class SparcInstPrinter : public MCInstPrinter {
raw_ostream &OS);
void printMembarTag(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
raw_ostream &O);
+ void printASITag(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
+ raw_ostream &O);
};
} // end namespace llvm
diff --git a/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td
index 078c08d8d4945f7..4b8793d1e7132f9 100644
--- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td
+++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td
@@ -239,7 +239,7 @@ def UDIVXri : F3_2<2, 0b001101,
let Predicates = [Is64Bit] in {
// 64-bit loads.
-defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>;
+defm LDX : LoadA<"ldx", 0b001011, 0b011011, load, I64Regs, i64>;
let mayLoad = 1, isAsmParserOnly = 1 in {
def TLS_LDXrr : F3_1<3, 0b001011,
@@ -282,10 +282,10 @@ def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr ADDRrr:$addr)>;
def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;
// Sign-extending load of i32 into i64 is a new SPARC v9 instruction.
-defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>;
+defm LDSW : LoadA<"ldsw", 0b001000, 0b011000, sextloadi32, I64Regs, i64>;
// 64-bit stores.
-defm STX : Store<"stx", 0b001110, store, I64Regs, i64>;
+defm STX : StoreA<"stx", 0b001110, 0b011110, store, I64Regs, i64>;
// Truncating stores from i64 are identical to the i32 stores.
def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>;
diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td
index c85c891d41a9047..6940a2a0266450d 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -183,6 +183,16 @@ def MembarTag : Operand<i32> {
let ParserMatchClass = SparcMembarTagAsmOperand;
}
+def SparcASITagAsmOperand : AsmOperandClass {
+ let Name = "ASITag";
+ let ParserMethod = "parseASITag";
+}
+
+def ASITag : Operand<i32> {
+ let PrintMethod = "printASITag";
+ let ParserMatchClass = SparcASITagAsmOperand;
+}
+
// Branch targets have OtherVT type.
def brtarget : Operand<OtherVT> {
let EncoderMethod = "getBranchTargetOpValue";
@@ -421,19 +431,26 @@ multiclass Load<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode,
// TODO: Instructions of the LoadASI class are currently asm only; hooking up
// CodeGen's address spaces to use these is a future task.
-class LoadASI<string OpcStr, bits<6> Op3Val, RegisterClass RC> :
- F3_1_asi<3, Op3Val, (outs RC:$rd), (ins (MEMrr $rs1, $rs2):$addr, i8imm:$asi),
- !strconcat(OpcStr, "a [$addr] $asi, $rd"),
- []>;
+multiclass LoadASI<string OpcStr, bits<6> Op3Val, RegisterClass RC> {
+ def rr : F3_1_asi<3, Op3Val, (outs RC:$rd), (ins (MEMrr $rs1, $rs2):$addr, ASITag:$asi),
+ !strconcat(OpcStr, "a [$addr] $asi, $rd"),
+ []>;
+
+ let Predicates = [HasV9], Uses = [ASR3] in
+ def ri : F3_2<3, Op3Val, (outs RC:$rd), (ins (MEMri $rs1, $simm13):$addr),
+ !strconcat(OpcStr, "a [$addr] %asi, $rd"),
+ []>;
+}
// LoadA multiclass - As above, but also define alternate address space variant
multiclass LoadA<string OpcStr, bits<6> Op3Val, bits<6> LoadAOp3Val,
SDPatternOperator OpNode, RegisterClass RC, ValueType Ty,
InstrItinClass itin = NoItinerary> :
Load<OpcStr, Op3Val, OpNode, RC, Ty, itin> {
- def Arr : LoadASI<OpcStr, LoadAOp3Val, RC>;
+ defm A : LoadASI<OpcStr, LoadAOp3Val, RC>;
}
+
// The LDSTUB instruction is supported for asm only.
// It is unlikely that general-purpose code could make use of it.
// CAS is preferred for sparc v9.
@@ -442,8 +459,12 @@ def LDSTUBrr : F3_1<3, 0b001101, (outs IntRegs:$rd), (ins (MEMrr $rs1, $rs2):$ad
def LDSTUBri : F3_2<3, 0b001101, (outs IntRegs:$rd), (ins (MEMri $rs1, $simm13):$addr),
"ldstub [$addr], $rd", []>;
def LDSTUBArr : F3_1_asi<3, 0b011101, (outs IntRegs:$rd),
- (ins (MEMrr $rs1, $rs2):$addr, i8imm:$asi),
+ (ins (MEMrr $rs1, $rs2):$addr, ASITag:$asi),
"ldstuba [$addr] $asi, $rd", []>;
+let Predicates = [HasV9], Uses = [ASR3] in
+def LDSTUBAri : F3_2<3, 0b011101, (outs IntRegs:$rd),
+ (ins (MEMri $rs1, $simm13):$addr),
+ "ldstuba [$addr] %asi, $rd", []>;
// Store multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot.
multiclass Store<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode,
@@ -462,17 +483,24 @@ multiclass Store<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode,
// TODO: Instructions of the StoreASI class are currently asm only; hooking up
// CodeGen's address spaces to use these is a future task.
-class StoreASI<string OpcStr, bits<6> Op3Val, RegisterClass RC,
- InstrItinClass itin = IIC_st> :
- F3_1_asi<3, Op3Val, (outs), (ins (MEMrr $rs1, $rs2):$addr, RC:$rd, i8imm:$asi),
+multiclass StoreASI<string OpcStr, bits<6> Op3Val, RegisterClass RC,
+ InstrItinClass itin = IIC_st> {
+ def rr : F3_1_asi<3, Op3Val, (outs), (ins (MEMrr $rs1, $rs2):$addr, RC:$rd, ASITag:$asi),
!strconcat(OpcStr, "a $rd, [$addr] $asi"),
[],
itin>;
+ let Predicates = [HasV9], Uses = [ASR3] in
+ def ri : F3_2<3, Op3Val, (outs), (ins (MEMri $rs1, $simm13):$addr, RC:$rd),
+ !strconcat(OpcStr, "a $rd, [$addr] %asi"),
+ [],
+ itin>;
+}
+
multiclass StoreA<string OpcStr, bits<6> Op3Val, bits<6> StoreAOp3Val,
SDPatternOperator OpNode, RegisterClass RC, ValueType Ty> :
Store<OpcStr, Op3Val, OpNode, RC, Ty> {
- def Arr : StoreASI<OpcStr, StoreAOp3Val, RC>;
+ defm A : StoreASI<OpcStr, StoreAOp3Val, RC>;
}
//===----------------------------------------------------------------------===//
@@ -587,18 +615,21 @@ defm LD : LoadA<"ld", 0b000000, 0b010000, load, IntRegs, i32>;
defm LDD : LoadA<"ldd", 0b000011, 0b010011, load, IntPair, v2i32, IIC_ldd>;
// Section B.2 - Load Floating-point Instructions, p. 92
-defm LDF : Load<"ld", 0b100000, load, FPRegs, f32, IIC_iu_or_fpu_instr>;
-def LDFArr : LoadASI<"ld", 0b110000, FPRegs>,
- Requires<[HasV9]>;
+defm LDF : Load<"ld", 0b100000, load, FPRegs, f32, IIC_iu_or_fpu_instr>;
+defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64, IIC_ldd>;
-defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64, IIC_ldd>;
-def LDDFArr : LoadASI<"ldd", 0b110011, DFPRegs>,
- Requires<[HasV9]>;
-defm LDQF : LoadA<"ldq", 0b100010, 0b110010, load, QFPRegs, f128>,
- Requires<[HasV9, HasHardQuad]>;
+let DecoderNamespace = "SparcV9", Predicates = [HasV9] in {
+ defm LDFA : LoadASI<"ld", 0b110000, FPRegs>;
+ defm LDDFA : LoadASI<"ldd", 0b110011, DFPRegs>;
+ defm LDQF : LoadA<"ldq", 0b100010, 0b110010, load, QFPRegs, f128>,
+ Requires<[HasHardQuad]>;
+}
-defm LDC : Load<"ld", 0b110000, load, CoprocRegs, i32>;
-defm LDDC : Load<"ldd", 0b110011, load, CoprocPair, v2i32, IIC_ldd>;
+// Coprocessor instructions were removed in v9.
+let DecoderNamespace = "SparcV8", Predicates = [HasNoV9] in {
+ defm LDC : Load<"ld", 0b110000, load, CoprocRegs, i32>;
+ defm LDDC : Load<"ldd", 0b110011, load, CoprocPair, v2i32, IIC_ldd>;
+}
let Defs = [CPSR] in {
let rd = 0 in {
@@ -641,16 +672,20 @@ defm STD : StoreA<"std", 0b000111, 0b010111, store, IntPair, v2i32>;
// Section B.5 - Store Floating-point Instructions, p. 97
defm STF : Store<"st", 0b100100, store, FPRegs, f32>;
-def STFArr : StoreASI<"st", 0b110100, FPRegs>,
- Requires<[HasV9]>;
defm STDF : Store<"std", 0b100111, store, DFPRegs, f64, IIC_std>;
-def STDFArr : StoreASI<"std", 0b110111, DFPRegs>,
- Requires<[HasV9]>;
-defm STQF : StoreA<"stq", 0b100110, 0b110110, store, QFPRegs, f128>,
- Requires<[HasV9, HasHardQuad]>;
-defm STC : Store<"st", 0b110100, store, CoprocRegs, i32>;
-defm STDC : Store<"std", 0b110111, store, CoprocPair, v2i32, IIC_std>;
+let DecoderNamespace = "SparcV9", Predicates = [HasV9] in {
+ defm STFA : StoreASI<"st", 0b110100, FPRegs>;
+ defm STDFA : StoreASI<"std", 0b110111, DFPRegs>;
+ defm STQF : StoreA<"stq", 0b100110, 0b110110, store, QFPRegs, f128>,
+ Requires<[HasHardQuad]>;
+}
+
+// Coprocessor instructions were removed in v9.
+let DecoderNamespace = "SparcV8", Predicates = [HasNoV9] in {
+ defm STC : Store<"st", 0b110100, store, CoprocRegs, i32>;
+ defm STDC : Store<"std", 0b110111, store, CoprocPair, v2i32, IIC_std>;
+}
let rd = 0 in {
let Defs = [CPSR] in {
@@ -700,9 +735,14 @@ let Constraints = "$val = $rd" in {
"swap [$addr], $rd",
[(set i32:$rd, (atomic_swap_32 ADDRri:$addr, i32:$val))]>;
def SWAPArr : F3_1_asi<3, 0b011111,
- (outs IntRegs:$rd), (ins (MEMrr $rs1, $rs2):$addr, i8imm:$asi, IntRegs:$val),
+ (outs IntRegs:$rd), (ins (MEMrr $rs1, $rs2):$addr, ASITag:$asi, IntRegs:$val),
"swapa [$addr] $asi, $rd",
[/*FIXME: pattern?*/]>;
+let Predicates = [HasV9], Uses = [ASR3] in
+ def SWAPAri : F3_2<3, 0b011111,
+ (outs IntRegs:$rd), (ins (MEMri $rs1, $simm13):$addr, IntRegs:$val),
+ "swapa [$addr] %asi, $rd",
+ [/*FIXME: pattern?*/]>;
}
@@ -1687,7 +1727,7 @@ let Predicates = [HasLeonCASA], Constraints = "$swap = $rd", asi = 0b00001010 in
let Predicates = [HasLeonCASA], Constraints = "$swap = $rd" in
def CASArr: F3_1_asi<3, 0b111100,
(outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2,
- IntRegs:$swap, i8imm:$asi),
+ IntRegs:$swap, ASITag:$asi),
"casa [$rs1] $asi, $rs2, $rd", []>;
// TODO: Add DAG sequence to lower these instructions. Currently, only provided
diff --git a/llvm/test/MC/Disassembler/Sparc/sparc-mem-v9.txt b/llvm/test/MC/Disassembler/Sparc/sparc-mem-v9.txt
new file mode 100644
index 000000000000000..f7f5907af909269
--- /dev/null
+++ b/llvm/test/MC/Disassembler/Sparc/sparc-mem-v9.txt
@@ -0,0 +1,31 @@
+# RUN: llvm-mc --disassemble %s -triple=sparcv9-unknown-linux | FileCheck %s
+
+# CHECK: lduba [%i0+8] %asi, %o2
+0xd4,0x8e,0x20,0x08
+
+# CHECK: lduha [%i0+8] %asi, %o2
+0xd4,0x96,0x20,0x08
+
+# CHECK: lda [%i0+8] %asi, %o2
+0xd4,0x86,0x20,0x08
+
+# CHECK: ldxa [%i0+8] %asi, %o2
+0xd4,0xde,0x20,0x08
+
+# CHECK: ldstuba [%i0+8] %asi, %o2
+0xd4,0xee,0x20,0x08
+
+# CHECK: swapa [%i0+8] %asi, %o2
+0xd4,0xfe,0x20,0x08
+
+# CHECK: stba %o2, [%i0+8] %asi
+0xd4,0xae,0x20,0x08
+
+# CHECK: stha %o2, [%i0+8] %asi
+0xd4,0xb6,0x20,0x08
+
+# CHECK: sta %o2, [%i0+8] %asi
+0xd4,0xa6,0x20,0x08
+
+# CHECK: stxa %o2, [%i0+8] %asi
+0xd4,0xf6,0x20,0x08
diff --git a/llvm/test/MC/Sparc/sparc-atomic-instructions.s b/llvm/test/MC/Sparc/sparc-atomic-instructions.s
index 4ce19d5cdda02bd..ce92bf82d3ec603 100644
--- a/llvm/test/MC/Sparc/sparc-atomic-instructions.s
+++ b/llvm/test/MC/Sparc/sparc-atomic-instructions.s
@@ -13,6 +13,9 @@
! CHECK: swapa [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xfe,0x10,0x76]
swapa [%i0+%l6] 131, %o2
+ ! CHECK: swapa [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xfe,0x10,0x76]
+ swapa [%i0+%l6] (130+1), %o2
+
! CHECK: ldstub [%i0+40], %g1 ! encoding: [0xc2,0x6e,0x20,0x28]
ldstub [%i0+40], %g1
@@ -21,3 +24,6 @@
! CHECK: ldstuba [%i0+%i2] 131, %g1 ! encoding: [0xc2,0xee,0x10,0x7a]
ldstuba [%i0+%i2] 131, %g1
+
+ ! CHECK: ldstuba [%i0+%i2] 131, %g1 ! encoding: [0xc2,0xee,0x10,0x7a]
+ ldstuba [%i0+%i2] (130+1), %g1
diff --git a/llvm/test/MC/Sparc/sparc-mem-asi-instructions.s b/llvm/test/MC/Sparc/sparc-mem-asi-instructions.s
new file mode 100644
index 000000000000000..6bad7c4b7e7277b
--- /dev/null
+++ b/llvm/test/MC/Sparc/sparc-mem-asi-instructions.s
@@ -0,0 +1,49 @@
+! RUN: not llvm-mc %s -arch=sparc -show-encoding 2>&1 | FileCheck %s --check-prefix=V8
+! RUN: not llvm-mc %s -arch=sparcv9 -show-encoding 2>&1 | FileCheck %s --check-prefix=V9
+
+! V8: error: malformed ASI tag, must be a constant integer expression
+! V8-NEXT: lduba [%i0] asi, %o2
+! V9: error: malformed ASI tag, must be %asi or a constant integer expression
+! V9-NEXT: lduba [%i0] asi, %o2
+lduba [%i0] asi, %o2
+
+! V8: error: malformed ASI tag, must be a constant integer expression
+! V8-NEXT: lduba [%i0] %g0, %o2
+! V9: error: malformed ASI tag, must be %asi or a constant integer expression
+! V9-NEXT: lduba [%i0] %g0, %o2
+lduba [%i0] %g0, %o2
+
+! V8: error: malformed ASI tag, must be a constant integer expression
+! V8-NEXT: lduba [%i0] %0, %o2
+! V9: error: malformed ASI tag, must be %asi or a constant integer expression
+! V9-NEXT: lduba [%i0] %0, %o2
+lduba [%i0] %0, %o2
+
+! V8: error: invalid ASI number, must be between 0 and 255
+! V8-NEXT: lduba [%i0] -1, %o2
+! V9: error: invalid ASI number, must be between 0 and 255
+! V9-NEXT: lduba [%i0] -1, %o2
+lduba [%i0] -1, %o2
+
+! V8: error: invalid ASI number, must be between 0 and 255
+! V8-NEXT: lduba [%i0] 256, %o2
+! V9: error: invalid ASI number, must be between 0 and 255
+! V9-NEXT: lduba [%i0] 256, %o2
+lduba [%i0] 256, %o2
+
+!! %asi register is only introduced in V9
+! V8: error: malformed ASI tag, must be a constant integer expression
+! V8-NEXT: lduba [%i0] %asi, %o2
+lduba [%i0] %asi, %o2
+
+!! [Reg+Imm] can't be used with immediate ASI forms.
+! V8: error: invalid operand for instruction
+! V8-NEXT: lduba [%i0+1] 255, %o2
+! V9: error: invalid operand for instruction
+! V9-NEXT: lduba [%i0+1] 255, %o2
+lduba [%i0+1] 255, %o2
+
+!! [Reg+Reg] can't be used with stored tag in %asi.
+! V9: error: invalid operand for instruction
+! V9-NEXT: lduba [%i0+%i1] %asi, %o2
+lduba [%i0+%i1] %asi, %o2
diff --git a/llvm/test/MC/Sparc/sparc-mem-instructions.s b/llvm/test/MC/Sparc/sparc-mem-instructions.s
index 85ff8ce657ee926..cf88fcb5ba145fd 100644
--- a/llvm/test/MC/Sparc/sparc-mem-instructions.s
+++ b/llvm/test/MC/Sparc/sparc-mem-instructions.s
@@ -9,6 +9,8 @@
ldsb [%g1], %o4
! CHECK: ldsba [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xce,0x10,0x76]
ldsba [%i0 + %l6] 131, %o2
+ ! CHECK: ldsba [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xce,0x10,0x76]
+ ldsba [%i0 + %l6] (130+1), %o2
! CHECK: ldsh [%i0+%l6], %o2 ! encoding: [0xd4,0x56,0x00,0x16]
ldsh [%i0 + %l6], %o2
@@ -18,6 +20,8 @@
ldsh [%g1], %o4
! CHECK: ldsha [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xd6,0x10,0x76]
ldsha [%i0 + %l6] 131, %o2
+ ! CHECK: ldsha [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xd6,0x10,0x76]
+ ldsha [%i0 + %l6] (130+1), %o2
! CHECK: ldub [%i0+%l6], %o2 ! encoding: [0xd4,0x0e,0x00,0x16]
ldub [%i0 + %l6], %o2
@@ -27,6 +31,8 @@
ldub [%g1], %o2
! CHECK: lduba [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x8e,0x10,0x76]
lduba [%i0 + %l6] 131, %o2
+ ! CHECK: lduba [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x8e,0x10,0x76]
+ lduba [%i0 + %l6] (130+1), %o2
! CHECK: lduh [%i0+%l6], %o2 ! encoding: [0xd4,0x16,0x00,0x16]
lduh [%i0 + %l6], %o2
@@ -36,6 +42,8 @@
lduh [%g1], %o2
! CHECK: lduha [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x96,0x10,0x76]
lduha [%i0 + %l6] 131, %o2
+ ! CHECK: lduha [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x96,0x10,0x76]
+ lduha [%i0 + %l6] (130+1), %o2
! CHECK: ld [%i0+%l6], %o2 ! encoding: [0xd4,0x06,0x00,0x16]
ld [%i0 + %l6], %o2
@@ -45,6 +53,8 @@
ld [%g1], %o2
! CHECK: lda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x86,0x10,0x76]
lda [%i0 + %l6] 131, %o2
+ ! CHECK: lda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x86,0x10,0x76]
+ lda [%i0 + %l6] (130+1), %o2
! CHECK: ldd [%i0+%l6], %o2 ! encoding: [0xd4,0x1e,0x00,0x16]
ldd [%i0 + %l6], %o2
@@ -54,6 +64,8 @@
ldd [%g1], %o2
! CHECK: ldda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x9e,0x10,0x76]
ldda [%i0 + %l6] 131, %o2
+ ! CHECK: ldda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x9e,0x10,0x76]
+ ldda [%i0 + %l6] (130+1), %o2
! CHECK: stb %o2, [%i0+%l6] ! encoding: [0xd4,0x2e,0x00,0x16]
stb %o2, [%i0 + %l6]
@@ -68,9 +80,15 @@
! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76]
stba %o2, [%i0 + %l6] 131
! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76]
+ stba %o2, [%i0 + %l6] (130+1)
+ ! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76]
stuba %o2, [%i0 + %l6] 131
! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76]
+ stuba %o2, [%i0 + %l6] (130+1)
+ ! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76]
stsba %o2, [%i0 + %l6] 131
+ ! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76]
+ stsba %o2, [%i0 + %l6] (130+1)
! CHECK: sth %o2, [%i0+%l6] ! encoding: [0xd4,0x36,0x00,0x16]
sth %o2, [%i0 + %l6]
@@ -85,9 +103,15 @@
! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76]
stha %o2, [%i0 + %l6] 131
! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76]
+ stha %o2, [%i0 + %l6] (130+1)
+ ! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76]
stuha %o2, [%i0 + %l6] 131
! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76]
+ stuha %o2, [%i0 + %l6] (130+1)
+ ! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76]
stsha %o2, [%i0 + %l6] 131
+ ! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76]
+ stsha %o2, [%i0 + %l6] (130+1)
! CHECK: st %o2, [%i0+%l6] ! encoding: [0xd4,0x26,0x00,0x16]
st %o2, [%i0 + %l6]
@@ -97,6 +121,8 @@
st %o2, [%g1]
! CHECK: sta %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xa6,0x10,0x76]
sta %o2, [%i0 + %l6] 131
+ ! CHECK: sta %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xa6,0x10,0x76]
+ sta %o2, [%i0 + %l6] (130+1)
! CHECK: std %o2, [%i0+%l6] ! encoding: [0xd4,0x3e,0x00,0x16]
std %o2, [%i0 + %l6]
@@ -106,6 +132,8 @@
std %o2, [%g1]
! CHECK: stda %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xbe,0x10,0x76]
stda %o2, [%i0 + %l6] 131
+ ! CHECK: stda %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xbe,0x10,0x76]
+ stda %o2, [%i0 + %l6] (130+1)
! CHECK: flush %g1+%g2 ! encoding: [0x81,0xd8,0x40,0x02]
flush %g1 + %g2
diff --git a/llvm/test/MC/Sparc/sparcv9-atomic-instructions.s b/llvm/test/MC/Sparc/sparcv9-atomic-instructions.s
index 449450f70f62b97..14f685c5f0a1108 100644
--- a/llvm/test/MC/Sparc/sparcv9-atomic-instructions.s
+++ b/llvm/test/MC/Sparc/sparcv9-atomic-instructions.s
@@ -12,6 +12,12 @@
! CHECK: membar #LoadLoad | #StoreLoad | #LoadStore | #StoreStore | #Lookaside | #MemIssue | #Sync ! encoding: [0x81,0x43,0xe0,0x7f]
membar #LoadLoad | #StoreLoad | #LoadStore | #StoreStore | #Lookaside | #MemIssue | #Sync
+ ! CHECK: swapa [%i0+6] %asi, %o2 ! encoding: [0xd4,0xfe,0x20,0x06]
+ swapa [%i0+6] %asi, %o2
+
+ ! CHECK: ldstuba [%i0+2] %asi, %g1 ! encoding: [0xc2,0xee,0x20,0x02]
+ ldstuba [%i0+2] %asi, %g1
+
! CHECK: cas [%i0], %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16]
cas [%i0], %l6, %o2
diff --git a/llvm/test/MC/Sparc/sparcv9-instructions.s b/llvm/test/MC/Sparc/sparcv9-instructions.s
index 2a90d4dc0387d42..f5d1231ccee2126 100644
--- a/llvm/test/MC/Sparc/sparcv9-instructions.s
+++ b/llvm/test/MC/Sparc/sparcv9-instructions.s
@@ -52,43 +52,83 @@
! V8-NEXT: lduwa [%i0 + %l6] 131, %o2
! V9: lda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x86,0x10,0x76]
lduwa [%i0 + %l6] 131, %o2
+ ! V8: error: invalid instruction mnemonic
+ ! V8-NEXT: lduwa [%i0 + %l6] (130+1), %o2
+ ! V9: lda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x86,0x10,0x76]
+ lduwa [%i0 + %l6] (130+1), %o2
+
+ ! V9: ldsw [%i0+%l6], %o2 ! encoding: [0xd4,0x46,0x00,0x16]
+ ldsw [%i0 + %l6], %o2
+ ! V9: ldsw [%i0+32], %o2 ! encoding: [0xd4,0x46,0x20,0x20]
+ ldsw [%i0 + 32], %o2
+ ! V9: ldsw [%g1], %o2 ! encoding: [0xd4,0x40,0x40,0x00]
+ ldsw [%g1], %o2
+ ! V9: ldswa [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xc6,0x10,0x76]
+ ldswa [%i0 + %l6] 131, %o2
+ ! V9: ldswa [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xc6,0x10,0x76]
+ ldswa [%i0 + %l6] (130+1), %o2
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: lda [%l0] 0xf0, %f29
! V9: lda [%l0] 240, %f29 ! encoding: [0xfb,0x84,0x1e,0x00]
lda [%l0] 0xf0, %f29
+ ! V8: error: instruction requires a CPU feature not currently enabled
+ ! V8-NEXT: lda [%l0] (0xef+0x01), %f29
+ ! V9: lda [%l0] 240, %f29 ! encoding: [0xfb,0x84,0x1e,0x00]
+ lda [%l0] (0xef+0x01), %f29
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: ldda [%l0] 0xf0, %f48
! V9: ldda [%l0] 240, %f48 ! encoding: [0xe3,0x9c,0x1e,0x00]
ldda [%l0] 0xf0, %f48
+ ! V8: error: instruction requires a CPU feature not currently enabled
+ ! V8-NEXT: ldda [%l0] (0xef+0x01), %f48
+ ! V9: ldda [%l0] 240, %f48 ! encoding: [0xe3,0x9c,0x1e,0x00]
+ ldda [%l0] (0xef+0x01), %f48
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: ldqa [%l0] 0xf0, %f48
+ ! V9: ldqa [%l0] 240, %f48 ! encoding: [0xe3,0x94,0x1e,0x00]
+ ldqa [%l0] 0xf0, %f48
! V8: error: instruction requires a CPU feature not currently enabled
- ! V8-NEXT: ldq [%l0], %f48
+ ! V8-NEXT: ldqa [%l0] (0xef+0x01), %f48
! V9: ldqa [%l0] 240, %f48 ! encoding: [0xe3,0x94,0x1e,0x00]
+ ldqa [%l0] (0xef+0x01), %f48
+ ! V8: error: instruction requires a CPU feature not currently enabled
+ ! V8-NEXT: ldq [%l0], %f48
! V9: ldq [%l0], %f48 ! encoding: [0xe3,0x14,0x00,0x00]
- ldqa [%l0] 0xf0, %f48
ldq [%l0], %f48
+
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: sta %f29, [%l0] 0xf0
! V9: sta %f29, [%l0] 240 ! encoding: [0xfb,0xa4,0x1e,0x00]
sta %f29, [%l0] 0xf0
+ ! V8: error: instruction requires a CPU feature not currently enabled
+ ! V8-NEXT: sta %f29, [%l0] (0xef+0x01)
+ ! V9: sta %f29, [%l0] 240 ! encoding: [0xfb,0xa4,0x1e,0x00]
+ sta %f29, [%l0] (0xef+0x01)
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: stda %f48, [%l0] 0xf0
! V9: stda %f48, [%l0] 240 ! encoding: [0xe3,0xbc,0x1e,0x00]
stda %f48, [%l0] 0xf0
+ ! V8: error: instruction requires a CPU feature not currently enabled
+ ! V8-NEXT: stda %f48, [%l0] (0xef+0x01)
+ ! V9: stda %f48, [%l0] 240 ! encoding: [0xe3,0xbc,0x1e,0x00]
+ stda %f48, [%l0] (0xef+0x01)
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: stqa %f48, [%l0] 0xf0
+ ! V9: stqa %f48, [%l0] 240 ! encoding: [0xe3,0xb4,0x1e,0x00]
+ stqa %f48, [%l0] 0xf0
! V8: error: instruction requires a CPU feature not currently enabled
- ! V8-NEXT: stq %f48, [%l0]
+ ! V8-NEXT: stqa %f48, [%l0] (0xef+0x01)
! V9: stqa %f48, [%l0] 240 ! encoding: [0xe3,0xb4,0x1e,0x00]
+ stqa %f48, [%l0] (0xef+0x01)
+ ! V8: error: instruction requires a CPU feature not currently enabled
+ ! V8-NEXT: stq %f48, [%l0]
! V9: stq %f48, [%l0] ! encoding: [0xe3,0x34,0x00,0x00]
- stqa %f48, [%l0] 0xf0
stq %f48, [%l0]
! V8: error: instruction requires a CPU feature not currently enabled
@@ -101,6 +141,11 @@
! V9: ldx [%g2+%i5], %fsr ! encoding: [0xc3,0x08,0x80,0x1d]
ldx [%g2 + %i5],%fsr
+ ! V9: ldxa [%g2+%i5] 131, %g0 ! encoding: [0xc0,0xd8,0x90,0x7d]
+ ldxa [%g2 + %i5] 131, %g0
+ ! V9: ldxa [%g2+%i5] 131, %g0 ! encoding: [0xc0,0xd8,0x90,0x7d]
+ ldxa [%g2 + %i5] (130+1), %g0
+
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: stx %fsr,[%g2 + 20]
! V9: stx %fsr, [%g2+20] ! encoding: [0xc3,0x28,0xa0,0x14]
@@ -111,6 +156,11 @@
! V9: stx %fsr, [%g2+%i5] ! encoding: [0xc3,0x28,0x80,0x1d]
stx %fsr,[%g2 + %i5]
+ ! V9: stxa %g0, [%g2+%i5] 131 ! encoding: [0xc0,0xf0,0x90,0x7d]
+ stxa %g0, [%g2 + %i5] 131
+ ! V9: stxa %g0, [%g2+%i5] 131 ! encoding: [0xc0,0xf0,0x90,0x7d]
+ stxa %g0, [%g2 + %i5] (130+1)
+
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: wrpr %g6,%i6,%tpc
! V9: wrpr %g6, %fp, %tpc ! encoding: [0x81,0x91,0x80,0x1e]
@@ -446,6 +496,16 @@
! V9: st %o1, [%o0] ! encoding: [0xd2,0x22,0x00,0x00]
stw %o1, [%o0]
+ !! SPARCv9 provides a new variant of ASI-tagged memory accesses.
+ ! V9: ldxa [%g2] %asi, %g0 ! encoding: [0xc0,0xd8,0xa0,0x00]
+ ldxa [%g2] %asi, %g0
+ ! V9: stxa %g0, [%g2] %asi ! encoding: [0xc0,0xf0,0xa0,0x00]
+ stxa %g0, [%g2] %asi
+ ! V9: ldxa [%g2+5] %asi, %g0 ! encoding: [0xc0,0xd8,0xa0,0x05]
+ ldxa [%g2 + 5] %asi, %g0
+ ! V9: stxa %g0, [%g2+5] %asi ! encoding: [0xc0,0xf0,0xa0,0x05]
+ stxa %g0, [%g2 + 5] %asi
+
! V8: error: instruction requires a CPU feature not currently enabled
! V8-NEXT: prefetch [ %i1 + 0xf80 ], 1
! V9: prefetch [%i1+3968], 1 ! encoding: [0xc3,0x6e,0x6f,0x80]
More information about the llvm-commits
mailing list