diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp --- 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 @@ OperandMatchResultTy parseMembarTag(OperandVector &Operands); + OperandMatchResultTy parseASITag(OperandVector &Operands); + template OperandMatchResultTy parseTailRelocSym(OperandVector &Operands); @@ -238,7 +241,8 @@ k_Register, k_Immediate, k_MemoryReg, - k_MemoryImm + k_MemoryImm, + k_ASITag } Kind; SMLoc StartLoc, EndLoc; @@ -268,6 +272,7 @@ struct RegOp Reg; struct ImmOp Imm; struct MemOp Mem; + unsigned ASI; }; public: @@ -280,6 +285,7 @@ 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 @@ 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 @@ OS << "Mem: " << getMemBase() << "+" << *getMemOff() << "\n"; break; + case k_ASITag: + OS << "ASI tag: " << getASITag() << "\n"; + break; } } @@ -430,6 +444,11 @@ 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 @@ return Op; } + static std::unique_ptr CreateASITag(unsigned Val, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(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 @@ 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 @@ Parser.Lex(); // Eat the ] // Parse an optional address-space identifier after the address. - if (getLexer().is(AsmToken::Integer)) { - std::unique_ptr 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 --- a/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +++ b/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp @@ -306,8 +306,10 @@ { 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.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h @@ -54,6 +54,8 @@ 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/MCTargetDesc/SparcInstPrinter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp @@ -251,3 +251,9 @@ } } } + +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/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td --- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -239,7 +239,7 @@ 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 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 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -183,6 +183,16 @@ let ParserMatchClass = SparcMembarTagAsmOperand; } +def SparcASITagAsmOperand : AsmOperandClass { + let Name = "ASITag"; + let ParserMethod = "parseASITag"; +} + +def ASITag : Operand { + let PrintMethod = "printASITag"; + let ParserMatchClass = SparcASITagAsmOperand; +} + // Branch targets have OtherVT type. def brtarget : Operand { let EncoderMethod = "getBranchTargetOpValue"; @@ -421,19 +431,26 @@ // 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 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 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 Op3Val, bits<6> LoadAOp3Val, SDPatternOperator OpNode, RegisterClass RC, ValueType Ty, InstrItinClass itin = NoItinerary> : Load { - def Arr : LoadASI; + defm A : LoadASI; } + // 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 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 Op3Val, SDPatternOperator OpNode, @@ -462,17 +483,24 @@ // 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 Op3Val, RegisterClass RC, - InstrItinClass itin = IIC_st> : - F3_1_asi<3, Op3Val, (outs), (ins (MEMrr $rs1, $rs2):$addr, RC:$rd, i8imm:$asi), +multiclass StoreASI 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 Op3Val, bits<6> StoreAOp3Val, SDPatternOperator OpNode, RegisterClass RC, ValueType Ty> : Store { - def Arr : StoreASI; + defm A : StoreASI; } //===----------------------------------------------------------------------===// @@ -587,18 +615,21 @@ 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 @@ // 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 @@ "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" 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 --- /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 --- 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 --- /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 --- 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 --- 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 --- 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]