Index: llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp =================================================================== --- llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -86,6 +86,8 @@ OperandMatchResultTy parseMembarTag(OperandVector &Operands); + OperandMatchResultTy parseASITag(OperandVector &Operands); + template OperandMatchResultTy parseTailRelocSym(OperandVector &Operands); @@ -119,6 +121,9 @@ bool expandSET(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); + bool expandSETX(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions); + SMLoc getLoc() const { return getParser().getTok().getLoc(); } public: @@ -275,6 +280,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_Immediate; } bool isTailRelocSym() const { return Kind == k_Immediate; } bool isCallTarget() const { @@ -431,6 +437,12 @@ addExpr(Inst, Expr); } + void addASITagOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCExpr *Expr = getImm(); + addExpr(Inst, Expr); + } + void addCallTargetOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); @@ -643,6 +655,118 @@ return false; } +bool SparcAsmParser::expandSETX(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions) { + MCOperand MCRegOp = Inst.getOperand(0); + MCOperand MCValOp = Inst.getOperand(1); + MCOperand MCTmpOp = Inst.getOperand(2); + assert(MCRegOp.isReg() && MCTmpOp.isReg()); + assert(MCValOp.isImm() || MCValOp.isExpr()); + + if (!is64Bit()) + return Error(IDLoc, "setx is only available in 64-bit mode"); + + // the imm operand can be either an expression or an immediate. + bool IsImm = Inst.getOperand(1).isImm(); + int64_t ImmValue = IsImm ? MCValOp.getImm() : 0; + + // Small positive immediates effectively becomes a `set`. + if (ImmValue > 0LL && ImmValue <= 4294967295LL) + return expandSET(Inst, IDLoc, Instructions); + + // Small negative immediates can be expressed directly as a single `or`. + bool IsSmallNegative = ImmValue >= -4096 && ImmValue <= 0; + if (IsImm && IsSmallNegative) { + MCInst TmpInst; + const MCExpr *Expr = MCConstantExpr::create(ImmValue, getContext()); + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(SP::ORri); + TmpInst.addOperand(MCRegOp); + TmpInst.addOperand(MCOperand::createReg(Sparc::G0)); + TmpInst.addOperand(MCOperand::createExpr(Expr)); + Instructions.push_back(TmpInst); + return false; + } + + // All other cases simply expand to a fixed sequence. + const MCExpr *ValExpr; + if (IsImm) + ValExpr = MCConstantExpr::create(ImmValue, getContext()); + else + ValExpr = MCValOp.getExpr(); + + // sethi %hh(val), tmp + { + MCInst TmpInst; + const MCExpr *Expr = adjustPICRelocation(SparcMCExpr::VK_Sparc_HH, ValExpr); + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(SP::SETHIi); + TmpInst.addOperand(MCTmpOp); + TmpInst.addOperand(MCOperand::createExpr(Expr)); + Instructions.push_back(TmpInst); + } + + // sethi %hi(val), rd + { + MCInst TmpInst; + const MCExpr *Expr = adjustPICRelocation(SparcMCExpr::VK_Sparc_HI, ValExpr); + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(SP::SETHIi); + TmpInst.addOperand(MCRegOp); + TmpInst.addOperand(MCOperand::createExpr(Expr)); + Instructions.push_back(TmpInst); + } + + // or tmp, %hm(val), tmp + { + MCInst TmpInst; + const MCExpr *Expr = adjustPICRelocation(SparcMCExpr::VK_Sparc_HM, ValExpr); + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(SP::ORri); + TmpInst.addOperand(MCTmpOp); + TmpInst.addOperand(MCTmpOp); + TmpInst.addOperand(MCOperand::createExpr(Expr)); + Instructions.push_back(TmpInst); + } + + // or rd, %lo(val), rd + { + MCInst TmpInst; + const MCExpr *Expr = adjustPICRelocation(SparcMCExpr::VK_Sparc_LO, ValExpr); + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(SP::ORri); + TmpInst.addOperand(MCRegOp); + TmpInst.addOperand(MCRegOp); + TmpInst.addOperand(MCOperand::createExpr(Expr)); + Instructions.push_back(TmpInst); + } + + // sllx tmp, 32, tmp + { + MCInst TmpInst; + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(SP::SLLXri); + TmpInst.addOperand(MCTmpOp); + TmpInst.addOperand(MCTmpOp); + TmpInst.addOperand( + MCOperand::createExpr(MCConstantExpr::create(32, getContext()))); + Instructions.push_back(TmpInst); + } + + // or tmp, rd, rd + { + MCInst TmpInst; + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(SP::ORrr); + TmpInst.addOperand(MCRegOp); + TmpInst.addOperand(MCTmpOp); + TmpInst.addOperand(MCRegOp); + Instructions.push_back(TmpInst); + } + + return false; +} + bool SparcAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -663,6 +787,10 @@ if (expandSET(Inst, IDLoc, Instructions)) return true; break; + case SP::SETX: + if (expandSETX(Inst, IDLoc, Instructions)) + return true; + break; } for (const MCInst &I : Instructions) { @@ -1001,6 +1129,69 @@ return MatchOperand_Success; } +OperandMatchResultTy SparcAsmParser::parseASITag(OperandVector &Operands) { + SMLoc S = Parser.getTok().getLoc(); + const MCExpr *EVal; + int64_t ASIVal = 0; + + std::unique_ptr Mask; + if (parseSparcAsmOperand(Mask) == MatchOperand_Success) { + if (!Mask->isImm() || !Mask->getImm()->evaluateAsAbsolute(ASIVal) || + ASIVal < 0 || ASIVal > 255) { + Error(S, "invalid ASI number"); + return MatchOperand_ParseFail; + } + } else if (getLexer().getKind() == AsmToken::Hash) { + SMLoc TagStart = getLexer().getLoc(); + Parser.Lex(); // Eat the '#'. + + ASIVal = StringSwitch(Parser.getTok().getString()) + .Case("ASI_N", 0x4) + .Case("ASI_N_L", 0xC) + .Case("ASI_AIUP", 0x10) + .Case("ASI_AIUS", 0x11) + .Case("ASI_AIUP_L", 0x18) + .Case("ASI_AIUS_L", 0x19) + .Case("ASI_P", 0x80) + .Case("ASI_S", 0x81) + .Case("ASI_PNF", 0x82) + .Case("ASI_SNF", 0x83) + .Case("ASI_P_L", 0x88) + .Case("ASI_S_L", 0x89) + .Case("ASI_PNF_L", 0x8A) + .Case("ASI_SNF_L", 0x8B) + .Case("ASI_NUCLEUS", 0x4) + .Case("ASI_NUCLEUS_L", 0xC) + .Case("ASI_AS_IF_USER_PRIMARY", 0x10) + .Case("ASI_AS_IF_USER_SECONDARY", 0x11) + .Case("ASI_AS_IF_USER_PRIMARY_LITTLE", 0x18) + .Case("ASI_AS_IF_USER_SECONDARY_LITTLE", 0x19) + .Case("ASI_PRIMARY", 0x80) + .Case("ASI_SECONDARY", 0x81) + .Case("ASI_PRIMARY_NOFAULT", 0x82) + .Case("ASI_SECONDARY_NOFAULT", 0x83) + .Case("ASI_PRIMARY_LITTLE", 0x88) + .Case("ASI_SECONDADY_LITTLE", 0x89) + .Case("ASI_PRIMARY_NOFAULT_LITTLE", 0x8A) + .Case("ASI_SECONDARY_NOFAULT_LITTLE", 0x8B) + .Default(-1); + Parser.Lex(); // Eat the identifier token. + + if (ASIVal == -1) { + Error(TagStart, "unknown ASI tag"); + return MatchOperand_ParseFail; + } + } else { + Error(S, "malformed ASI tag"); + return MatchOperand_ParseFail; + } + + EVal = MCConstantExpr::create(ASIVal, getContext()); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(SparcOperand::CreateImm(EVal, S, E)); + return MatchOperand_Success; +} + OperandMatchResultTy SparcAsmParser::parseCallTarget(OperandVector &Operands) { SMLoc S = Parser.getTok().getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); @@ -1045,7 +1236,8 @@ Parser.getTok().getLoc())); Parser.Lex(); // Eat the [ - if (Mnemonic == "cas" || Mnemonic == "casx" || Mnemonic == "casa") { + if (Mnemonic == "cas" || Mnemonic == "casl" || Mnemonic == "casa" || + Mnemonic == "casx" || Mnemonic == "casxl" || Mnemonic == "casxa") { SMLoc S = Parser.getTok().getLoc(); if (getLexer().getKind() != AsmToken::Percent) return MatchOperand_NoMatch; @@ -1075,13 +1267,34 @@ Parser.Lex(); // Eat the ] // Parse an optional address-space identifier after the address. - if (getLexer().is(AsmToken::Integer)) { + // This will be either the %asi register, or an immediate constant + // expression, or a named tag. + if (getLexer().is(AsmToken::Percent)) { std::unique_ptr Op; - ResTy = parseSparcAsmOperand(Op, false); - if (ResTy != MatchOperand_Success || !Op) - return MatchOperand_ParseFail; - Operands.push_back(std::move(Op)); + if (parseSparcAsmOperand(Op) == MatchOperand_Success && Op) { + if (!Op->isReg() || Op->getReg() != Sparc::ASI) + return MatchOperand_NoMatch; + // 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. + SparcOperand &OldMemOp = (SparcOperand &)*Operands[Operands.size() - 2]; + if (OldMemOp.isMEMrr()) { + if (OldMemOp.getMemOffsetReg() != Sparc::G0) + return MatchOperand_ParseFail; + std::unique_ptr NewMemOp = SparcOperand::MorphToMEMri( + OldMemOp.getMemBase(), + SparcOperand::CreateImm(MCConstantExpr::create(0, getContext()), + OldMemOp.getStartLoc(), + OldMemOp.getEndLoc())); + Operands[Operands.size() - 2] = std::move(NewMemOp); + } + Operands.push_back(std::move(Op)); + } } + + if (getLexer().is(AsmToken::Integer) || getLexer().is(AsmToken::LParen) || + getLexer().is(AsmToken::Hash)) + return parseASITag(Operands); return MatchOperand_Success; } @@ -1141,9 +1354,6 @@ case Sparc::TBR: Op = SparcOperand::CreateToken("%tbr", S); break; - case Sparc::PC: - Op = SparcOperand::CreateToken("%pc", S); - break; case Sparc::ICC: if (name == "xcc") Op = SparcOperand::CreateToken("%xcc", S); @@ -1240,9 +1450,8 @@ return true; } - // %fprs is an alias of %asr6. if (name.equals("fprs")) { - RegNo = ASRRegs[6]; + RegNo = Sparc::FPRS; RegKind = SparcOperand::rk_Special; return true; } @@ -1450,6 +1659,69 @@ RegKind = SparcOperand::rk_Special; return true; } + if (name.equals("asi")) { + RegNo = Sparc::ASI; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("ccr")) { + RegNo = Sparc::CCR; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("gl")) { + RegNo = Sparc::GL; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("ver")) { + RegNo = Sparc::VER; + RegKind = SparcOperand::rk_Special; + return true; + } + + // JPS1 extension - aliases for ASRs + // Section A.51 - Read State Register + if (name.equals("pcr")) { + RegNo = Sparc::ASR16; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("pic")) { + RegNo = Sparc::ASR17; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("dcr")) { + RegNo = Sparc::ASR18; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("gsr")) { + RegNo = Sparc::ASR19; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("softint")) { + RegNo = Sparc::ASR22; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("tick_cmpr")) { + RegNo = Sparc::ASR23; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("stick") || name.equals("sys_tick")) { + RegNo = Sparc::ASR24; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("stick_cmpr") || name.equals("sys_tick_cmpr")) { + RegNo = Sparc::ASR25; + RegKind = SparcOperand::rk_Special; + return true; + } } return false; } Index: llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp =================================================================== --- llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +++ llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp @@ -101,20 +101,16 @@ SP::FCC0, SP::FCC1, SP::FCC2, SP::FCC3 }; static const unsigned ASRRegDecoderTable[] = { - SP::Y, SP::ASR1, SP::ASR2, SP::ASR3, - SP::ASR4, SP::ASR5, SP::ASR6, SP::ASR7, - SP::ASR8, SP::ASR9, SP::ASR10, SP::ASR11, - SP::ASR12, SP::ASR13, SP::ASR14, SP::ASR15, - SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19, - SP::ASR20, SP::ASR21, SP::ASR22, SP::ASR23, - SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27, - SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31}; + SP::Y, SP::ASR1, SP::CCR, SP::ASI, SP::TICK, SP::PC, SP::FPRS, + SP::ASR7, SP::ASR8, SP::ASR9, SP::ASR10, SP::ASR11, SP::ASR12, SP::ASR13, + SP::ASR14, SP::ASR15, SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19, SP::ASR20, + SP::ASR21, SP::ASR22, SP::ASR23, SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27, + SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31}; static const unsigned PRRegDecoderTable[] = { - SP::TPC, SP::TNPC, SP::TSTATE, SP::TT, SP::TICK, SP::TBA, SP::PSTATE, - SP::TL, SP::PIL, SP::CWP, SP::CANSAVE, SP::CANRESTORE, SP::CLEANWIN, - SP::OTHERWIN, SP::WSTATE, SP::PC -}; + SP::TPC, SP::TNPC, SP::TSTATE, SP::TT, SP::TICK, + SP::TBA, SP::PSTATE, SP::TL, SP::PIL, SP::CWP, + SP::CANSAVE, SP::CANRESTORE, SP::CLEANWIN, SP::OTHERWIN, SP::WSTATE}; static const uint16_t IntPairDecoderTable[] = { SP::G0_G1, SP::G2_G3, SP::G4_G5, SP::G6_G7, @@ -310,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); Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h @@ -51,6 +51,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 Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp @@ -236,3 +236,56 @@ } } } + +void SparcInstPrinter::printASITag(const MCInst *MI, int opNum, + const MCSubtargetInfo &STI, raw_ostream &O) { + unsigned Imm = MI->getOperand(opNum).getImm(); + + switch (Imm) { + case 0x04: + O << "#ASI_N"; + break; + case 0x0C: + O << "#ASI_N_L"; + break; + case 0x10: + O << "#ASI_AIUP"; + break; + case 0x11: + O << "#ASI_AIUS"; + break; + case 0x18: + O << "#ASI_AIUP_L"; + break; + case 0x19: + O << "#ASI_AIUS_L"; + break; + case 0x80: + O << "#ASI_P"; + break; + case 0x81: + O << "#ASI_S"; + break; + case 0x82: + O << "#ASI_PNF"; + break; + case 0x83: + O << "#ASI_SNF"; + break; + case 0x88: + O << "#ASI_P_L"; + break; + case 0x89: + O << "#ASI_S_L"; + break; + case 0x8A: + O << "#ASI_PNF_L"; + break; + case 0x8B: + O << "#ASI_SNF_L"; + break; + default: + O << Imm; + break; + } +} Index: llvm/lib/Target/Sparc/SparcInstr64Bit.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ 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)>; @@ -486,14 +486,33 @@ } // ATOMICS. -let Predicates = [Is64Bit], Constraints = "$swap = $rd", asi = 0b10000000 in { - def CASXrr: F3_1_asi<3, 0b111110, +let Predicates = [Is64Bit], Constraints = "$swap = $rd" in { + let asi = 0b10000000 in + def CASXrr: F3_1_asi<3, 0b111110, (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, I64Regs:$swap), "casx [$rs1], $rs2, $rd", [(set i64:$rd, (atomic_cmp_swap_64 i64:$rs1, i64:$rs2, i64:$swap))]>; + let asi = 0b10001000 in + def CASXLrr: F3_1_asi<3, 0b111110, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap), + "casxl [$rs1], $rs2, $rd", + []>; + + def CASXArr: F3_1_asi<3, 0b111110, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap, ASITag:$asi), + "casxa [$rs1] $asi, $rs2, $rd", + []>; + + def CASXAri: F3_1_cas_asi<3, 0b111110, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap, ASRRegs:$asr), + "casxa [$rs1] $asr, $rs2, $rd", + []>; } // Predicates = [Is64Bit], Constraints = ... let Predicates = [Is64Bit] in { Index: llvm/lib/Target/Sparc/SparcInstrAliases.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrAliases.td +++ llvm/lib/Target/Sparc/SparcInstrAliases.td @@ -320,6 +320,8 @@ let EmitPriority = 0 in { defm : int_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual + defm : int_cond_alias<"gt", 0b0011>; // same as g; gnu asm, not in manual + defm : int_cond_alias<"lt", 0b0011>; // same as l; gnu asm, not in manual defm : int_cond_alias<"nz", 0b1001>; // same as ne defm : int_cond_alias<"eq", 0b0001>; // same as e defm : int_cond_alias<"z", 0b0001>; // same as e @@ -413,6 +415,13 @@ // def : InstAlias<"set $val, $rd", (ORri IntRegs:$rd, (SETHIi (HI22 imm:$val)), (LO10 imm:$val))>; def SET : AsmPseudoInst<(outs IntRegs:$rd), (ins i32imm:$val), "set $val, $rd">; +// setx value, tmp, rd +// (turns into a sequence of sethi+or+shift, depending on the value) +def SETX : AsmPseudoInst<(outs I64Regs:$rd), + (ins i64imm:$val, I64Regs:$tmp), + "setx $val, $tmp, $rd">, + Requires<[Is64Bit]>; + // not rd -> xnor rd, %g0, rd def : InstAlias<"not $rd", (XNORrr IntRegs:$rd, IntRegs:$rd, G0), 0>; @@ -477,7 +486,6 @@ def : InstAlias<"clr [$addr]", (STrr MEMrr:$addr, G0), 0>; def : InstAlias<"clr [$addr]", (STri MEMri:$addr, G0), 0>; - // mov reg_or_imm, rd -> or %g0, reg_or_imm, rd def : InstAlias<"mov $rs2, $rd", (ORrr IntRegs:$rd, G0, IntRegs:$rs2)>; def : InstAlias<"mov $simm13, $rd", (ORri IntRegs:$rd, G0, i32imm:$simm13)>; @@ -487,7 +495,7 @@ def : InstAlias<"mov %psr, $rd", (RDPSR IntRegs:$rd), 0>; def : InstAlias<"mov %wim, $rd", (RDWIM IntRegs:$rd), 0>; def : InstAlias<"mov %tbr, $rd", (RDTBR IntRegs:$rd), 0>; -def : InstAlias<"mov %pc, $rd", (RDPC IntRegs:$rd), 0>; +def : InstAlias<"mov %pc, $rd", (RDASR IntRegs:$rd, PC), 0>; // mov reg_or_imm, specialreg -> wr %g0, reg_or_imm, specialreg def : InstAlias<"mov $rs2, $asr", (WRASRrr ASRRegs:$asr, G0, IntRegs:$rs2), 0>; @@ -499,6 +507,11 @@ def : InstAlias<"mov $rs2, %tbr", (WRTBRrr G0, IntRegs:$rs2), 0>; def : InstAlias<"mov $simm13, %tbr", (WRTBRri G0, i32imm:$simm13), 0>; +// or imm, reg, rd -> or reg, imm, rd +// Nonstandard GNU extension. +let EmitPriority = 0 in + def : InstAlias<"or $simm13, $rs1, $rd", (ORri IntRegs:$rd, IntRegs:$rs1, i32imm:$simm13)>; + // End of Section A.3 // wr reg_or_imm, specialreg -> wr %g0, reg_or_imm, specialreg @@ -543,7 +556,14 @@ def : MnemonicAlias<"stuha", "stha">; def : MnemonicAlias<"stsha", "stha">; + def : MnemonicAlias<"stw", "st">, Requires<[HasV9]>; +def : MnemonicAlias<"stuw", "st">, Requires<[HasV9]>; +def : MnemonicAlias<"stsw", "st">, Requires<[HasV9]>; + +def : MnemonicAlias<"stwa", "sta">, Requires<[HasV9]>; +def : MnemonicAlias<"stuwa", "sta">, Requires<[HasV9]>; +def : MnemonicAlias<"stswa", "sta">, Requires<[HasV9]>; def : MnemonicAlias<"lduw", "ld">, Requires<[HasV9]>; def : MnemonicAlias<"lduwa", "lda">, Requires<[HasV9]>; Index: llvm/lib/Target/Sparc/SparcInstrFormats.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrFormats.td +++ llvm/lib/Target/Sparc/SparcInstrFormats.td @@ -134,6 +134,14 @@ let Inst{4-0} = rs2; } +// CAS instructions does not use an immediate even when i=1 +class F3_1_cas_asi opVal, bits<6> op3val, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : F3_1_asi { + let asi = 0; + let Inst{13} = 1; // i field = 1 +} + class F3_1 opVal, bits<6> op3val, dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin = IIC_iu_instr> : F3_1_asi { Index: llvm/lib/Target/Sparc/SparcInstrInfo.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrInfo.td +++ llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -51,10 +51,13 @@ // point instructions. def HasHardQuad : Predicate<"Subtarget->hasHardQuad()">; -// HasLeonCASA - This is true when the target processor supports the CASA +// HasLeonCASA - This is true when the target processor supports the Leon CASA // instruction def HasLeonCASA : Predicate<"Subtarget->hasLeonCasa()">; +// HasCAS - This is true when the target processor supports CASA instruction. +def HasCAS : Predicate<"Subtarget->hasLeonCasa() || Subtarget->isV9()">; + // HasPWRPSR - This is true when the target processor supports partial // writes to the PSR register that only affects the ET field. def HasPWRPSR : Predicate<"Subtarget->hasPWRPSR()">, @@ -183,6 +186,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"; @@ -418,17 +431,23 @@ // 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] in + def ri : F3_2<3, Op3Val, (outs RC:$rd), (ins (MEMri $rs1, $simm13):$addr, ASRRegs:$asr), + !strconcat(OpcStr, "a [$addr] $asr, $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. @@ -439,8 +458,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] in +def LDSTUBAri : F3_2<3, 0b011101, (outs IntRegs:$rd), + (ins (MEMrr $rs1, $simm13):$addr, ASRRegs:$asr), + "ldstuba [$addr] $asr, $rd", []>; // Store multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot. multiclass Store Op3Val, SDPatternOperator OpNode, @@ -459,17 +482,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] in + def ri : F3_2<3, Op3Val, (outs), (ins (MEMri $rs1, $simm13):$addr, RC:$rd, ASRRegs:$asr), + !strconcat(OpcStr, "a $rd, [$addr] $asr"), + [], + itin>; +} + multiclass StoreA Op3Val, bits<6> StoreAOp3Val, SDPatternOperator OpNode, RegisterClass RC, ValueType Ty> : Store { - def Arr : StoreASI; + defm A : StoreASI; } //===----------------------------------------------------------------------===// @@ -584,18 +614,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 { @@ -638,16 +671,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 { @@ -697,7 +734,7 @@ "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?*/]>; } @@ -1103,7 +1140,8 @@ let hasSideEffects = 1, rd = 0b01000, rs1 = 0, simm13 = 1 in def TA1 : F3_2<0b10, 0b111010, (outs), (ins), "ta 1", [(debugtrap)]>; -// Section B.28 - Read State Register Instructions +// Section B.28 (v8) - Read State Register Instructions +// Section A.44 (v9) - Read State Register let rs2 = 0 in def RDASR : F3_1<2, 0b101000, (outs IntRegs:$rd), (ins ASRRegs:$rs1), @@ -1127,14 +1165,6 @@ "rd %tbr, $rd", []>; } -// PC don't exist on the SparcV8, only the V9. -let Predicates = [HasV9] in { - let rs2 = 0, rs1 = 5 in - def RDPC : F3_1<2, 0b101000, - (outs IntRegs:$rd), (ins), - "rd %pc, $rd", []>; -} - // Section B.29 - Write State Register Instructions def WRASRrr : F3_1<2, 0b110000, (outs ASRRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), @@ -1672,16 +1702,27 @@ "sir $simm13", []>; // The CAS instruction, unlike other instructions, only comes in a -// form which requires an ASI be provided. The ASI value hardcoded -// here is ASI_PRIMARY, the default unprivileged ASI for SparcV9. -let Predicates = [HasV9], Constraints = "$swap = $rd", asi = 0b10000000 in - def CASrr: F3_1_asi<3, 0b111100, +// form which requires an ASI be provided. +let Predicates = [HasV9], Constraints = "$swap = $rd" in { + // The ASI value hardcoded here is ASI_PRIMARY, the default + // unprivileged ASI for SparcV9. + let asi = 0b10000000 in + def CASrr: F3_1_asi<3, 0b111100, (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, IntRegs:$swap), "cas [$rs1], $rs2, $rd", [(set i32:$rd, (atomic_cmp_swap_32 iPTR:$rs1, i32:$rs2, i32:$swap))]>; + // SparcV9 also specifies a CASL alias, which uses ASI_PRIMARY_LITTLE. + let asi = 0b10001000 in + def CASLrr: F3_1_asi<3, 0b111100, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap), + "casl [$rs1], $rs2, $rd", + []>; +} + // CASA is supported as an instruction on some LEON3 and all LEON4 processors. // This version can be automatically lowered from C code, selecting ASI 10 @@ -1693,15 +1734,23 @@ [(set i32:$rd, (atomic_cmp_swap_32 iPTR:$rs1, i32:$rs2, i32:$swap))]>; -// CASA supported on some LEON3 and all LEON4 processors. Same pattern as -// CASrr, above, but with a different ASI. This version is supported for -// inline assembly lowering only. -let Predicates = [HasLeonCASA], Constraints = "$swap = $rd" in +// CASA supported on all V9, some LEON3 and all LEON4 processors. +// Same pattern as CASrr above, but with a different ASI. +// This version is supported for inline assembly lowering only. +let Predicates = [HasCAS], 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", []>; +// On the other hand, CASA that takes its ASI from a register +// is only supported on V9 processors. +let Predicates = [HasV9], Constraints = "$swap = $rd" in + def CASAri: F3_1_cas_asi<3, 0b111100, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap, ASRRegs:$asr), + "casa [$rs1] $asr, $rs2, $rd", []>; + // TODO: Add DAG sequence to lower these instructions. Currently, only provided // as inline assembler-supported instructions. let Predicates = [HasUMAC_SMAC], Defs = [Y, ASR18], Uses = [Y, ASR18] in { @@ -1747,6 +1796,22 @@ } } +// Section A.11 - DONE and RETRY +// Section A.47 - SAVED and RESTORED +let Predicates = [HasV9], rs1 = 0, rs2 = 0 in { + let rd = 0 in + def DONE : F3_1<2, 0b111110, (outs), (ins), "done", []>; + + let rd = 1 in + def RETRY : F3_1<2, 0b111110, (outs), (ins), "retry", []>; + + let rd = 0 in + def SAVED : F3_1<2, 0b110001, (outs), (ins), "saved", []>; + + let rd = 1 in + def RESTORED : F3_1<2, 0b110001, (outs), (ins), "restored", []>; +} + // Section A.42 - Prefetch Data let Predicates = [HasV9] in { def PREFETCHr : F3_1<3, 0b101101, @@ -1765,6 +1830,15 @@ def RDPR : F3_1<2, 0b101010, (outs IntRegs:$rd), (ins PRRegs:$rs1), "rdpr $rs1, $rd", []>; + +// Special case %fq as the register is also used in V8 +// (albeit with different instructions and encoding) +// This allows us to reuse the register definition and +// the "%fq" designation while giving it a different encoding. +let Uses = [FQ], rs1 = 15, rs2 = 0 in + def RDFQ : F3_1<2, 0b101010, + (outs IntRegs:$rd), (ins), + "rdpr %fq, $rd", []>; } // Section A.62 - Write Privileged Register Instructions Index: llvm/lib/Target/Sparc/SparcRegisterInfo.td =================================================================== --- llvm/lib/Target/Sparc/SparcRegisterInfo.td +++ llvm/lib/Target/Sparc/SparcRegisterInfo.td @@ -106,24 +106,33 @@ def PSR : SparcCtrlReg<0, "PSR">; def WIM : SparcCtrlReg<0, "WIM">; def TBR : SparcCtrlReg<0, "TBR">; -// PC on the other hand is only available for SparcV9. -def PC : SparcCtrlReg<5, "PC">; - -def TPC : SparcCtrlReg<0, "TPC">; -def TNPC : SparcCtrlReg<1, "TNPC">; -def TSTATE : SparcCtrlReg<2, "TSTATE">; -def TT : SparcCtrlReg<3, "TT">; -def TICK : SparcCtrlReg<4, "TICK">; -def TBA : SparcCtrlReg<5, "TBA">; -def PSTATE : SparcCtrlReg<6, "PSTATE">; -def TL : SparcCtrlReg<7, "TL">; -def PIL : SparcCtrlReg<8, "PIL">; -def CWP : SparcCtrlReg<9, "CWP">; -def CANSAVE : SparcCtrlReg<10, "CANSAVE">; + +// The rest of the state registers on the other hand is only available for SparcV9. +// Unprivileged V9 state registers +def CCR : SparcCtrlReg<2, "CCR">; +def ASI : SparcCtrlReg<3, "ASI">; +def PC : SparcCtrlReg<5, "PC">; +def FPRS : SparcCtrlReg<6, "FPRS">; +// %tick can be read by both privileged and unprivileged instructions, +// but can only be written by privileged instructions. +def TICK : SparcCtrlReg<4, "TICK">; +// Privileged V9 state registers +def TPC : SparcCtrlReg<0, "TPC">; +def TNPC : SparcCtrlReg<1, "TNPC">; +def TSTATE : SparcCtrlReg<2, "TSTATE">; +def TT : SparcCtrlReg<3, "TT">; +def TBA : SparcCtrlReg<5, "TBA">; +def PSTATE : SparcCtrlReg<6, "PSTATE">; +def TL : SparcCtrlReg<7, "TL">; +def PIL : SparcCtrlReg<8, "PIL">; +def CWP : SparcCtrlReg<9, "CWP">; +def CANSAVE : SparcCtrlReg<10, "CANSAVE">; def CANRESTORE : SparcCtrlReg<11, "CANRESTORE">; -def CLEANWIN : SparcCtrlReg<12, "CLEANWIN">; -def OTHERWIN : SparcCtrlReg<13, "OTHERWIN">; -def WSTATE : SparcCtrlReg<14, "WSTATE">; +def CLEANWIN : SparcCtrlReg<12, "CLEANWIN">; +def OTHERWIN : SparcCtrlReg<13, "OTHERWIN">; +def WSTATE : SparcCtrlReg<14, "WSTATE">; +def GL : SparcCtrlReg<16, "GL">; +def VER : SparcCtrlReg<31, "VER">; // Integer registers def G0 : Ri< 0, "G0">, DwarfRegNum<[0]> { @@ -362,7 +371,8 @@ let isAllocatable = 0 in { // Ancillary state registers def ASRRegs : RegisterClass<"SP", [i32], 32, - (add Y, (sequence "ASR%u", 1, 31))>; + (add Y, CCR, ASI, TICK, PC, FPRS, + (sequence "ASR%u", 1, 31))>; // This register class should not be used to hold i64 values. def CoprocRegs : RegisterClass<"SP", [i32], 32, @@ -379,5 +389,4 @@ // Privileged Registers def PRRegs : RegisterClass<"SP", [i64], 64, (add TPC, TNPC, TSTATE, TT, TICK, TBA, PSTATE, TL, PIL, CWP, - CANSAVE, CANRESTORE, CLEANWIN, OTHERWIN, WSTATE)>; - + CANSAVE, CANRESTORE, CLEANWIN, OTHERWIN, WSTATE, GL, VER)>; Index: llvm/test/MC/Disassembler/Sparc/sparc-mem.txt =================================================================== --- llvm/test/MC/Disassembler/Sparc/sparc-mem.txt +++ llvm/test/MC/Disassembler/Sparc/sparc-mem.txt @@ -12,7 +12,7 @@ # CHECK: ldsb [%g1], %o4 0xd8 0x48 0x40 0x00 -# CHECK: ldsba [%i0+%l6] 131, %o2 +# CHECK: ldsba [%i0+%l6] #ASI_SNF, %o2 0xd4 0xce 0x10 0x76 # CHECK: ldsh [%i0+%l6], %o2 @@ -27,7 +27,7 @@ # CHECK: ldsh [%g1], %o4 0xd8 0x50 0x40 0x00 -# CHECK: ldsha [%i0+%l6] 131, %o2 +# CHECK: ldsha [%i0+%l6] #ASI_SNF, %o2 0xd4 0xd6 0x10 0x76 # CHECK: ldub [%i0+%l6], %o2 @@ -42,7 +42,7 @@ # CHECK: ldub [%g1], %o2 0xd4 0x08 0x40 0x00 -# CHECK: lduba [%i0+%l6] 131, %o2 +# CHECK: lduba [%i0+%l6] #ASI_SNF, %o2 0xd4 0x8e 0x10 0x76 # CHECK: lduh [%i0+%l6], %o2 @@ -57,7 +57,7 @@ # CHECK: lduh [%g1], %o2 0xd4 0x10 0x40 0x00 -# CHECK: lduha [%i0+%l6] 131, %o2 +# CHECK: lduha [%i0+%l6] #ASI_SNF, %o2 0xd4 0x96 0x10 0x76 # CHECK: ld [%i0+%l6], %o2 @@ -72,7 +72,7 @@ # CHECK: ld [%g1], %o2 0xd4 0x00 0x40 0x00 -# CHECK: lda [%i0+%l6] 131, %o2 +# CHECK: lda [%i0+%l6] #ASI_SNF, %o2 0xd4 0x86 0x10 0x76 # CHECK: ld [%i0+%l6], %f2 @@ -87,7 +87,7 @@ # CHECK: ld [%g1], %f2 0xc5 0x00 0x40 0x00 -# CHECK: lda [%i0+%l6] 131, %f2 +# CHECK: lda [%i0+%l6] #ASI_SNF, %f2 0xc5 0x86 0x10 0x76 # CHECK: ldd [%i0+%l6], %f2 @@ -102,7 +102,7 @@ # CHECK: ldd [%g1], %f2 0xc5 0x18 0x40 0x00 -# CHECK: ldda [%i0+%l6] 131, %f2 +# CHECK: ldda [%i0+%l6] #ASI_SNF, %f2 0xc5 0x9e 0x10 0x76 # CHECK: ldq [%i0+%l6], %f4 @@ -153,7 +153,7 @@ # CHECK: stb %o2, [%g1] 0xd4 0x28 0x40 0x00 -# CHECK: stba %o2, [%i0+%l6] 131 +# CHECK: stba %o2, [%i0+%l6] #ASI_SNF 0xd4 0xae 0x10 0x76 # CHECK: sth %o2, [%i0+%l6] @@ -168,7 +168,7 @@ # CHECK: sth %o2, [%g1] 0xd4 0x30 0x40 0x00 -# CHECK: stha %o2, [%i0+%l6] 131 +# CHECK: stha %o2, [%i0+%l6] #ASI_SNF 0xd4 0xb6 0x10 0x76 # CHECK: st %o2, [%i0+%l6] @@ -183,7 +183,7 @@ # CHECK: st %o2, [%g1] 0xd4 0x20 0x40 0x00 -# CHECK: sta %o2, [%i0+%l6] 131 +# CHECK: sta %o2, [%i0+%l6] #ASI_SNF 0xd4 0xa6 0x10 0x76 # CHECK: st %f2, [%i0+%l6] @@ -198,7 +198,7 @@ # CHECK: st %f2, [%g1] 0xc5 0x20 0x40 0x00 -# CHECK: sta %f2, [%i0+%l6] 131 +# CHECK: sta %f2, [%i0+%l6] #ASI_SNF 0xc5 0xa6 0x10 0x76 # CHECK: std %f2, [%i0+%l6] @@ -213,7 +213,7 @@ # CHECK: std %f2, [%g1] 0xc5 0x38 0x40 0x00 -# CHECK: stda %f2, [%i0+%l6] 131 +# CHECK: stda %f2, [%i0+%l6] #ASI_SNF 0xc5 0xbe 0x10 0x76 # CHECK: stq %f4, [%i0+%l6] @@ -252,10 +252,10 @@ # CHECK: swap [%g1], %o2 0xd4 0x78 0x40 0x00 -# CHECK: swapa [%i0+%l6] 131, %o2 +# CHECK: swapa [%i0+%l6] #ASI_SNF, %o2 0xd4 0xfe 0x10 0x76 -# CHECK: swapa [%g1] 131, %o2 +# CHECK: swapa [%g1] #ASI_SNF, %o2 0xd4 0xf8 0x50 0x60 # CHECK: ldd [%i0+%l6], %o2 @@ -282,7 +282,7 @@ # CHECK: std %o2, [%g1] 0xd4 0x38 0x40 0x00 -# CHECK: stda %o2, [%i0+%l6] 131 +# CHECK: stda %o2, [%i0+%l6] #ASI_SNF 0xd4 0xbe 0x10 0x76 # CHECK: ldstub [%i0+%l6], %o2 @@ -297,10 +297,10 @@ # CHECK: ldstub [%g1], %o2 0xd4 0x68 0x40 0x00 -# CHECK: ldstuba [%i0+%l6] 131, %o2 +# CHECK: ldstuba [%i0+%l6] #ASI_SNF, %o2 0xd4 0xee 0x10 0x76 -# CHECK: ldstuba [%g1] 131, %o2 +# CHECK: ldstuba [%g1] #ASI_SNF, %o2 0xd4 0xe8 0x50 0x60 # CHECK: flush %g1+%g2 Index: llvm/test/MC/Sparc/sparc-atomic-instructions.s =================================================================== --- llvm/test/MC/Sparc/sparc-atomic-instructions.s +++ llvm/test/MC/Sparc/sparc-atomic-instructions.s @@ -10,7 +10,7 @@ ! CHECK: swap [%i0+32], %o2 ! encoding: [0xd4,0x7e,0x20,0x20] swap [%i0+32], %o2 - ! CHECK: swapa [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xfe,0x10,0x76] + ! CHECK: swapa [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0xfe,0x10,0x76] swapa [%i0+%l6] 131, %o2 ! CHECK: ldstub [%i0+40], %g1 ! encoding: [0xc2,0x6e,0x20,0x28] @@ -19,5 +19,5 @@ ! CHECK: ldstub [%i0+%i2], %g1 ! encoding: [0xc2,0x6e,0x00,0x1a] ldstub [%i0+%i2], %g1 - ! CHECK: ldstuba [%i0+%i2] 131, %g1 ! encoding: [0xc2,0xee,0x10,0x7a] + ! CHECK: ldstuba [%i0+%i2] #ASI_SNF, %g1 ! encoding: [0xc2,0xee,0x10,0x7a] ldstuba [%i0+%i2] 131, %g1 Index: llvm/test/MC/Sparc/sparc-mem-instructions.s =================================================================== --- llvm/test/MC/Sparc/sparc-mem-instructions.s +++ llvm/test/MC/Sparc/sparc-mem-instructions.s @@ -7,7 +7,7 @@ ldsb [%i0 + 32], %o2 ! CHECK: ldsb [%g1], %o4 ! encoding: [0xd8,0x48,0x40,0x00] ldsb [%g1], %o4 - ! CHECK: ldsba [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xce,0x10,0x76] + ! CHECK: ldsba [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0xce,0x10,0x76] ldsba [%i0 + %l6] 131, %o2 ! CHECK: ldsh [%i0+%l6], %o2 ! encoding: [0xd4,0x56,0x00,0x16] @@ -16,7 +16,7 @@ ldsh [%i0 + 32], %o2 ! CHECK: ldsh [%g1], %o4 ! encoding: [0xd8,0x50,0x40,0x00] ldsh [%g1], %o4 - ! CHECK: ldsha [%i0+%l6] 131, %o2 ! encoding: [0xd4,0xd6,0x10,0x76] + ! CHECK: ldsha [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0xd6,0x10,0x76] ldsha [%i0 + %l6] 131, %o2 ! CHECK: ldub [%i0+%l6], %o2 ! encoding: [0xd4,0x0e,0x00,0x16] @@ -25,7 +25,7 @@ ldub [%i0 + 32], %o2 ! CHECK: ldub [%g1], %o2 ! encoding: [0xd4,0x08,0x40,0x00] ldub [%g1], %o2 - ! CHECK: lduba [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x8e,0x10,0x76] + ! CHECK: lduba [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0x8e,0x10,0x76] lduba [%i0 + %l6] 131, %o2 ! CHECK: lduh [%i0+%l6], %o2 ! encoding: [0xd4,0x16,0x00,0x16] @@ -34,7 +34,7 @@ lduh [%i0 + 32], %o2 ! CHECK: lduh [%g1], %o2 ! encoding: [0xd4,0x10,0x40,0x00] lduh [%g1], %o2 - ! CHECK: lduha [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x96,0x10,0x76] + ! CHECK: lduha [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0x96,0x10,0x76] lduha [%i0 + %l6] 131, %o2 ! CHECK: ld [%i0+%l6], %o2 ! encoding: [0xd4,0x06,0x00,0x16] @@ -43,7 +43,7 @@ ld [%i0 + 32], %o2 ! CHECK: ld [%g1], %o2 ! encoding: [0xd4,0x00,0x40,0x00] ld [%g1], %o2 - ! CHECK: lda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x86,0x10,0x76] + ! CHECK: lda [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0x86,0x10,0x76] lda [%i0 + %l6] 131, %o2 ! CHECK: ldd [%i0+%l6], %o2 ! encoding: [0xd4,0x1e,0x00,0x16] @@ -52,7 +52,7 @@ ldd [%i0 + 32], %o2 ! CHECK: ldd [%g1], %o2 ! encoding: [0xd4,0x18,0x40,0x00] ldd [%g1], %o2 - ! CHECK: ldda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x9e,0x10,0x76] + ! CHECK: ldda [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0x9e,0x10,0x76] ldda [%i0 + %l6] 131, %o2 ! CHECK: stb %o2, [%i0+%l6] ! encoding: [0xd4,0x2e,0x00,0x16] @@ -65,11 +65,11 @@ stub %o2, [%g1] ! CHECK: stb %o2, [%g1] ! encoding: [0xd4,0x28,0x40,0x00] stsb %o2, [%g1] - ! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76] + ! CHECK: stba %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xae,0x10,0x76] stba %o2, [%i0 + %l6] 131 - ! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76] + ! CHECK: stba %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xae,0x10,0x76] stuba %o2, [%i0 + %l6] 131 - ! CHECK: stba %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xae,0x10,0x76] + ! CHECK: stba %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xae,0x10,0x76] stsba %o2, [%i0 + %l6] 131 ! CHECK: sth %o2, [%i0+%l6] ! encoding: [0xd4,0x36,0x00,0x16] @@ -82,11 +82,11 @@ stuh %o2, [%g1] ! CHECK: sth %o2, [%g1] ! encoding: [0xd4,0x30,0x40,0x00] stsh %o2, [%g1] - ! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76] + ! CHECK: stha %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xb6,0x10,0x76] stha %o2, [%i0 + %l6] 131 - ! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76] + ! CHECK: stha %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xb6,0x10,0x76] stuha %o2, [%i0 + %l6] 131 - ! CHECK: stha %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xb6,0x10,0x76] + ! CHECK: stha %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xb6,0x10,0x76] stsha %o2, [%i0 + %l6] 131 ! CHECK: st %o2, [%i0+%l6] ! encoding: [0xd4,0x26,0x00,0x16] @@ -95,7 +95,7 @@ st %o2, [%i0 + 32] ! CHECK: st %o2, [%g1] ! encoding: [0xd4,0x20,0x40,0x00] st %o2, [%g1] - ! CHECK: sta %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xa6,0x10,0x76] + ! CHECK: sta %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xa6,0x10,0x76] sta %o2, [%i0 + %l6] 131 ! CHECK: std %o2, [%i0+%l6] ! encoding: [0xd4,0x3e,0x00,0x16] @@ -104,7 +104,7 @@ std %o2, [%i0 + 32] ! CHECK: std %o2, [%g1] ! encoding: [0xd4,0x38,0x40,0x00] std %o2, [%g1] - ! CHECK: stda %o2, [%i0+%l6] 131 ! encoding: [0xd4,0xbe,0x10,0x76] + ! CHECK: stda %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xbe,0x10,0x76] stda %o2, [%i0 + %l6] 131 ! CHECK: flush %g1+%g2 ! encoding: [0x81,0xd8,0x40,0x02] Index: llvm/test/MC/Sparc/sparc-special-registers.s =================================================================== --- llvm/test/MC/Sparc/sparc-special-registers.s +++ llvm/test/MC/Sparc/sparc-special-registers.s @@ -34,10 +34,10 @@ ! CHECK: wr %i0, 5, %tbr ! encoding: [0x81,0x9e,0x20,0x05] wr %i0, 5, %tbr - ! CHECK: rd %asr6, %i0 ! encoding: [0xb1,0x41,0x80,0x00] + ! CHECK: rd %fprs, %i0 ! encoding: [0xb1,0x41,0x80,0x00] rd %fprs, %i0 - ! CHECK: wr %i0, 7, %asr6 ! encoding: [0x8d,0x86,0x20,0x07] + ! CHECK: wr %i0, 7, %fprs ! encoding: [0x8d,0x86,0x20,0x07] wr %i0, 7, %fprs ! CHECK: ld [%g2+20], %fsr ! encoding: [0xc1,0x08,0xa0,0x14] Index: llvm/test/MC/Sparc/sparcv9-atomic-instructions.s =================================================================== --- llvm/test/MC/Sparc/sparcv9-atomic-instructions.s +++ llvm/test/MC/Sparc/sparcv9-atomic-instructions.s @@ -15,5 +15,23 @@ ! CHECK: cas [%i0], %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16] cas [%i0], %l6, %o2 + ! CHECK: casl [%i0], %l6, %o2 ! encoding: [0xd5,0xe6,0x11,0x16] + casl [%i0], %l6, %o2 + + ! CHECK: casa [%i0] #ASI_P, %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16] + casa [%i0] #ASI_P, %l6, %o2 + + ! CHECK: casa [%i0] %asi, %l6, %o2 ! encoding: [0xd5,0xe6,0x20,0x16] + casa [%i0] %asi, %l6, %o2 + ! CHECK: casx [%i0], %l6, %o2 ! encoding: [0xd5,0xf6,0x10,0x16] casx [%i0], %l6, %o2 + + ! CHECK: casxl [%i0], %l6, %o2 ! encoding: [0xd5,0xf6,0x11,0x16] + casxl [%i0], %l6, %o2 + + ! CHECK: casxa [%i0] #ASI_P, %l6, %o2 ! encoding: [0xd5,0xf6,0x10,0x16] + casxa [%i0] #ASI_P, %l6, %o2 + + ! CHECK: casxa [%i0] %asi, %l6, %o2 ! encoding: [0xd5,0xf6,0x20,0x16] + casxa [%i0] %asi, %l6, %o2 Index: llvm/test/MC/Sparc/sparcv9-instructions.s =================================================================== --- llvm/test/MC/Sparc/sparcv9-instructions.s +++ llvm/test/MC/Sparc/sparcv9-instructions.s @@ -50,9 +50,18 @@ lduw [%g1], %o2 ! V8: error: invalid instruction mnemonic ! V8-NEXT: lduwa [%i0 + %l6] 131, %o2 - ! V9: lda [%i0+%l6] 131, %o2 ! encoding: [0xd4,0x86,0x10,0x76] + ! V9: lda [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0x86,0x10,0x76] lduwa [%i0 + %l6] 131, %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] #ASI_SNF, %o2 ! encoding: [0xd4,0xc6,0x10,0x76] + ldswa [%i0 + %l6] 131, %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] @@ -101,6 +110,9 @@ ! V9: ldx [%g2+%i5], %fsr ! encoding: [0xc3,0x08,0x80,0x1d] ldx [%g2 + %i5],%fsr + ! V9: ldxa [%g2+%i5] #ASI_SNF, %g0 ! encoding: [0xc0,0xd8,0x90,0x7d] + ldxa [%g2 + %i5] 131, %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 +123,9 @@ ! V9: stx %fsr, [%g2+%i5] ! encoding: [0xc3,0x28,0x80,0x1d] stx %fsr,[%g2 + %i5] + ! V9: stxa %g0, [%g2+%i5] #ASI_SNF ! encoding: [0xc0,0xf0,0x90,0x7d] + stxa %g0, [%g2 + %i5] 131 + ! 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] @@ -415,14 +430,62 @@ ! V8-NEXT: rdpr %wstate,%i5 ! V9: rdpr %wstate, %i5 ! encoding: [0xbb,0x53,0x80,0x00] rdpr %wstate,%i5 - ! V8: error: instruction requires a CPU feature not currently enabled - ! V8-NEXT: rd %pc, %o7 + ! V8-NEXT: rdpr %fq,%i5 + ! V9: rdpr %fq, %i5 ! encoding: [0xbb,0x53,0xc0,0x00] + rdpr %fq,%i5 + ! V8: error: instruction requires a CPU feature not currently enabled + ! V8-NEXT: rdpr %ver,%i5 + ! V9: rdpr %ver, %i5 ! encoding: [0xbb,0x57,0xc0,0x00] + rdpr %ver,%i5 + ! V9: rd %pc, %o7 ! encoding: [0x9f,0x41,0x40,0x00] rd %pc, %o7 + ! V9: rd %asi, %g1 ! encoding: [0x83,0x40,0xc0,0x00] + rd %asi, %g1 + ! V9: rd %ccr, %g1 ! encoding: [0x83,0x40,0x80,0x00] + rd %ccr, %g1 + ! V9: rd %tick, %i5 ! encoding: [0xbb,0x41,0x00,0x00] + rd %tick,%i5 + + ! V9: wr %i0, %i1, %asi ! encoding: [0x87,0x86,0x00,0x19] + wr %i0, %i1, %asi + ! V9: wr %i0, 1, %asi ! encoding: [0x87,0x86,0x20,0x01] + wr %i0, 1, %asi + ! V9: wr %i0, %i1, %ccr ! encoding: [0x85,0x86,0x00,0x19] + wr %i0, %i1, %ccr + ! V9: wr %i0, 1, %ccr ! encoding: [0x85,0x86,0x20,0x01] + wr %i0, 1, %ccr ! V9: st %o1, [%o0] ! encoding: [0xd2,0x22,0x00,0x00] stw %o1, [%o0] + ! V9: st %o1, [%o0] ! encoding: [0xd2,0x22,0x00,0x00] + stuw %o1, [%o0] + ! V9: st %o1, [%o0] ! encoding: [0xd2,0x22,0x00,0x00] + stsw %o1, [%o0] + + ! V9: sta %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xa6,0x10,0x76] + stwa %o2, [%i0 + %l6] 131 + ! V9: sta %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xa6,0x10,0x76] + stuwa %o2, [%i0 + %l6] 131 + ! V9: sta %o2, [%i0+%l6] #ASI_SNF ! encoding: [0xd4,0xa6,0x10,0x76] + stswa %o2, [%i0 + %l6] 131 + + !! 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 + + !! Also make sure named ASI tags are parsed properly. + ! V9: ldxa [%g2+%i5] #ASI_SNF, %g0 ! encoding: [0xc0,0xd8,0x90,0x7d] + ldxa [%g2 + %i5] #ASI_SNF, %g0 + ! V9: stxa %g0, [%g2+%i5] #ASI_SNF ! encoding: [0xc0,0xf0,0x90,0x7d] + stxa %g0, [%g2 + %i5] #ASI_SNF ! V8: error: instruction requires a CPU feature not currently enabled ! V8-NEXT: prefetch [ %i1 + 0xf80 ], 1 @@ -433,3 +496,20 @@ ! V8-NEXT: prefetch [ %i1 + %i2 ], 1 ! V9: prefetch [%i1+%i2], 1 ! encoding: [0xc3,0x6e,0x40,0x1a] prefetch [ %i1 + %i2 ], 1 + + ! V8: error: instruction requires a CPU feature not currently enabled + ! V8-NEXT: done + ! V9: done ! encoding: [0x81,0xf0,0x00,0x00] + done + ! V8: error: instruction requires a CPU feature not currently enabled + ! V8-NEXT: retry + ! V9: retry ! encoding: [0x83,0xf0,0x00,0x00] + retry + ! V8: error: instruction requires a CPU feature not currently enabled + ! V8-NEXT: saved + ! V9: saved ! encoding: [0x81,0x88,0x00,0x00] + saved + ! V8: error: instruction requires a CPU feature not currently enabled + ! V8-NEXT: restored + ! V9: restored ! encoding: [0x83,0x88,0x00,0x00] + restored Index: llvm/test/MC/Sparc/sparcv9-synthetic-instructions.s =================================================================== --- /dev/null +++ llvm/test/MC/Sparc/sparcv9-synthetic-instructions.s @@ -0,0 +1,22 @@ +! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s --check-prefix=V9 + + ! V9: mov -1, %o1 ! encoding: [0x92,0x10,0x3f,0xff] + setx -1, %g1, %o1 + + ! V9: sethi %hi(-1), %o1 ! encoding: [0x13,0b00AAAAAA,A,A] + ! V9: ! fixup A - offset: 0, value: %hi(-1), kind: fixup_sparc_hi22 + ! V9: or %o1, %lo(-1), %o1 ! encoding: [0x92,0x12,0b011000AA,A] + ! V9: ! fixup A - offset: 0, value: %lo(-1), kind: fixup_sparc_lo10 + setx 0xffffffff, %g1, %o1 + + ! V9: sethi %hh(81985529216486895), %g1 ! encoding: [0x03,0b00AAAAAA,A,A] + ! V9: ! fixup A - offset: 0, value: %hh(81985529216486895), kind: fixup_sparc_hh + ! V9: sethi %hi(81985529216486895), %o0 ! encoding: [0x11,0b00AAAAAA,A,A] + ! V9: ! fixup A - offset: 0, value: %hi(81985529216486895), kind: fixup_sparc_hi22 + ! V9: or %g1, %hm(81985529216486895), %g1 ! encoding: [0x82,0x10,0b011000AA,A] + ! V9: ! fixup A - offset: 0, value: %hm(81985529216486895), kind: fixup_sparc_hm + ! V9: or %o0, %lo(81985529216486895), %o0 ! encoding: [0x90,0x12,0b001000AA,A] + ! V9: ! fixup A - offset: 0, value: %lo(81985529216486895), kind: fixup_sparc_lo10 + ! V9: sllx %g1, 32, %g1 ! encoding: [0x83,0x28,0x70,0x20] + ! V9: or %g1, %o0, %o0 ! encoding: [0x90,0x10,0x40,0x08] + setx 0x0123456789abcdef, %g1, %o0