Index: llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -127,6 +127,7 @@ OperandMatchResultTy parseRegister(OperandVector &Operands, bool AllowParens = false); OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); + OperandMatchResultTy parseAtomicMemOp(OperandVector &Operands); OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); OperandMatchResultTy parseBareSymbol(OperandVector &Operands); OperandMatchResultTy parseCallSymbol(OperandVector &Operands); @@ -575,6 +576,15 @@ bool isSImm21Lsb0JAL() const { return isBareSimmNLsb0<21>(); } + bool isImmZero() const { + if (!isImm()) + return false; + int64_t Imm; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); + return IsConstantImm && (Imm == 0) && VK == RISCVMCExpr::VK_RISCV_None; + } + /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand @@ -1282,6 +1292,73 @@ return MatchOperand_Success; } +OperandMatchResultTy RISCVAsmParser::parseAtomicMemOp(OperandVector &Operands) { + // Atomic operations such as lr.w, sc.w, and amo*.w accept a "memory operand" + // as one of their register operands, such as `(a0)`. This just denotes that + // the register (in this case `a0`) contains a memory address. + // + // Normally, we would be able to parse these by putting the parens into the + // instruction string. However, GNU as also accepts a zero-offset memory + // operand (such as `0(a0)`), and ignores the 0. Normally this would be parsed + // with parseImmediate followed by parseMemOpBaseReg, but these instructions + // do not accept an immediate operand, and we do not want to add a "dummy" + // operand that is silently dropped. + // + // Instead, we use this custom parser. This will: allow (and discard) an + // offset if it is zero; require (and discard) parentheses; and add only the + // parsed register operand to `Operands`. + // + // These operands are printed with RISCVInstPrinter::printAtomicMemOp, which + // will only print the register surrounded by parentheses (which GNU as also + // uses as its canonical representation for these operands). + std::unique_ptr OptionalImmOp; + + if (getLexer().isNot(AsmToken::LParen)) { + // Parse an Integer token. We do not accept arbritrary constant expressions + // in the offset field (because they may include parens, which complicates + // parsing a lot). + int64_t ImmVal; + SMLoc ImmStart = getLoc(); + if (getParser().parseIntToken(ImmVal, + "expected '(' or optional integer offset")) + return MatchOperand_ParseFail; + + // Create a RISCVOperand for checking later (so the error messages are + // nicer), but we don't add it to Operands. + SMLoc ImmEnd = getLoc(); + OptionalImmOp = + RISCVOperand::createImm(MCConstantExpr::create(ImmVal, getContext()), + ImmStart, ImmEnd, isRV64()); + } + + if (getLexer().isNot(AsmToken::LParen)) { + Error(getLoc(), OptionalImmOp ? "expected '(' after optional integer offset" + : "expected '(' or optional integer offset"); + return MatchOperand_ParseFail; + } + getParser().Lex(); // Eat '(' + + if (parseRegister(Operands) != MatchOperand_Success) { + Error(getLoc(), "expected register"); + return MatchOperand_ParseFail; + } + + if (getLexer().isNot(AsmToken::RParen)) { + Error(getLoc(), "expected ')'"); + return MatchOperand_ParseFail; + } + getParser().Lex(); // Eat ')' + + // Deferred Handling of non-zero offsets. This makes the error messages nicer. + if (OptionalImmOp && !OptionalImmOp->isImmZero()) { + Error(OptionalImmOp->getStartLoc(), "optional integer offset must be 0", + SMRange(OptionalImmOp->getStartLoc(), OptionalImmOp->getEndLoc())); + return MatchOperand_ParseFail; + } + + return MatchOperand_Success; +} + /// Looks at a token type and creates the relevant operand from this /// information, adding to Operands. If operand was parsed, returns false, else /// true. Index: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h =================================================================== --- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h +++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h @@ -37,6 +37,8 @@ const MCSubtargetInfo &STI, raw_ostream &O); void printFRMArg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); + void printAtomicMemOp(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); // Autogenerated by tblgen. void printInstruction(const MCInst *MI, const MCSubtargetInfo &STI, Index: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp +++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp @@ -112,3 +112,15 @@ static_cast(MI->getOperand(OpNo).getImm()); O << RISCVFPRndMode::roundingModeToString(FRMArg); } + +void RISCVInstPrinter::printAtomicMemOp(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNo); + + assert(MO.isReg() && "printAtomicMemOp can only print register operands"); + O << "("; + printRegName(O, MO.getReg()); + O << ")"; + return; +} Index: llvm/trunk/lib/Target/RISCV/RISCVInstrInfoA.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfoA.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfoA.td @@ -12,14 +12,32 @@ //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// +// Operand and SDNode transformation definitions. +//===----------------------------------------------------------------------===// + +// A parse method for (${gpr}) or 0(${gpr}), where the 0 is be silently ignored. +// Used for GNU as Compatibility. +def AtomicMemOpOperand : AsmOperandClass { + let Name = "AtomicMemOpOperand"; + let RenderMethod = "addRegOperands"; + let PredicateMethod = "isReg"; + let ParserMethod = "parseAtomicMemOp"; +} + +def GPRMemAtomic : RegisterOperand { + let ParserMatchClass = AtomicMemOpOperand; + let PrintMethod = "printAtomicMemOp"; +} + +//===----------------------------------------------------------------------===// // Instruction class templates //===----------------------------------------------------------------------===// let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in class LR_r funct3, string opcodestr> : RVInstRAtomic<0b00010, aq, rl, funct3, OPC_AMO, - (outs GPR:$rd), (ins GPR:$rs1), - opcodestr, "$rd, (${rs1})"> { + (outs GPR:$rd), (ins GPRMemAtomic:$rs1), + opcodestr, "$rd, $rs1"> { let rs2 = 0; } @@ -33,8 +51,8 @@ let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in class AMO_rr funct5, bit aq, bit rl, bits<3> funct3, string opcodestr> : RVInstRAtomic; + (outs GPR:$rd), (ins GPRMemAtomic:$rs1, GPR:$rs2), + opcodestr, "$rd, $rs2, $rs1">; multiclass AMO_rr_aq_rl funct5, bits<3> funct3, string opcodestr> { def "" : AMO_rr; Index: llvm/trunk/test/MC/RISCV/rv32a-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv32a-invalid.s +++ llvm/trunk/test/MC/RISCV/rv32a-invalid.s @@ -1,9 +1,10 @@ # RUN: not llvm-mc -triple riscv32 -mattr=+a < %s 2>&1 | FileCheck %s # Final operand must have parentheses -amoswap.w a1, a2, a3 # CHECK: :[[@LINE]]:19: error: invalid operand for instruction -amomin.w a1, a2, 1 # CHECK: :[[@LINE]]:18: error: invalid operand for instruction -lr.w a4, a5 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction +amoswap.w a1, a2, a3 # CHECK: :[[@LINE]]:19: error: expected '(' or optional integer offset +amomin.w a1, a2, 1 # CHECK: :[[@LINE]]:20: error: expected '(' after optional integer offset +amomin.w a1, a2, 1(a3) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +lr.w a4, a5 # CHECK: :[[@LINE]]:10: error: expected '(' or optional integer offset # Only .aq, .rl, and .aqrl suffixes are valid amoxor.w.rlqa a2, a3, (a4) # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic Index: llvm/trunk/test/MC/RISCV/rv64a-aliases-valid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv64a-aliases-valid.s +++ llvm/trunk/test/MC/RISCV/rv64a-aliases-valid.s @@ -0,0 +1,189 @@ +# RUN: llvm-mc %s -triple=riscv64 -mattr=+a -riscv-no-aliases \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc %s -triple=riscv64 -mattr=+a \ +# RUN: | FileCheck -check-prefix=CHECK-ALIAS %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+a < %s \ +# RUN: | llvm-objdump -d -mattr=+a -riscv-no-aliases - \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+a < %s \ +# RUN: | llvm-objdump -d -mattr=+a - \ +# RUN: | FileCheck -check-prefix=CHECK-ALIAS %s + +# The below tests for lr.d, sc.d and amo*.d, using `0(reg)` are actually +# implemented using a custom parser, but we test them as if they're aliases. + +# CHECK-INST: lr.d a1, (a0) +# CHECK-ALIAS: lr.d a1, (a0) +lr.d a1, 0(a0) + +# CHECK-INST: lr.d.aq a1, (a0) +# CHECK-ALIAS: lr.d.aq a1, (a0) +lr.d.aq a1, 0(a0) + +# CHECK-INST: lr.d.rl a1, (a0) +# CHECK-ALIAS: lr.d.rl a1, (a0) +lr.d.rl a1, 0(a0) + +# CHECK-INST: lr.d.aqrl a1, (a0) +# CHECK-ALIAS: lr.d.aqrl a1, (a0) +lr.d.aqrl a1, 0(a0) + +# CHECK-INST: sc.d a2, a1, (a0) +# CHECK-ALIAS: sc.d a2, a1, (a0) +sc.d a2, a1, 0(a0) + +# CHECK-INST: sc.d.aq a2, a1, (a0) +# CHECK-ALIAS: sc.d.aq a2, a1, (a0) +sc.d.aq a2, a1, 0(a0) + +# CHECK-INST: sc.d.rl a2, a1, (a0) +# CHECK-ALIAS: sc.d.rl a2, a1, (a0) +sc.d.rl a2, a1, 0(a0) + +# CHECK-INST: sc.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: sc.d.aqrl a2, a1, (a0) +sc.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amoswap.d a2, a1, (a0) +# CHECK-ALIAS: amoswap.d a2, a1, (a0) +amoswap.d a2, a1, 0(a0) + +# CHECK-INST: amoswap.d.aq a2, a1, (a0) +# CHECK-ALIAS: amoswap.d.aq a2, a1, (a0) +amoswap.d.aq a2, a1, 0(a0) + +# CHECK-INST: amoswap.d.rl a2, a1, (a0) +# CHECK-ALIAS: amoswap.d.rl a2, a1, (a0) +amoswap.d.rl a2, a1, 0(a0) + +# CHECK-INST: amoswap.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amoswap.d.aqrl a2, a1, (a0) +amoswap.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amoadd.d a2, a1, (a0) +# CHECK-ALIAS: amoadd.d a2, a1, (a0) +amoadd.d a2, a1, 0(a0) + +# CHECK-INST: amoadd.d.aq a2, a1, (a0) +# CHECK-ALIAS: amoadd.d.aq a2, a1, (a0) +amoadd.d.aq a2, a1, 0(a0) + +# CHECK-INST: amoadd.d.rl a2, a1, (a0) +# CHECK-ALIAS: amoadd.d.rl a2, a1, (a0) +amoadd.d.rl a2, a1, 0(a0) + +# CHECK-INST: amoadd.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amoadd.d.aqrl a2, a1, (a0) +amoadd.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amoxor.d a2, a1, (a0) +# CHECK-ALIAS: amoxor.d a2, a1, (a0) +amoxor.d a2, a1, 0(a0) + +# CHECK-INST: amoxor.d.aq a2, a1, (a0) +# CHECK-ALIAS: amoxor.d.aq a2, a1, (a0) +amoxor.d.aq a2, a1, 0(a0) + +# CHECK-INST: amoxor.d.rl a2, a1, (a0) +# CHECK-ALIAS: amoxor.d.rl a2, a1, (a0) +amoxor.d.rl a2, a1, 0(a0) + +# CHECK-INST: amoxor.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amoxor.d.aqrl a2, a1, (a0) +amoxor.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amoand.d a2, a1, (a0) +# CHECK-ALIAS: amoand.d a2, a1, (a0) +amoand.d a2, a1, 0(a0) + +# CHECK-INST: amoand.d.aq a2, a1, (a0) +# CHECK-ALIAS: amoand.d.aq a2, a1, (a0) +amoand.d.aq a2, a1, 0(a0) + +# CHECK-INST: amoand.d.rl a2, a1, (a0) +# CHECK-ALIAS: amoand.d.rl a2, a1, (a0) +amoand.d.rl a2, a1, 0(a0) + +# CHECK-INST: amoand.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amoand.d.aqrl a2, a1, (a0) +amoand.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amoor.d a2, a1, (a0) +# CHECK-ALIAS: amoor.d a2, a1, (a0) +amoor.d a2, a1, 0(a0) + +# CHECK-INST: amoor.d.aq a2, a1, (a0) +# CHECK-ALIAS: amoor.d.aq a2, a1, (a0) +amoor.d.aq a2, a1, 0(a0) + +# CHECK-INST: amoor.d.rl a2, a1, (a0) +# CHECK-ALIAS: amoor.d.rl a2, a1, (a0) +amoor.d.rl a2, a1, 0(a0) + +# CHECK-INST: amoor.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amoor.d.aqrl a2, a1, (a0) +amoor.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amomin.d a2, a1, (a0) +# CHECK-ALIAS: amomin.d a2, a1, (a0) +amomin.d a2, a1, 0(a0) + +# CHECK-INST: amomin.d.aq a2, a1, (a0) +# CHECK-ALIAS: amomin.d.aq a2, a1, (a0) +amomin.d.aq a2, a1, 0(a0) + +# CHECK-INST: amomin.d.rl a2, a1, (a0) +# CHECK-ALIAS: amomin.d.rl a2, a1, (a0) +amomin.d.rl a2, a1, 0(a0) + +# CHECK-INST: amomin.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amomin.d.aqrl a2, a1, (a0) +amomin.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amomax.d a2, a1, (a0) +# CHECK-ALIAS: amomax.d a2, a1, (a0) +amomax.d a2, a1, 0(a0) + +# CHECK-INST: amomax.d.aq a2, a1, (a0) +# CHECK-ALIAS: amomax.d.aq a2, a1, (a0) +amomax.d.aq a2, a1, 0(a0) + +# CHECK-INST: amomax.d.rl a2, a1, (a0) +# CHECK-ALIAS: amomax.d.rl a2, a1, (a0) +amomax.d.rl a2, a1, 0(a0) + +# CHECK-INST: amomax.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amomax.d.aqrl a2, a1, (a0) +amomax.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amominu.d a2, a1, (a0) +# CHECK-ALIAS: amominu.d a2, a1, (a0) +amominu.d a2, a1, 0(a0) + +# CHECK-INST: amominu.d.aq a2, a1, (a0) +# CHECK-ALIAS: amominu.d.aq a2, a1, (a0) +amominu.d.aq a2, a1, 0(a0) + +# CHECK-INST: amominu.d.rl a2, a1, (a0) +# CHECK-ALIAS: amominu.d.rl a2, a1, (a0) +amominu.d.rl a2, a1, 0(a0) + +# CHECK-INST: amominu.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amominu.d.aqrl a2, a1, (a0) +amominu.d.aqrl a2, a1, 0(a0) + +# CHECK-INST: amomaxu.d a2, a1, (a0) +# CHECK-ALIAS: amomaxu.d a2, a1, (a0) +amomaxu.d a2, a1, 0(a0) + +# CHECK-INST: amomaxu.d.aq a2, a1, (a0) +# CHECK-ALIAS: amomaxu.d.aq a2, a1, (a0) +amomaxu.d.aq a2, a1, 0(a0) + +# CHECK-INST: amomaxu.d.rl a2, a1, (a0) +# CHECK-ALIAS: amomaxu.d.rl a2, a1, (a0) +amomaxu.d.rl a2, a1, 0(a0) + +# CHECK-INST: amomaxu.d.aqrl a2, a1, (a0) +# CHECK-ALIAS: amomaxu.d.aqrl a2, a1, (a0) +amomaxu.d.aqrl a2, a1, 0(a0) Index: llvm/trunk/test/MC/RISCV/rv64a-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv64a-invalid.s +++ llvm/trunk/test/MC/RISCV/rv64a-invalid.s @@ -1,9 +1,10 @@ # RUN: not llvm-mc -triple riscv64 -mattr=+a < %s 2>&1 | FileCheck %s # Final operand must have parentheses -amoswap.d a1, a2, a3 # CHECK: :[[@LINE]]:19: error: invalid operand for instruction -amomin.d a1, a2, 1 # CHECK: :[[@LINE]]:18: error: invalid operand for instruction -lr.d a4, a5 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction +amoswap.d a1, a2, a3 # CHECK: :[[@LINE]]:19: error: expected '(' or optional integer offset +amomin.d a1, a2, 1 # CHECK: :[[@LINE]]:20: error: expected '(' after optional integer offset +amomin.d a1, a2, 1(a3) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +lr.d a4, a5 # CHECK: :[[@LINE]]:10: error: expected '(' or optional integer offset # Only .aq, .rl, and .aqrl suffixes are valid amoxor.d.rlqa a2, a3, (a4) # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic Index: llvm/trunk/test/MC/RISCV/rva-aliases-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rva-aliases-invalid.s +++ llvm/trunk/test/MC/RISCV/rva-aliases-invalid.s @@ -0,0 +1,94 @@ +# RUN: not llvm-mc %s -triple=riscv32 2>&1 | FileCheck %s +# RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s + +# The below tests for lr(.w), sc(.w) and amo*(.w), using `0(reg)` are actually +# implemented using a custom parser. These tests ensure the custom parser gives +# good error messages. + +lr.w a1, a0 # CHECK: :[[@LINE]]:10: error: expected '(' or optional integer offset +lr.w a1, foo # CHECK: :[[@LINE]]:10: error: expected '(' or optional integer offset +lr.w a1, 1(a0) # CHECK: :[[@LINE]]:10: error: optional integer offset must be 0 +lr.w a1, (foo) # CHECK: :[[@LINE]]:11: error: expected register +lr.w a1, 0(foo) # CHECK: :[[@LINE]]:12: error: expected register +lr.w a1, 0(a0 # CHECK: :[[@LINE]]:17: error: expected ')' +lr.w a1, (a0 # CHECK: :[[@LINE]]:17: error: expected ')' + +sc.w a2, a1, a0 # CHECK: :[[@LINE]]:14: error: expected '(' or optional integer offset +sc.w a2, a1, foo # CHECK: :[[@LINE]]:14: error: expected '(' or optional integer offset +sc.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:14: error: optional integer offset must be 0 +sc.w a2, a1, (foo) # CHECK: :[[@LINE]]:15: error: expected register +sc.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:16: error: expected register +sc.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:21: error: expected ')' +sc.w a2, a1, (a0 # CHECK: :[[@LINE]]:21: error: expected ')' + +amoswap.w a2, a1, a0 # CHECK: :[[@LINE]]:19: error: expected '(' or optional integer offset +amoswap.w a2, a1, foo # CHECK: :[[@LINE]]:19: error: expected '(' or optional integer offset +amoswap.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:19: error: optional integer offset must be 0 +amoswap.w a2, a1, (foo) # CHECK: :[[@LINE]]:20: error: expected register +amoswap.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:21: error: expected register +amoswap.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:26: error: expected ')' +amoswap.w a2, a1, (a0 # CHECK: :[[@LINE]]:26: error: expected ')' + +amoadd.w a2, a1, a0 # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amoadd.w a2, a1, foo # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amoadd.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +amoadd.w a2, a1, (foo) # CHECK: :[[@LINE]]:19: error: expected register +amoadd.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:20: error: expected register +amoadd.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:25: error: expected ')' +amoadd.w a2, a1, (a0 # CHECK: :[[@LINE]]:25: error: expected ')' + +amoxor.w a2, a1, a0 # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amoxor.w a2, a1, foo # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amoxor.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +amoxor.w a2, a1, (foo) # CHECK: :[[@LINE]]:19: error: expected register +amoxor.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:20: error: expected register +amoxor.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:25: error: expected ')' +amoxor.w a2, a1, (a0 # CHECK: :[[@LINE]]:25: error: expected ')' + +amoand.w a2, a1, a0 # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amoand.w a2, a1, foo # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amoand.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +amoand.w a2, a1, (foo) # CHECK: :[[@LINE]]:19: error: expected register +amoand.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:20: error: expected register +amoand.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:25: error: expected ')' +amoand.w a2, a1, (a0 # CHECK: :[[@LINE]]:25: error: expected ')' + +amoor.w a2, a1, a0 # CHECK: :[[@LINE]]:17: error: expected '(' or optional integer offset +amoor.w a2, a1, foo # CHECK: :[[@LINE]]:17: error: expected '(' or optional integer offset +amoor.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:17: error: optional integer offset must be 0 +amoor.w a2, a1, (foo) # CHECK: :[[@LINE]]:18: error: expected register +amoor.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:19: error: expected register +amoor.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:24: error: expected ')' +amoor.w a2, a1, (a0 # CHECK: :[[@LINE]]:24: error: expected ')' + +amomin.w a2, a1, a0 # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amomin.w a2, a1, foo # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amomin.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +amomin.w a2, a1, (foo) # CHECK: :[[@LINE]]:19: error: expected register +amomin.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:20: error: expected register +amomin.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:25: error: expected ')' +amomin.w a2, a1, (a0 # CHECK: :[[@LINE]]:25: error: expected ')' + +amomax.w a2, a1, a0 # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amomax.w a2, a1, foo # CHECK: :[[@LINE]]:18: error: expected '(' or optional integer offset +amomax.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +amomax.w a2, a1, (foo) # CHECK: :[[@LINE]]:19: error: expected register +amomax.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:20: error: expected register +amomax.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:25: error: expected ')' +amomax.w a2, a1, (a0 # CHECK: :[[@LINE]]:25: error: expected ')' + +amominu.w a2, a1, a0 # CHECK: :[[@LINE]]:19: error: expected '(' or optional integer offset +amominu.w a2, a1, foo # CHECK: :[[@LINE]]:19: error: expected '(' or optional integer offset +amominu.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:19: error: optional integer offset must be 0 +amominu.w a2, a1, (foo) # CHECK: :[[@LINE]]:20: error: expected register +amominu.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:21: error: expected register +amominu.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:26: error: expected ')' +amominu.w a2, a1, (a0 # CHECK: :[[@LINE]]:26: error: expected ')' + +amomaxu.w a2, a1, a0 # CHECK: :[[@LINE]]:19: error: expected '(' or optional integer offset +amomaxu.w a2, a1, foo # CHECK: :[[@LINE]]:19: error: expected '(' or optional integer offset +amomaxu.w a2, a1, 1(a0) # CHECK: :[[@LINE]]:19: error: optional integer offset must be 0 +amomaxu.w a2, a1, (foo) # CHECK: :[[@LINE]]:20: error: expected register +amomaxu.w a2, a1, 0(foo) # CHECK: :[[@LINE]]:21: error: expected register +amomaxu.w a2, a1, 0(a0 # CHECK: :[[@LINE]]:26: error: expected ')' +amomaxu.w a2, a1, (a0 # CHECK: :[[@LINE]]:26: error: expected ')' \ No newline at end of file Index: llvm/trunk/test/MC/RISCV/rva-aliases-valid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rva-aliases-valid.s +++ llvm/trunk/test/MC/RISCV/rva-aliases-valid.s @@ -0,0 +1,297 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+a -riscv-no-aliases \ +# RUN: | FileCheck -check-prefixes=CHECK-S-NOALIAS,CHECK-S-OBJ-NOALIAS %s +# RUN: llvm-mc %s -triple=riscv32 -mattr=+a \ +# RUN: | FileCheck -check-prefixes=CHECK-S,CHECK-S-OBJ %s +# RUN: llvm-mc %s -triple=riscv64 -mattr=+a -riscv-no-aliases\ +# RUN: | FileCheck -check-prefixes=CHECK-S-NOALIAS,CHECK-S-OBJ-NOALIAS %s +# RUN: llvm-mc %s -triple=riscv64 -mattr=+a \ +# RUN: | FileCheck -check-prefixes=CHECK-S,CHECK-S-OBJ %s +# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+a < %s \ +# RUN: | llvm-objdump -d -mattr=+a -riscv-no-aliases - \ +# RUN: | FileCheck -check-prefixes=CHECK-OBJ-NOALIAS,CHECK-S-OBJ-NOALIAS %s +# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+a < %s \ +# RUN: | llvm-objdump -d -mattr=+a - \ +# RUN: | FileCheck -check-prefixes=CHECK-OBJ,CHECK-S-OBJ %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+a < %s \ +# RUN: | llvm-objdump -d -mattr=+a -riscv-no-aliases - \ +# RUN: | FileCheck -check-prefixes=CHECK-OBJ-NOALIAS,CHECK-S-OBJ-NOALIAS %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+a < %s \ +# RUN: | llvm-objdump -d -mattr=+a - \ +# RUN: | FileCheck -check-prefixes=CHECK-OBJ,CHECK-S-OBJ %s + +# The following check prefixes are used in this test: +# CHECK-S Match the .s output with aliases enabled +# CHECK-S-NOALIAS Match the .s output with aliases disabled +# CHECK-OBJ Match the objdumped object output with aliases enabled +# CHECK-OBJ-NOALIAS Match the objdumped object output with aliases enabled +# CHECK-S-OBJ Match both the .s and objdumped object output with +# aliases enabled +# CHECK-S-OBJ-NOALIAS Match both the .s and objdumped object output with +# aliases disabled + +# The below tests for lr.w, sc.w and amo*.w, using `0(reg)` are actually +# implemented using a custom parser, but we test them as if they're aliases. + +# CHECK-S: lr.w a1, (a0) +# CHECK-S-NOALIAS: lr.w a1, (a0) +# CHECK-OBJ: lr.w a1, (a0) +# CHECK-OBJ-NOALIAS: lr.w a1, (a0) +lr.w a1, 0(a0) + +# CHECK-S: lr.w.aq a1, (a0) +# CHECK-S-NOALIAS: lr.w.aq a1, (a0) +# CHECK-OBJ: lr.w.aq a1, (a0) +# CHECK-OBJ-NOALIAS: lr.w.aq a1, (a0) +lr.w.aq a1, 0(a0) + +# CHECK-S: lr.w.rl a1, (a0) +# CHECK-S-NOALIAS: lr.w.rl a1, (a0) +# CHECK-OBJ: lr.w.rl a1, (a0) +# CHECK-OBJ-NOALIAS: lr.w.rl a1, (a0) +lr.w.rl a1, 0(a0) + +# CHECK-S: lr.w.aqrl a1, (a0) +# CHECK-S-NOALIAS: lr.w.aqrl a1, (a0) +# CHECK-OBJ: lr.w.aqrl a1, (a0) +# CHECK-OBJ-NOALIAS: lr.w.aqrl a1, (a0) +lr.w.aqrl a1, 0(a0) + +# CHECK-S: sc.w a2, a1, (a0) +# CHECK-S-NOALIAS: sc.w a2, a1, (a0) +# CHECK-OBJ: sc.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: sc.w a2, a1, (a0) +sc.w a2, a1, 0(a0) + +# CHECK-S: sc.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: sc.w.aq a2, a1, (a0) +# CHECK-OBJ: sc.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: sc.w.aq a2, a1, (a0) +sc.w.aq a2, a1, 0(a0) + +# CHECK-S: sc.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: sc.w.rl a2, a1, (a0) +# CHECK-OBJ: sc.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: sc.w.rl a2, a1, (a0) +sc.w.rl a2, a1, 0(a0) + +# CHECK-S: sc.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: sc.w.aqrl a2, a1, (a0) +# CHECK-OBJ: sc.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: sc.w.aqrl a2, a1, (a0) +sc.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amoswap.w a2, a1, (a0) +# CHECK-S-NOALIAS: amoswap.w a2, a1, (a0) +# CHECK-OBJ: amoswap.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoswap.w a2, a1, (a0) +amoswap.w a2, a1, 0(a0) + +# CHECK-S: amoswap.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amoswap.w.aq a2, a1, (a0) +# CHECK-OBJ: amoswap.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoswap.w.aq a2, a1, (a0) +amoswap.w.aq a2, a1, 0(a0) + +# CHECK-S: amoswap.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amoswap.w.rl a2, a1, (a0) +# CHECK-OBJ: amoswap.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoswap.w.rl a2, a1, (a0) +amoswap.w.rl a2, a1, 0(a0) + +# CHECK-S: amoswap.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amoswap.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amoswap.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoswap.w.aqrl a2, a1, (a0) +amoswap.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amoadd.w a2, a1, (a0) +# CHECK-S-NOALIAS: amoadd.w a2, a1, (a0) +# CHECK-OBJ: amoadd.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoadd.w a2, a1, (a0) +amoadd.w a2, a1, 0(a0) + +# CHECK-S: amoadd.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amoadd.w.aq a2, a1, (a0) +# CHECK-OBJ: amoadd.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoadd.w.aq a2, a1, (a0) +amoadd.w.aq a2, a1, 0(a0) + +# CHECK-S: amoadd.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amoadd.w.rl a2, a1, (a0) +# CHECK-OBJ: amoadd.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoadd.w.rl a2, a1, (a0) +amoadd.w.rl a2, a1, 0(a0) + +# CHECK-S: amoadd.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amoadd.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amoadd.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoadd.w.aqrl a2, a1, (a0) +amoadd.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amoxor.w a2, a1, (a0) +# CHECK-S-NOALIAS: amoxor.w a2, a1, (a0) +# CHECK-OBJ: amoxor.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoxor.w a2, a1, (a0) +amoxor.w a2, a1, 0(a0) + +# CHECK-S: amoxor.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amoxor.w.aq a2, a1, (a0) +# CHECK-OBJ: amoxor.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoxor.w.aq a2, a1, (a0) +amoxor.w.aq a2, a1, 0(a0) + +# CHECK-S: amoxor.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amoxor.w.rl a2, a1, (a0) +# CHECK-OBJ: amoxor.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoxor.w.rl a2, a1, (a0) +amoxor.w.rl a2, a1, 0(a0) + +# CHECK-S: amoxor.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amoxor.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amoxor.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoxor.w.aqrl a2, a1, (a0) +amoxor.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amoand.w a2, a1, (a0) +# CHECK-S-NOALIAS: amoand.w a2, a1, (a0) +# CHECK-OBJ: amoand.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoand.w a2, a1, (a0) +amoand.w a2, a1, 0(a0) + +# CHECK-S: amoand.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amoand.w.aq a2, a1, (a0) +# CHECK-OBJ: amoand.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoand.w.aq a2, a1, (a0) +amoand.w.aq a2, a1, 0(a0) + +# CHECK-S: amoand.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amoand.w.rl a2, a1, (a0) +# CHECK-OBJ: amoand.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoand.w.rl a2, a1, (a0) +amoand.w.rl a2, a1, 0(a0) + +# CHECK-S: amoand.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amoand.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amoand.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoand.w.aqrl a2, a1, (a0) +amoand.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amoor.w a2, a1, (a0) +# CHECK-S-NOALIAS: amoor.w a2, a1, (a0) +# CHECK-OBJ: amoor.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoor.w a2, a1, (a0) +amoor.w a2, a1, 0(a0) + +# CHECK-S: amoor.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amoor.w.aq a2, a1, (a0) +# CHECK-OBJ: amoor.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoor.w.aq a2, a1, (a0) +amoor.w.aq a2, a1, 0(a0) + +# CHECK-S: amoor.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amoor.w.rl a2, a1, (a0) +# CHECK-OBJ: amoor.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoor.w.rl a2, a1, (a0) +amoor.w.rl a2, a1, 0(a0) + +# CHECK-S: amoor.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amoor.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amoor.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amoor.w.aqrl a2, a1, (a0) +amoor.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amomin.w a2, a1, (a0) +# CHECK-S-NOALIAS: amomin.w a2, a1, (a0) +# CHECK-OBJ: amomin.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomin.w a2, a1, (a0) +amomin.w a2, a1, 0(a0) + +# CHECK-S: amomin.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amomin.w.aq a2, a1, (a0) +# CHECK-OBJ: amomin.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomin.w.aq a2, a1, (a0) +amomin.w.aq a2, a1, 0(a0) + +# CHECK-S: amomin.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amomin.w.rl a2, a1, (a0) +# CHECK-OBJ: amomin.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomin.w.rl a2, a1, (a0) +amomin.w.rl a2, a1, 0(a0) + +# CHECK-S: amomin.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amomin.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amomin.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomin.w.aqrl a2, a1, (a0) +amomin.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amomax.w a2, a1, (a0) +# CHECK-S-NOALIAS: amomax.w a2, a1, (a0) +# CHECK-OBJ: amomax.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomax.w a2, a1, (a0) +amomax.w a2, a1, 0(a0) + +# CHECK-S: amomax.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amomax.w.aq a2, a1, (a0) +# CHECK-OBJ: amomax.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomax.w.aq a2, a1, (a0) +amomax.w.aq a2, a1, 0(a0) + +# CHECK-S: amomax.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amomax.w.rl a2, a1, (a0) +# CHECK-OBJ: amomax.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomax.w.rl a2, a1, (a0) +amomax.w.rl a2, a1, 0(a0) + +# CHECK-S: amomax.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amomax.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amomax.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomax.w.aqrl a2, a1, (a0) +amomax.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amominu.w a2, a1, (a0) +# CHECK-S-NOALIAS: amominu.w a2, a1, (a0) +# CHECK-OBJ: amominu.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amominu.w a2, a1, (a0) +amominu.w a2, a1, 0(a0) + +# CHECK-S: amominu.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amominu.w.aq a2, a1, (a0) +# CHECK-OBJ: amominu.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amominu.w.aq a2, a1, (a0) +amominu.w.aq a2, a1, 0(a0) + +# CHECK-S: amominu.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amominu.w.rl a2, a1, (a0) +# CHECK-OBJ: amominu.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amominu.w.rl a2, a1, (a0) +amominu.w.rl a2, a1, 0(a0) + +# CHECK-S: amominu.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amominu.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amominu.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amominu.w.aqrl a2, a1, (a0) +amominu.w.aqrl a2, a1, 0(a0) + +# CHECK-S: amomaxu.w a2, a1, (a0) +# CHECK-S-NOALIAS: amomaxu.w a2, a1, (a0) +# CHECK-OBJ: amomaxu.w a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomaxu.w a2, a1, (a0) +amomaxu.w a2, a1, 0(a0) + +# CHECK-S: amomaxu.w.aq a2, a1, (a0) +# CHECK-S-NOALIAS: amomaxu.w.aq a2, a1, (a0) +# CHECK-OBJ: amomaxu.w.aq a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomaxu.w.aq a2, a1, (a0) +amomaxu.w.aq a2, a1, 0(a0) + +# CHECK-S: amomaxu.w.rl a2, a1, (a0) +# CHECK-S-NOALIAS: amomaxu.w.rl a2, a1, (a0) +# CHECK-OBJ: amomaxu.w.rl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomaxu.w.rl a2, a1, (a0) +amomaxu.w.rl a2, a1, 0(a0) + +# CHECK-S: amomaxu.w.aqrl a2, a1, (a0) +# CHECK-S-NOALIAS: amomaxu.w.aqrl a2, a1, (a0) +# CHECK-OBJ: amomaxu.w.aqrl a2, a1, (a0) +# CHECK-OBJ-NOALIAS: amomaxu.w.aqrl a2, a1, (a0) +amomaxu.w.aqrl a2, a1, 0(a0)