diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index d43da911e22..2cf0f09ffc6 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -842,6 +842,14 @@ def c_imm : Operand { let PrintMethod = "printCImmediate"; let ParserMatchClass = CoprocRegAsmOperand; } +def CoprocOptionAsmOperand : AsmOperandClass { + let Name = "CoprocOption"; + let ParserMethod = "parseCoprocOptionOperand"; +} +def coproc_option_imm : Operand { + let PrintMethod = "printCoprocOptionImm"; + let ParserMatchClass = CoprocOptionAsmOperand; +} //===----------------------------------------------------------------------===// @@ -4312,8 +4320,8 @@ multiclass LdStCop { } def _OPTION : ACI<(outs), (ins p_imm:$cop, c_imm:$CRd, addr_offset_none:$addr, - nohash_imm:$option), - asm, "\t$cop, $CRd, $addr, \\{$option\\}"> { + coproc_option_imm:$option), + asm, "\t$cop, $CRd, $addr, $option"> { bits<8> option; bits<4> addr; bits<4> cop; @@ -4383,8 +4391,8 @@ multiclass LdSt2Cop { } def _OPTION : ACInoP<(outs), (ins p_imm:$cop, c_imm:$CRd, addr_offset_none:$addr, - nohash_imm:$option), - asm, "\t$cop, $CRd, $addr, \\{$option\\}"> { + coproc_option_imm:$option), + asm, "\t$cop, $CRd, $addr, $option"> { bits<8> option; bits<4> addr; bits<4> cop; diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index afb6e5684dd..3ce086a0491 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -138,6 +138,8 @@ class ARMAsmParser : public MCTargetAsmParser { SmallVectorImpl&); OperandMatchResultTy parseCoprocRegOperand( SmallVectorImpl&); + OperandMatchResultTy parseCoprocOptionOperand( + SmallVectorImpl&); OperandMatchResultTy parseMemBarrierOptOperand( SmallVectorImpl&); OperandMatchResultTy parseProcIFlagsOperand( @@ -247,6 +249,7 @@ class ARMOperand : public MCParsedAsmOperand { k_ITCondMask, k_CoprocNum, k_CoprocReg, + k_CoprocOption, k_Immediate, k_FPImmediate, k_MemBarrierOpt, @@ -279,6 +282,10 @@ class ARMOperand : public MCParsedAsmOperand { unsigned Val; } Cop; + struct { + unsigned Val; + } CoprocOption; + struct { unsigned Mask:4; } ITMask; @@ -390,6 +397,9 @@ public: case k_CoprocReg: Cop = o.Cop; break; + case k_CoprocOption: + CoprocOption = o.CoprocOption; + break; case k_Immediate: Imm = o.Imm; break; @@ -495,6 +505,7 @@ public: bool isCoprocNum() const { return Kind == k_CoprocNum; } bool isCoprocReg() const { return Kind == k_CoprocReg; } + bool isCoprocOption() const { return Kind == k_CoprocOption; } bool isCondCode() const { return Kind == k_CondCode; } bool isCCOut() const { return Kind == k_CCOut; } bool isITMask() const { return Kind == k_ITCondMask; } @@ -924,6 +935,16 @@ public: Inst.addOperand(MCOperand::CreateImm(getCoproc())); } + void addCoprocRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(getCoproc())); + } + + void addCoprocOptionOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(CoprocOption.Val)); + } + void addITMaskOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateImm(ITMask.Mask)); @@ -934,11 +955,6 @@ public: Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode()))); } - void addCoprocRegOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getCoproc())); - } - void addCCOutOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(getReg())); @@ -1453,6 +1469,14 @@ public: return Op; } + static ARMOperand *CreateCoprocOption(unsigned Val, SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(k_CoprocOption); + Op->Cop.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static ARMOperand *CreateCCOut(unsigned RegNum, SMLoc S) { ARMOperand *Op = new ARMOperand(k_CCOut); Op->Reg.RegNum = RegNum; @@ -1668,6 +1692,9 @@ void ARMOperand::print(raw_ostream &OS) const { case k_CoprocReg: OS << ""; break; + case k_CoprocOption: + OS << ""; + break; case k_MSRMask: OS << ""; break; @@ -2088,6 +2115,40 @@ parseCoprocRegOperand(SmallVectorImpl &Operands) { return MatchOperand_Success; } +/// parseCoprocOptionOperand - Try to parse an coprocessor option operand. +/// coproc_option : '{' imm0_255 '}' +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseCoprocOptionOperand(SmallVectorImpl &Operands) { + SMLoc S = Parser.getTok().getLoc(); + + // If this isn't a '{', this isn't a coprocessor immediate operand. + if (Parser.getTok().isNot(AsmToken::LCurly)) + return MatchOperand_NoMatch; + Parser.Lex(); // Eat the '{' + + const MCExpr *Expr; + SMLoc Loc = Parser.getTok().getLoc(); + if (getParser().ParseExpression(Expr)) { + Error(Loc, "illegal expression"); + return MatchOperand_ParseFail; + } + const MCConstantExpr *CE = dyn_cast(Expr); + if (!CE || CE->getValue() < 0 || CE->getValue() > 255) { + Error(Loc, "coprocessor option must be an immediate in range [0, 255]"); + return MatchOperand_ParseFail; + } + int Val = CE->getValue(); + + // Check for and consume the closing '}' + if (Parser.getTok().isNot(AsmToken::RCurly)) + return MatchOperand_ParseFail; + SMLoc E = Parser.getTok().getLoc(); + Parser.Lex(); // Eat the '}' + + Operands.push_back(ARMOperand::CreateCoprocOption(Val, S, E)); + return MatchOperand_Success; +} + // For register list parsing, we need to map from raw GPR register numbering // to the enumeration values. The enumeration values aren't sorted by // register number due to our using "sp", "lr" and "pc" as canonical names. diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp index 81608922842..ccdac3ebeb4 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -719,6 +719,11 @@ void ARMInstPrinter::printCImmediate(const MCInst *MI, unsigned OpNum, O << "c" << MI->getOperand(OpNum).getImm(); } +void ARMInstPrinter::printCoprocOptionImm(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + O << "{" << MI->getOperand(OpNum).getImm() << "}"; +} + void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum, raw_ostream &O) { llvm_unreachable("Unhandled PC-relative pseudo-instruction!"); diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h index 61b26e67924..5c2173fcde6 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h @@ -120,6 +120,7 @@ public: void printNoHashImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printPImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printCImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printCoprocOptionImm(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printFPImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printNEONModImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printImmPlusOneOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); diff --git a/test/MC/ARM/basic-arm-instructions.s b/test/MC/ARM/basic-arm-instructions.s index 04054e95c0e..8b4c0536c95 100644 --- a/test/MC/ARM/basic-arm-instructions.s +++ b/test/MC/ARM/basic-arm-instructions.s @@ -684,6 +684,8 @@ Lforward: ldcleq p6, c14, [r10], #16 ldclhi p7, c15, [r11], #-72 + ldc2 p2, c8, [r1], { 25 } + @ CHECK: ldc2 p0, c8, [r1, #4] @ encoding: [0x01,0x80,0x91,0xfd] @ CHECK: ldc2 p1, c7, [r2] @ encoding: [0x00,0x71,0x92,0xfd] @ CHECK: ldc2 p2, c6, [r3, #-224] @ encoding: [0x38,0x62,0x13,0xfd] @@ -723,6 +725,8 @@ Lforward: @ CHECK: ldcleq p6, c14, [r10], #16 @ encoding: [0x04,0xe6,0xfa,0x0c] @ CHECK: ldclhi p7, c15, [r11], #-72 @ encoding: [0x12,0xf7,0x7b,0x8c] +@ CHECK: ldc2 p2, c8, [r1], {25} @ encoding: [0x19,0x82,0x91,0xfc] + @------------------------------------------------------------------------------ @ LDM* diff --git a/test/MC/ARM/diagnostics.s b/test/MC/ARM/diagnostics.s index 41dde080522..f722dd7c070 100644 --- a/test/MC/ARM/diagnostics.s +++ b/test/MC/ARM/diagnostics.s @@ -305,3 +305,13 @@ @ CHECK-ERRORS: vpush {s0, s3} @ CHECK-ERRORS: ^ + @ Out of range coprocessor option immediate. + ldc2 p2, c8, [r1], { 256 } + ldc2 p2, c8, [r1], { -1 } + +@ CHECK-ERRORS: error: coprocessor option must be an immediate in range [0, 255] +@ CHECK-ERRORS: ldc2 p2, c8, [r1], { 256 } +@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: error: coprocessor option must be an immediate in range [0, 255] +@ CHECK-ERRORS: ldc2 p2, c8, [r1], { -1 } +@ CHECK-ERRORS: ^ diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index a38f0066d98..abef70e3189 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -581,6 +581,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, IMM("nohash_imm"); IMM("p_imm"); IMM("c_imm"); + IMM("coproc_option_imm"); IMM("imod_op"); IMM("iflags_op"); IMM("cpinst_operand");