From 584bf7bb03e4cf1475b26851edcc1ddb66b85028 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Fri, 18 Feb 2011 19:45:59 +0000 Subject: [PATCH] Add assembly parsing support for "msr" and also fix its encoding. Also add testcases for the disassembler to make sure it still works for "msr". git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@125948 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstrFormats.td | 7 ++ lib/Target/ARM/ARMInstrInfo.td | 50 ++++++---- lib/Target/ARM/ARMInstrThumb2.td | 29 +++--- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 95 +++++++++++++++++++ .../ARM/Disassembler/ARMDisassemblerCore.cpp | 18 ++-- .../ARM/Disassembler/ThumbDisassemblerCore.h | 8 +- lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp | 9 +- test/MC/ARM/arm_instructions.s | 36 +++++++ test/MC/ARM/thumb2.s | 25 +++++ test/MC/Disassembler/ARM/arm-tests.txt | 3 + test/MC/Disassembler/ARM/thumb-tests.txt | 3 + 11 files changed, 236 insertions(+), 47 deletions(-) diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 24587cb6f69..765cba42d0b 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -161,6 +161,12 @@ def ProcIFlagsOperand : AsmOperandClass { let ParserMethod = "tryParseProcIFlagsOperand"; } +def MSRMaskOperand : AsmOperandClass { + let Name = "MSRMask"; + let SuperClasses = []; + let ParserMethod = "tryParseMSRMaskOperand"; +} + // ARM imod and iflag operands, used only by the CPS instruction. def imod_op : Operand { let PrintMethod = "printCPSIMod"; @@ -205,6 +211,7 @@ def cps_opt : Operand { def msr_mask : Operand { let PrintMethod = "printMSRMaskOperand"; + let ParserMatchClass = MSRMaskOperand; } // A8.6.117, A8.6.118. Different instructions are generated for #0 and #-0. diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index c66bc139152..c827ce3da97 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -3856,6 +3856,7 @@ def MRRC2 : MovRRCopro2<"mrrc2", 1 /* from coprocessor to ARM core register */>; // Move between special register and ARM core register -- for disassembly only // +// Move to ARM core register from Special Register def MRS : ABI<0b0001, (outs GPR:$Rd), (ins), NoItinerary, "mrs", "\t$Rd, cpsr", [/* For disassembly only; pattern left blank */]> { bits<4> Rd; @@ -3872,30 +3873,37 @@ def MRSsys : ABI<0b0001, (outs GPR:$Rd), (ins), NoItinerary,"mrs","\t$Rd, spsr", let Inst{7-4} = 0b0000; } -def MSR : ABI<0b0001, (outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, - "msr", "\tcpsr$mask, $src", +// Move from ARM core register to Special Register +// +// No need to have both system and application versions, the encodings are the +// same and the assembly parser has no way to distinguish between them. The mask +// operand contains the special register (R Bit) in bit 4 and bits 3-0 contains +// the mask with the fields to be accessed in the special register. +def MSR : ABI<0b0001, (outs), (ins msr_mask:$mask, GPR:$Rn), NoItinerary, + "msr", "\t$mask, $Rn", [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0010; - let Inst{7-4} = 0b0000; -} + bits<5> mask; + bits<4> Rn; -def MSRi : ABI<0b0011, (outs), (ins so_imm:$a, msr_mask:$mask), NoItinerary, - "msr", "\tcpsr$mask, $a", - [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0010; - let Inst{7-4} = 0b0000; + let Inst{23} = 0; + let Inst{22} = mask{4}; // R bit + let Inst{21-20} = 0b10; + let Inst{19-16} = mask{3-0}; + let Inst{15-12} = 0b1111; + let Inst{11-4} = 0b00000000; + let Inst{3-0} = Rn; } -def MSRsys : ABI<0b0001, (outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, - "msr", "\tspsr$mask, $src", - [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0110; - let Inst{7-4} = 0b0000; -} +def MSRi : ABI<0b0011, (outs), (ins msr_mask:$mask, so_imm:$a), NoItinerary, + "msr", "\t$mask, $a", + [/* For disassembly only; pattern left blank */]> { + bits<5> mask; + bits<12> a; -def MSRsysi : ABI<0b0011, (outs), (ins so_imm:$a, msr_mask:$mask), NoItinerary, - "msr", "\tspsr$mask, $a", - [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0110; - let Inst{7-4} = 0b0000; + let Inst{23} = 0; + let Inst{22} = mask{4}; // R bit + let Inst{21-20} = 0b10; + let Inst{19-16} = mask{3-0}; + let Inst{15-12} = 0b1111; + let Inst{11-0} = a; } diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 2c2cf46f960..0e01be59c7e 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -3330,25 +3330,24 @@ def t2MRSsys : T2MRS<0b111100111111, 0b10, 0, (outs rGPR:$Rd), (ins), NoItinerary, "mrs", "\t$Rd, spsr", [/* For disassembly only; pattern left blank */]>; -class T2MSR op31_20, bits<2> op15_14, bits<1> op12, - dag oops, dag iops, InstrItinClass itin, - string opc, string asm, list pattern> - : T2SpecialReg { +// Move from ARM core register to Special Register +// +// No need to have both system and application versions, the encodings are the +// same and the assembly parser has no way to distinguish between them. The mask +// operand contains the special register (R Bit) in bit 4 and bits 3-0 contains +// the mask with the fields to be accessed in the special register. +def t2MSR : T2SpecialReg<0b111100111000 /* op31-20 */, 0b10 /* op15-14 */, + 0 /* op12 */, (outs), (ins msr_mask:$mask, rGPR:$Rn), + NoItinerary, "msr", "\t$mask, $Rn", + [/* For disassembly only; pattern left blank */]> { + bits<5> mask; bits<4> Rn; - bits<4> mask; let Inst{19-16} = Rn; - let Inst{11-8} = mask; + let Inst{20} = mask{4}; // R Bit + let Inst{13} = 0b0; + let Inst{11-8} = mask{3-0}; } -def t2MSR : T2MSR<0b111100111000, 0b10, 0, - (outs), (ins rGPR:$Rn, msr_mask:$mask), NoItinerary, "msr", - "\tcpsr$mask, $Rn", - [/* For disassembly only; pattern left blank */]>; -def t2MSRsys : T2MSR<0b111100111001, 0b10, 0, - (outs), (ins rGPR:$Rn, msr_mask:$mask), NoItinerary, "msr", - "\tspsr$mask, $Rn", - [/* For disassembly only; pattern left blank */]>; - //===----------------------------------------------------------------------===// // Move between coprocessor and ARM core register -- for disassembly only // diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index e9a507088a6..7cd0394fdfd 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -100,6 +100,8 @@ class ARMAsmParser : public TargetAsmParser { SmallVectorImpl &); OperandMatchResultTy tryParseProcIFlagsOperand( SmallVectorImpl &); + OperandMatchResultTy tryParseMSRMaskOperand( + SmallVectorImpl &); public: ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM) @@ -128,6 +130,7 @@ class ARMOperand : public MCParsedAsmOperand { Immediate, MemBarrierOpt, Memory, + MSRMask, ProcIFlags, Register, RegisterList, @@ -156,6 +159,10 @@ class ARMOperand : public MCParsedAsmOperand { ARM_PROC::IFlags Val; } IFlags; + struct { + unsigned Val; + } MMask; + struct { const char *Data; unsigned Length; @@ -222,6 +229,9 @@ public: case Memory: Mem = o.Mem; break; + case MSRMask: + MMask = o.MMask; + break; case ProcIFlags: IFlags = o.IFlags; } @@ -273,6 +283,11 @@ public: return IFlags.Val; } + unsigned getMSRMask() const { + assert(Kind == MSRMask && "Invalid access!"); + return MMask.Val; + } + /// @name Memory Operand Accessors /// @{ @@ -347,6 +362,7 @@ public: uint64_t Value = CE->getValue(); return ((Value & 0x3) == 0 && Value <= 124); } + bool isMSRMask() const { return Kind == MSRMask; } bool isProcIFlags() const { return Kind == ProcIFlags; } void addExpr(MCInst &Inst, const MCExpr *Expr) const { @@ -448,6 +464,11 @@ public: Inst.addOperand(MCOperand::CreateImm(CE->getValue())); } + void addMSRMaskOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(unsigned(getMSRMask()))); + } + void addProcIFlagsOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateImm(unsigned(getProcIFlags()))); @@ -584,6 +605,14 @@ public: Op->EndLoc = S; return Op; } + + static ARMOperand *CreateMSRMask(unsigned MMask, SMLoc S) { + ARMOperand *Op = new ARMOperand(MSRMask); + Op->MMask.Val = MMask; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } }; } // end anonymous namespace. @@ -602,6 +631,9 @@ void ARMOperand::dump(raw_ostream &OS) const { case CoprocReg: OS << ""; break; + case MSRMask: + OS << ""; + break; case Immediate: getImm()->print(OS); break; @@ -950,6 +982,69 @@ tryParseProcIFlagsOperand(SmallVectorImpl &Operands) { return MatchOperand_Success; } +/// tryParseMSRMaskOperand - Try to parse mask flags from MSR instruction. +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +tryParseMSRMaskOperand(SmallVectorImpl &Operands) { + SMLoc S = Parser.getTok().getLoc(); + const AsmToken &Tok = Parser.getTok(); + assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); + StringRef Mask = Tok.getString(); + + // Split spec_reg from flag, example: CPSR_sxf => "CPSR" and "sxf" + size_t Start = 0, Next = Mask.find('_'); + StringRef Flags = ""; + StringRef SpecReg = Mask.slice(Start, Next); + if (Next != StringRef::npos) + Flags = Mask.slice(Next+1, Mask.size()); + + // FlagsVal contains the complete mask: + // 3-0: Mask + // 4: Special Reg (cpsr, apsr => 0; spsr => 1) + unsigned FlagsVal = 0; + + if (SpecReg == "apsr") { + FlagsVal = StringSwitch(Flags) + .Case("nzcvq", 0x8) // same as CPSR_c + .Case("g", 0x4) // same as CPSR_s + .Case("nzcvqg", 0xc) // same as CPSR_fs + .Default(~0U); + + if (FlagsVal == ~0U) + if (!Flags.empty()) + return MatchOperand_NoMatch; + else + FlagsVal = 0; // No flag + } else if (SpecReg == "cpsr" || SpecReg == "spsr") { + for (int i = 0, e = Flags.size(); i != e; ++i) { + unsigned Flag = StringSwitch(Flags.substr(i, 1)) + .Case("c", 1) + .Case("x", 2) + .Case("s", 4) + .Case("f", 8) + .Default(~0U); + + // If some specific flag is already set, it means that some letter is + // present more than once, this is not acceptable. + if (FlagsVal == ~0U || (FlagsVal & Flag)) + return MatchOperand_NoMatch; + FlagsVal |= Flag; + } + } else // No match for special register. + return MatchOperand_NoMatch; + + // Special register without flags are equivalent to "fc" flags. + if (!FlagsVal) + FlagsVal = 0x9; + + // Bit 4: Special Reg (cpsr, apsr => 0; spsr => 1) + if (SpecReg == "spsr") + FlagsVal |= 16; + + Parser.Lex(); // Eat identifier token. + Operands.push_back(ARMOperand::CreateMSRMask(FlagsVal, S)); + return MatchOperand_Success; +} + /// Parse an ARM memory expression, return false if successful else return true /// or an error. The first token must be a '[' when called. /// diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp index 06ad61e9b35..bac68dd9ead 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp @@ -720,25 +720,29 @@ static bool DisassembleBrFrm(MCInst &MI, unsigned Opcode, uint32_t insn, NumOpsAdded = 1; return true; } - // MSR and MSRsys take one GPR reg Rm, followed by the mask. - if (Opcode == ARM::MSR || Opcode == ARM::MSRsys) { - assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID && + // MSR take a mask, followed by one GPR reg Rm. The mask contains the R Bit in + // bit 4, and the special register fields in bits 3-0. + if (Opcode == ARM::MSR) { + assert(NumOps >= 1 && OpInfo[1].RegClass == ARM::GPRRegClassID && "Reg operand expected"); + MI.addOperand(MCOperand::CreateImm(slice(insn, 22, 22) << 4 /* R Bit */ | + slice(insn, 19, 16) /* Special Reg */ )); MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, decodeRm(insn)))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); NumOpsAdded = 2; return true; } - // MSRi and MSRsysi take one so_imm operand, followed by the mask. - if (Opcode == ARM::MSRi || Opcode == ARM::MSRsysi) { + // MSRi take a mask, followed by one so_imm operand. The mask contains the + // R Bit in bit 4, and the special register fields in bits 3-0. + if (Opcode == ARM::MSRi) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 22, 22) << 4 /* R Bit */ | + slice(insn, 19, 16) /* Special Reg */ )); // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0. // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}. // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot(). unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF; unsigned Imm = insn & 0xFF; MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); NumOpsAdded = 2; return true; } diff --git a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h index d1428169f7b..23372e02241 100644 --- a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h +++ b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h @@ -1702,11 +1702,13 @@ static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode, NumOpsAdded = 1; return true; } - // MSR and MSRsys take one GPR reg Rn, followed by the mask. - if (Opcode == ARM::t2MSR || Opcode == ARM::t2MSRsys || Opcode == ARM::t2BXJ) { + // MSR take a mask, followed by one GPR reg Rn. The mask contains the R Bit in + // bit 4, and the special register fields in bits 3-0. + if (Opcode == ARM::t2MSR) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 20, 20) << 4 /* R Bit */ | + slice(insn, 11, 8) /* Special Reg */)); MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn)))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8))); NumOpsAdded = 2; return true; } diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp index aace2f97233..1499da00ae1 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -397,7 +397,14 @@ void ARMInstPrinter::printCPSIFlag(const MCInst *MI, unsigned OpNum, void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O) { const MCOperand &Op = MI->getOperand(OpNum); - unsigned Mask = Op.getImm(); + unsigned SpecRegRBit = Op.getImm() >> 4; + unsigned Mask = Op.getImm() & 0xf; + + if (SpecRegRBit) + O << "spsr"; + else + O << "cpsr"; + if (Mask) { O << '_'; if (Mask & 8) O << 'f'; diff --git a/test/MC/ARM/arm_instructions.s b/test/MC/ARM/arm_instructions.s index 291a76131c6..fbec7891c80 100644 --- a/test/MC/ARM/arm_instructions.s +++ b/test/MC/ARM/arm_instructions.s @@ -246,3 +246,39 @@ @ CHECK: cpsie if, #10 @ encoding: [0xca,0x00,0x0a,0xf1] cpsie if, #10 +@ CHECK: msr cpsr_fc, r0 @ encoding: [0x00,0xf0,0x29,0xe1] + msr apsr, r0 + +@ CHECK: msr cpsr_s, r0 @ encoding: [0x00,0xf0,0x24,0xe1] + msr apsr_g, r0 + +@ CHECK: msr cpsr_f, r0 @ encoding: [0x00,0xf0,0x28,0xe1] + msr apsr_nzcvq, r0 + +@ CHECK: msr cpsr_fs, r0 @ encoding: [0x00,0xf0,0x2c,0xe1] + msr apsr_nzcvqg, r0 + +@ CHECK: msr cpsr_fc, r0 @ encoding: [0x00,0xf0,0x29,0xe1] + msr cpsr_fc, r0 + +@ CHECK: msr cpsr_c, r0 @ encoding: [0x00,0xf0,0x21,0xe1] + msr cpsr_c, r0 + +@ CHECK: msr cpsr_x, r0 @ encoding: [0x00,0xf0,0x22,0xe1] + msr cpsr_x, r0 + +@ CHECK: msr cpsr_fc, r0 @ encoding: [0x00,0xf0,0x29,0xe1] + msr cpsr_fc, r0 + +@ CHECK: msr cpsr_fsx, r0 @ encoding: [0x00,0xf0,0x2e,0xe1] + msr cpsr_fsx, r0 + +@ CHECK: msr spsr_fc, r0 @ encoding: [0x00,0xf0,0x69,0xe1] + msr spsr_fc, r0 + +@ CHECK: msr spsr_fsxc, r0 @ encoding: [0x00,0xf0,0x6f,0xe1] + msr spsr_fsxc, r0 + +@ CHECK: msr cpsr_fsxc, r0 @ encoding: [0x00,0xf0,0x2f,0xe1] + msr cpsr_fsxc, r0 + diff --git a/test/MC/ARM/thumb2.s b/test/MC/ARM/thumb2.s index be4e555dc45..cd093119e58 100644 --- a/test/MC/ARM/thumb2.s +++ b/test/MC/ARM/thumb2.s @@ -259,3 +259,28 @@ @ CHECK: cpsie.w if, #10 @ encoding: [0xaf,0xf3,0x6a,0x85] cpsie.w if, #10 +@ CHECK: msr cpsr_fc, r0 @ encoding: [0x80,0xf3,0x00,0x89] + msr apsr, r0 +@ CHECK: msr cpsr_s, r0 @ encoding: [0x80,0xf3,0x00,0x84] + msr apsr_g, r0 +@ CHECK: msr cpsr_f, r0 @ encoding: [0x80,0xf3,0x00,0x88] + msr apsr_nzcvq, r0 +@ CHECK: msr cpsr_fs, r0 @ encoding: [0x80,0xf3,0x00,0x8c] + msr apsr_nzcvqg, r0 +@ CHECK: msr cpsr_fc, r0 @ encoding: [0x80,0xf3,0x00,0x89] + msr cpsr_fc, r0 +@ CHECK: msr cpsr_c, r0 @ encoding: [0x80,0xf3,0x00,0x81] + msr cpsr_c, r0 +@ CHECK: msr cpsr_x, r0 @ encoding: [0x80,0xf3,0x00,0x82] + msr cpsr_x, r0 +@ CHECK: msr cpsr_fc, r0 @ encoding: [0x80,0xf3,0x00,0x89] + msr cpsr_fc, r0 +@ CHECK: msr cpsr_fsx, r0 @ encoding: [0x80,0xf3,0x00,0x8e] + msr cpsr_fsx, r0 +@ CHECK: msr spsr_fc, r0 @ encoding: [0x90,0xf3,0x00,0x89] + msr spsr_fc, r0 +@ CHECK: msr spsr_fsxc, r0 @ encoding: [0x90,0xf3,0x00,0x8f] + msr spsr_fsxc, r0 +@ CHECK: msr cpsr_fsxc, r0 @ encoding: [0x80,0xf3,0x00,0x8f] + msr cpsr_fsxc, r0 + diff --git a/test/MC/Disassembler/ARM/arm-tests.txt b/test/MC/Disassembler/ARM/arm-tests.txt index 26bd182d78a..0f6aeb7052b 100644 --- a/test/MC/Disassembler/ARM/arm-tests.txt +++ b/test/MC/Disassembler/ARM/arm-tests.txt @@ -127,3 +127,6 @@ # CHECK: cpsie if, #10 0xca 0x00 0x0a 0xf1 + +# CHECK: msr cpsr_fc, r0 +0x00 0xf0 0x29 0xe1 diff --git a/test/MC/Disassembler/ARM/thumb-tests.txt b/test/MC/Disassembler/ARM/thumb-tests.txt index 4e8bc9baa26..6dab1237a11 100644 --- a/test/MC/Disassembler/ARM/thumb-tests.txt +++ b/test/MC/Disassembler/ARM/thumb-tests.txt @@ -115,3 +115,6 @@ # CHECK: cpsie aif 0x67 0xb6 + +# CHECK: msr cpsr_fc, r0 +0x80 0xf3 0x00 0x89 -- 2.34.1