Index: lib/Target/ARM/ARMInstrThumb2.td =================================================================== --- lib/Target/ARM/ARMInstrThumb2.td +++ lib/Target/ARM/ARMInstrThumb2.td @@ -4013,15 +4013,17 @@ // // This MRS has a mask field in bits 7-0 and can take more values than // the A/R class (a full msr_mask). -def t2MRS_M : T2I<(outs rGPR:$Rd), (ins msr_mask:$mask), NoItinerary, - "mrs", "\t$Rd, $mask", []>, +def t2MRS_M : T2I<(outs rGPR:$Rd), (ins msr_mask:$SYSm), NoItinerary, + "mrs", "\t$Rd, $SYSm", []>, Requires<[IsThumb,IsMClass]> { bits<4> Rd; - bits<8> mask; + bits<8> SYSm; let Inst{31-12} = 0b11110011111011111000; let Inst{11-8} = Rd; - let Inst{19-16} = 0b1111; - let Inst{7-0} = mask; + let Inst{7-0} = SYSm; + + let Unpredictable{20-16} = 0b11111; + let Unpredictable{13} = 0b1; } @@ -4077,7 +4079,13 @@ let Inst{20} = 0b0; let Inst{19-16} = Rn; let Inst{15-12} = 0b1000; - let Inst{11-0} = SYSm; + let Inst{11-10} = SYSm{11-10}; + let Inst{9-8} = 0b00; + let Inst{7-0} = SYSm{7-0}; + + let Unpredictable{20} = 0b1; + let Unpredictable{13} = 0b1; + let Unpredictable{9-8} = 0b11; } Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -265,6 +265,9 @@ bool hasARM() const { return !(STI.getFeatureBits() & ARM::FeatureNoARM); } + bool hasThumb2DSP() const { + return STI.getFeatureBits() & ARM::FeatureDSPThumb2; + } void SwitchMode() { uint64_t FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb)); @@ -3928,9 +3931,6 @@ // should really only be allowed when writing a special register. Note // they get dropped in the MRS instruction reading a special register as // the SYSm field is only 8 bits. - // - // FIXME: the _g and _nzcvqg versions are only allowed if the processor - // includes the DSP extension but that is not checked. .Case("apsr", 0x800) .Case("apsr_nzcvq", 0x800) .Case("apsr_g", 0x400) @@ -3962,6 +3962,11 @@ if (FlagsVal == ~0U) return MatchOperand_NoMatch; + if (!hasThumb2DSP() && (FlagsVal & 0x400)) + // The _g and _nzcvqg versions are only valid if the DSP extension is + // available. + return MatchOperand_NoMatch; + if (!hasV7Ops() && FlagsVal >= 0x811 && FlagsVal <= 0x813) // basepri, basepri_max and faultmask only valid for V7m. return MatchOperand_NoMatch; Index: lib/Target/ARM/Disassembler/ARMDisassembler.cpp =================================================================== --- lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -3976,6 +3976,7 @@ static DecodeStatus DecodeMSRMask(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; uint64_t FeatureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() .getFeatureBits(); if (FeatureBits & ARM::FeatureMClass) { @@ -4006,17 +4007,25 @@ return MCDisassembler::Fail; } - // The ARMv7-M architecture has an additional 2-bit mask value in the MSR - // instruction (bits {11,10}). The mask is used only with apsr, iapsr, - // eapsr and xpsr, it has to be 0b10 in other cases. Bit mask{1} indicates - // if the NZCVQ bits should be moved by the instruction. Bit mask{0} - // indicates the move for the GE{3:0} bits, the mask{0} bit can be set - // only if the processor includes the DSP extension. - if ((FeatureBits & ARM::HasV7Ops) && Inst.getOpcode() == ARM::t2MSR_M) { - unsigned Mask = (Val >> 10) & 3; - if (Mask == 0 || (Mask != 2 && ValLow > 3) || - (!(FeatureBits & ARM::FeatureDSPThumb2) && Mask == 1)) - return MCDisassembler::Fail; + if (Inst.getOpcode() == ARM::t2MSR_M) { + unsigned Mask = fieldFromInstruction(Val, 10, 2); + if (!(FeatureBits & ARM::HasV7Ops)) { + // The ARMv6-M MSR bits {11-10} can be only 0b10, other values are + // unpredictable. + if (Mask != 2) + S = MCDisassembler::SoftFail; + } + else { + // The ARMv7-M architecture stores an additional 2-bit mask value in + // MSR bits {11-10}. The mask is used only with apsr, iapsr, eapsr and + // xpsr, it has to be 0b10 in other cases. Bit mask{1} indicates if + // the NZCVQ bits should be moved by the instruction. Bit mask{0} + // indicates the move for the GE{3:0} bits, the mask{0} bit can be set + // only if the processor includes the DSP extension. + if (Mask == 0 || (Mask != 2 && ValLow > 3) || + (!(FeatureBits & ARM::FeatureDSPThumb2) && (Mask & 1))) + S = MCDisassembler::SoftFail; + } } } else { // A/R class @@ -4024,7 +4033,7 @@ return MCDisassembler::Fail; } Inst.addOperand(MCOperand::CreateImm(Val)); - return MCDisassembler::Success; + return S; } static DecodeStatus DecodeBankedReg(MCInst &Inst, unsigned Val, Index: lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp =================================================================== --- lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -807,52 +807,56 @@ const MCOperand &Op = MI->getOperand(OpNum); unsigned SpecRegRBit = Op.getImm() >> 4; unsigned Mask = Op.getImm() & 0xf; + uint64_t FeatureBits = getAvailableFeatures(); - if (getAvailableFeatures() & ARM::FeatureMClass) { + if (FeatureBits & ARM::FeatureMClass) { unsigned SYSm = Op.getImm(); unsigned Opcode = MI->getOpcode(); - // For reads of the special registers ignore the "mask encoding" bits - // which are only for writes. - if (Opcode == ARM::t2MRS_M) - SYSm &= 0xff; + + // For writes, handle extended mask bits if the DSP extension is present. + if (Opcode == ARM::t2MSR_M && (FeatureBits & ARM::FeatureDSPThumb2)) { + switch (SYSm) { + case 0x400: O << "apsr_g"; return; + case 0xc00: O << "apsr_nzcvqg"; return; + case 0x401: O << "iapsr_g"; return; + case 0xc01: O << "iapsr_nzcvqg"; return; + case 0x402: O << "eapsr_g"; return; + case 0xc02: O << "eapsr_nzcvqg"; return; + case 0x403: O << "xpsr_g"; return; + case 0xc03: O << "xpsr_nzcvqg"; return; + } + } + + // Handle the basic 8-bit mask. + SYSm &= 0xff; + + if (Opcode == ARM::t2MSR_M && (FeatureBits & ARM::HasV7Ops)) { + // ARMv7-M deprecates using MSR APSR without a _ qualifier as an + // alias for MSR APSR_nzcvq. + switch (SYSm) { + case 0: O << "apsr_nzcvq"; return; + case 1: O << "iapsr_nzcvq"; return; + case 2: O << "eapsr_nzcvq"; return; + case 3: O << "xpsr_nzcvq"; return; + } + } + switch (SYSm) { default: llvm_unreachable("Unexpected mask value!"); - case 0: - case 0x800: O << "apsr"; return; // with _nzcvq bits is an alias for aspr - case 0x400: O << "apsr_g"; return; - case 0xc00: O << "apsr_nzcvqg"; return; - case 1: - case 0x801: O << "iapsr"; return; // with _nzcvq bits is an alias for iapsr - case 0x401: O << "iapsr_g"; return; - case 0xc01: O << "iapsr_nzcvqg"; return; - case 2: - case 0x802: O << "eapsr"; return; // with _nzcvq bits is an alias for eapsr - case 0x402: O << "eapsr_g"; return; - case 0xc02: O << "eapsr_nzcvqg"; return; - case 3: - case 0x803: O << "xpsr"; return; // with _nzcvq bits is an alias for xpsr - case 0x403: O << "xpsr_g"; return; - case 0xc03: O << "xpsr_nzcvqg"; return; - case 5: - case 0x805: O << "ipsr"; return; - case 6: - case 0x806: O << "epsr"; return; - case 7: - case 0x807: O << "iepsr"; return; - case 8: - case 0x808: O << "msp"; return; - case 9: - case 0x809: O << "psp"; return; - case 0x10: - case 0x810: O << "primask"; return; - case 0x11: - case 0x811: O << "basepri"; return; - case 0x12: - case 0x812: O << "basepri_max"; return; - case 0x13: - case 0x813: O << "faultmask"; return; - case 0x14: - case 0x814: O << "control"; return; + case 0: O << "apsr"; return; + case 1: O << "iapsr"; return; + case 2: O << "eapsr"; return; + case 3: O << "xpsr"; return; + case 5: O << "ipsr"; return; + case 6: O << "epsr"; return; + case 7: O << "iepsr"; return; + case 8: O << "msp"; return; + case 9: O << "psp"; return; + case 16: O << "primask"; return; + case 17: O << "basepri"; return; + case 18: O << "basepri_max"; return; + case 19: O << "faultmask"; return; + case 20: O << "control"; return; } } Index: test/MC/ARM/thumb2-mclass.s =================================================================== --- test/MC/ARM/thumb2-mclass.s +++ test/MC/ARM/thumb2-mclass.s @@ -1,7 +1,7 @@ -@ RUN: llvm-mc -triple=thumbv7m-apple-darwin -show-encoding < %s | FileCheck %s -@ RUN: llvm-mc -triple=thumbv6m -show-encoding < %s | FileCheck %s +@ RUN: llvm-mc -triple=thumbv6m -show-encoding < %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-V6M %s +@ RUN: llvm-mc -triple=thumbv7m -show-encoding < %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-V7M %s + .syntax unified - .globl _func @ Check that the assembler can handle the documented syntax from the ARM ARM. @ These tests test instruction encodings specific to v6m & v7m (FeatureMClass). @@ -40,20 +40,12 @@ msr apsr, r0 msr apsr_nzcvq, r0 - msr apsr_g, r0 - msr apsr_nzcvqg, r0 msr iapsr, r0 msr iapsr_nzcvq, r0 - msr iapsr_g, r0 - msr iapsr_nzcvqg, r0 msr eapsr, r0 msr eapsr_nzcvq, r0 - msr eapsr_g, r0 - msr eapsr_nzcvqg, r0 msr xpsr, r0 msr xpsr_nzcvq, r0 - msr xpsr_g, r0 - msr xpsr_nzcvqg, r0 msr ipsr, r0 msr epsr, r0 msr iepsr, r0 @@ -62,22 +54,22 @@ msr primask, r0 msr control, r0 -@ CHECK: msr apsr, r0 @ encoding: [0x80,0xf3,0x00,0x88] -@ CHECK: msr apsr, r0 @ encoding: [0x80,0xf3,0x00,0x88] -@ CHECK: msr apsr_g, r0 @ encoding: [0x80,0xf3,0x00,0x84] -@ CHECK: msr apsr_nzcvqg, r0 @ encoding: [0x80,0xf3,0x00,0x8c] -@ CHECK: msr iapsr, r0 @ encoding: [0x80,0xf3,0x01,0x88] -@ CHECK: msr iapsr, r0 @ encoding: [0x80,0xf3,0x01,0x88] -@ CHECK: msr iapsr_g, r0 @ encoding: [0x80,0xf3,0x01,0x84] -@ CHECK: msr iapsr_nzcvqg, r0 @ encoding: [0x80,0xf3,0x01,0x8c] -@ CHECK: msr eapsr, r0 @ encoding: [0x80,0xf3,0x02,0x88] -@ CHECK: msr eapsr, r0 @ encoding: [0x80,0xf3,0x02,0x88] -@ CHECK: msr eapsr_g, r0 @ encoding: [0x80,0xf3,0x02,0x84] -@ CHECK: msr eapsr_nzcvqg, r0 @ encoding: [0x80,0xf3,0x02,0x8c] -@ CHECK: msr xpsr, r0 @ encoding: [0x80,0xf3,0x03,0x88] -@ CHECK: msr xpsr, r0 @ encoding: [0x80,0xf3,0x03,0x88] -@ CHECK: msr xpsr_g, r0 @ encoding: [0x80,0xf3,0x03,0x84] -@ CHECK: msr xpsr_nzcvqg, r0 @ encoding: [0x80,0xf3,0x03,0x8c] +@ CHECK-V6M: msr apsr, r0 @ encoding: [0x80,0xf3,0x00,0x88] +@ CHECK-V6M: msr apsr, r0 @ encoding: [0x80,0xf3,0x00,0x88] +@ CHECK-V6M: msr iapsr, r0 @ encoding: [0x80,0xf3,0x01,0x88] +@ CHECK-V6M: msr iapsr, r0 @ encoding: [0x80,0xf3,0x01,0x88] +@ CHECK-V6M: msr eapsr, r0 @ encoding: [0x80,0xf3,0x02,0x88] +@ CHECK-V6M: msr eapsr, r0 @ encoding: [0x80,0xf3,0x02,0x88] +@ CHECK-V6M: msr xpsr, r0 @ encoding: [0x80,0xf3,0x03,0x88] +@ CHECK-V6M: msr xpsr, r0 @ encoding: [0x80,0xf3,0x03,0x88] +@ CHECK-V7M: msr apsr_nzcvq, r0 @ encoding: [0x80,0xf3,0x00,0x88] +@ CHECK-V7M: msr apsr_nzcvq, r0 @ encoding: [0x80,0xf3,0x00,0x88] +@ CHECK-V7M: msr iapsr_nzcvq, r0 @ encoding: [0x80,0xf3,0x01,0x88] +@ CHECK-V7M: msr iapsr_nzcvq, r0 @ encoding: [0x80,0xf3,0x01,0x88] +@ CHECK-V7M: msr eapsr_nzcvq, r0 @ encoding: [0x80,0xf3,0x02,0x88] +@ CHECK-V7M: msr eapsr_nzcvq, r0 @ encoding: [0x80,0xf3,0x02,0x88] +@ CHECK-V7M: msr xpsr_nzcvq, r0 @ encoding: [0x80,0xf3,0x03,0x88] +@ CHECK-V7M: msr xpsr_nzcvq, r0 @ encoding: [0x80,0xf3,0x03,0x88] @ CHECK: msr ipsr, r0 @ encoding: [0x80,0xf3,0x05,0x88] @ CHECK: msr epsr, r0 @ encoding: [0x80,0xf3,0x06,0x88] @ CHECK: msr iepsr, r0 @ encoding: [0x80,0xf3,0x07,0x88] Index: test/MC/ARM/thumbv7em.s =================================================================== --- /dev/null +++ test/MC/ARM/thumbv7em.s @@ -0,0 +1,53 @@ +@ RUN: llvm-mc -triple=thumbv7em -show-encoding < %s | FileCheck %s +@ RUN: not llvm-mc -triple=thumbv7m -show-encoding 2>&1 < %s | FileCheck --check-prefix=CHECK-V7M %s + + .syntax unified + +@ Check that the assembler can handle the documented syntax from the ARM ARM. +@ These tests test instruction encodings specific to ARMv7E-M. + +@------------------------------------------------------------------------------ +@ MSR +@------------------------------------------------------------------------------ + + msr apsr_g, r0 + msr apsr_nzcvqg, r0 + msr iapsr_g, r0 + msr iapsr_nzcvqg, r0 + msr eapsr_g, r0 + msr eapsr_nzcvqg, r0 + msr xpsr_g, r0 + msr xpsr_nzcvqg, r0 + +@ CHECK: msr apsr_g, r0 @ encoding: [0x80,0xf3,0x00,0x84] +@ CHECK: msr apsr_nzcvqg, r0 @ encoding: [0x80,0xf3,0x00,0x8c] +@ CHECK: msr iapsr_g, r0 @ encoding: [0x80,0xf3,0x01,0x84] +@ CHECK: msr iapsr_nzcvqg, r0 @ encoding: [0x80,0xf3,0x01,0x8c] +@ CHECK: msr eapsr_g, r0 @ encoding: [0x80,0xf3,0x02,0x84] +@ CHECK: msr eapsr_nzcvqg, r0 @ encoding: [0x80,0xf3,0x02,0x8c] +@ CHECK: msr xpsr_g, r0 @ encoding: [0x80,0xf3,0x03,0x84] +@ CHECK: msr xpsr_nzcvqg, r0 @ encoding: [0x80,0xf3,0x03,0x8c] +@ CHECK-V7M: error: invalid operand for instruction +@ CHECK-V7M-NEXT: msr apsr_g, r0 +@ CHECK-V7M-NEXT: ^ +@ CHECK-V7M: error: invalid operand for instruction +@ CHECK-V7M-NEXT: msr apsr_nzcvqg, r0 +@ CHECK-V7M-NEXT: ^ +@ CHECK-V7M: error: invalid operand for instruction +@ CHECK-V7M-NEXT: msr iapsr_g, r0 +@ CHECK-V7M-NEXT: ^ +@ CHECK-V7M: error: invalid operand for instruction +@ CHECK-V7M-NEXT: msr iapsr_nzcvqg, r0 +@ CHECK-V7M-NEXT: ^ +@ CHECK-V7M: error: invalid operand for instruction +@ CHECK-V7M-NEXT: msr eapsr_g, r0 +@ CHECK-V7M-NEXT: ^ +@ CHECK-V7M: error: invalid operand for instruction +@ CHECK-V7M-NEXT: msr eapsr_nzcvqg, r0 +@ CHECK-V7M-NEXT: ^ +@ CHECK-V7M: error: invalid operand for instruction +@ CHECK-V7M-NEXT: msr xpsr_g, r0 +@ CHECK-V7M-NEXT: ^ +@ CHECK-V7M: error: invalid operand for instruction +@ CHECK-V7M-NEXT: msr xpsr_nzcvqg, r0 +@ CHECK-V7M-NEXT: ^ Index: test/MC/Disassembler/ARM/invalid-thumb-MSR-MClass.txt =================================================================== --- test/MC/Disassembler/ARM/invalid-thumb-MSR-MClass.txt +++ test/MC/Disassembler/ARM/invalid-thumb-MSR-MClass.txt @@ -1,4 +1,5 @@ -# RUN: not llvm-mc -disassemble %s -triple=thumbv7-apple-darwin9 -mcpu cortex-m3 2>&1 | FileCheck %s +# RUN: not llvm-mc -disassemble %s -triple=thumbv7em 2>&1 | FileCheck --check-prefix=CHECK %s +# RUN: not llvm-mc -disassemble %s -triple=thumbv7m 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK-V7M %s #------------------------------------------------------------------------------ # Undefined encodings for mrs @@ -14,18 +15,18 @@ #------------------------------------------------------------------------------ # invalid mask = '00' -# CHECK: warning: invalid instruction encoding +# CHECK: warning: potentially undefined instruction encoding # CHECK-NEXT: [0x80 0xf3 0x00 0x80] [0x80 0xf3 0x00 0x80] # invalid mask = '11' with SYSm not in {0..3} -# CHECK: warning: invalid instruction encoding -# CHECK-NEXT: [0x80 0xf3 0x04 0x8c] -[0x80 0xf3 0x04 0x8c] +# CHECK: warning: potentially undefined instruction encoding +# CHECK-NEXT: [0x80 0xf3 0x05 0x8c] +[0x80 0xf3 0x05 0x8c] -# invalid mask = '01' (Cortex-M3 does not have the DSP extension) -# CHECK: warning: invalid instruction encoding -# CHECK-NEXT: [0x80 0xf3 0x00 0x84] +# invalid mask = '01' (ThumbV7M does not have the DSP extension) +# CHECK-V7M: warning: potentially undefined instruction encoding +# CHECK-V7M-NEXT: [0x80 0xf3 0x00 0x84] [0x80 0xf3 0x00 0x84] # invalid SYSm Index: test/MC/Disassembler/ARM/thumb-MSR-MClass.txt =================================================================== --- test/MC/Disassembler/ARM/thumb-MSR-MClass.txt +++ test/MC/Disassembler/ARM/thumb-MSR-MClass.txt @@ -1,4 +1,4 @@ -# RUN: llvm-mc --disassemble %s -triple=thumbv7-apple-darwin9 -mcpu cortex-m4 | FileCheck %s +# RUN: llvm-mc --disassemble %s -triple=thumbv7em | FileCheck %s #------------------------------------------------------------------------------ # MRS @@ -39,7 +39,7 @@ # MSR #------------------------------------------------------------------------------ -# CHECK: msr apsr, r0 +# CHECK: msr apsr_nzcvq, r0 # CHECK: msr apsr_g, r0 # CHECK: msr apsr_nzcvqg, r0 @@ -47,7 +47,7 @@ 0x80 0xf3 0x00 0x84 0x80 0xf3 0x00 0x8c -# CHECK: msr iapsr, r0 +# CHECK: msr iapsr_nzcvq, r0 # CHECK: msr iapsr_g, r0 # CHECK: msr iapsr_nzcvqg, r0 @@ -55,7 +55,7 @@ 0x80 0xf3 0x01 0x84 0x80 0xf3 0x01 0x8c -# CHECK: msr eapsr, r0 +# CHECK: msr eapsr_nzcvq, r0 # CHECK: msr eapsr_g, r0 # CHECK: msr eapsr_nzcvqg, r0 @@ -63,7 +63,7 @@ 0x80 0xf3 0x02 0x84 0x80 0xf3 0x02 0x8c -# CHECK: msr xpsr, r0 +# CHECK: msr xpsr_nzcvq, r0 # CHECK: msr xpsr_g, r0 # CHECK: msr xpsr_nzcvqg, r0