Index: lib/Target/AArch64/AArch64ISelDAGToDAG.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -2265,7 +2265,9 @@ assert (isa(N->getOperand(2)) && "Expected a constant integer expression."); uint64_t Immed = cast(N->getOperand(2))->getZExtValue(); - return CurDAG->getMachineNode(AArch64::MSRpstate, DL, MVT::Other, + return CurDAG->getMachineNode(Immed < 2 ? AArch64::MSRpstateImm1 : + AArch64::MSRpstateImm4, + DL, MVT::Other, CurDAG->getTargetConstant(Reg, DL, MVT::i32), CurDAG->getTargetConstant(Immed, DL, MVT::i16), N->getOperand(0)); Index: lib/Target/AArch64/AArch64InstrFormats.td =================================================================== --- lib/Target/AArch64/AArch64InstrFormats.td +++ lib/Target/AArch64/AArch64InstrFormats.td @@ -408,6 +408,7 @@ let ParserMatchClass = Imm1_32Operand; } +def Imm0_1Operand : AsmImmRange<0, 1>; def Imm0_7Operand : AsmImmRange<0, 7>; def Imm0_15Operand : AsmImmRange<0, 15>; def Imm0_31Operand : AsmImmRange<0, 31>; @@ -538,6 +539,13 @@ let ParserMatchClass = Imm0_31Operand; } +// imm0_1 predicate - True if the immediate is in the range [0,1] +def imm0_1 : Operand, ImmLeaf { + let ParserMatchClass = Imm0_1Operand; +} + // imm0_15 predicate - True if the immediate is in the range [0,15] def imm0_15 : Operand, ImmLeaf { - let ParserMatchClass = SystemPStateFieldOperand; +def pstatefield4_op : Operand { + let ParserMatchClass = SystemPStateFieldWithImm0_15Operand; let PrintMethod = "printSystemPStateField"; } let Defs = [NZCV] in -class MSRpstateI - : SimpleSystemI<0, (ins pstatefield_op:$pstate_field, imm0_15:$imm), - "msr", "\t$pstate_field, $imm">, +class MSRpstateImm0_15 + : SimpleSystemI<0, (ins pstatefield4_op:$pstatefield, imm0_15:$imm), + "msr", "\t$pstatefield, $imm">, Sched<[WriteSys]> { bits<6> pstatefield; bits<4> imm; @@ -933,6 +941,34 @@ let hasCompleteDecoder = 0; } +def SystemPStateFieldWithImm0_1Operand : AsmOperandClass { + let Name = "SystemPStateFieldWithImm0_1"; + let ParserMethod = "tryParseSysReg"; +} +def pstatefield1_op : Operand { + let ParserMatchClass = SystemPStateFieldWithImm0_1Operand; + let PrintMethod = "printSystemPStateField"; +} + +let Defs = [NZCV] in +class MSRpstateImm0_1 + : SimpleSystemI<0, (ins pstatefield1_op:$pstatefield, imm0_1:$imm), + "msr", "\t$pstatefield, $imm">, + Sched<[WriteSys]> { + bits<6> pstatefield; + bit imm; + let Inst{20-19} = 0b00; + let Inst{18-16} = pstatefield{5-3}; + let Inst{15-9} = 0b0100000; + let Inst{8} = imm; + let Inst{7-5} = pstatefield{2-0}; + + let DecoderMethod = "DecodeSystemPStateInstruction"; + // MSRpstateI aliases with MSRI. When the MSRpstateI decoder method returns + // Fail the decoder should attempt to decode the instruction as MSRI. + let hasCompleteDecoder = 0; +} + // SYS and SYSL generic system instructions. def SysCRAsmOperand : AsmOperandClass { let Name = "SysCR"; Index: lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.td +++ lib/Target/AArch64/AArch64InstrInfo.td @@ -399,7 +399,8 @@ def MRS : MRSI; def MSR : MSRI; -def MSRpstate: MSRpstateI; +def MSRpstateImm1 : MSRpstateImm0_1; +def MSRpstateImm4 : MSRpstateImm0_15; // The thread pointer (on Linux, at least, where this has been implemented) is // TPIDR_EL0. Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -497,6 +497,15 @@ return (Val % Scale) == 0 && Val >= 0 && (Val / Scale) < 0x1000; } + bool isImm0_1() const { + if (!isImm()) + return false; + const MCConstantExpr *MCE = dyn_cast(getImm()); + if (!MCE) + return false; + int64_t Val = MCE->getValue(); + return (Val >= 0 && Val < 2); + } bool isImm0_7() const { if (!isImm()) return false; @@ -876,12 +885,14 @@ } bool isMSRSystemRegister() const { if (!isSysReg()) return false; - return SysReg.MSRReg != -1U; } - bool isSystemPStateField() const { + bool isSystemPStateFieldWithImm0_1() const { if (!isSysReg()) return false; - + return SysReg.PStateField == AArch64PState::PAN; + } + bool isSystemPStateFieldWithImm0_15() const { + if (!isSysReg() || isSystemPStateFieldWithImm0_1()) return false; return SysReg.PStateField != -1U; } bool isReg() const override { return Kind == k_Register && !Reg.isVector; } @@ -1304,6 +1315,12 @@ Inst.addOperand(MCOperand::createImm(MCE->getValue() / 16)); } + void addImm0_1Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *MCE = cast(getImm()); + Inst.addOperand(MCOperand::createImm(MCE->getValue())); + } + void addImm0_7Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *MCE = cast(getImm()); @@ -1491,7 +1508,13 @@ Inst.addOperand(MCOperand::createImm(SysReg.MSRReg)); } - void addSystemPStateFieldOperands(MCInst &Inst, unsigned N) const { + void addSystemPStateFieldWithImm0_1Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::createImm(SysReg.PStateField)); + } + + void addSystemPStateFieldWithImm0_15Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(SysReg.PStateField)); @@ -3601,6 +3624,8 @@ return Error(Loc, "index must be a multiple of 8 in range [0, 32760]."); case Match_InvalidMemoryIndexed16: return Error(Loc, "index must be a multiple of 16 in range [0, 65520]."); + case Match_InvalidImm0_1: + return Error(Loc, "immediate must be an integer in range [0, 1]."); case Match_InvalidImm0_7: return Error(Loc, "immediate must be an integer in range [0, 7]."); case Match_InvalidImm0_15: @@ -4029,6 +4054,7 @@ case Match_InvalidMemoryIndexed8SImm7: case Match_InvalidMemoryIndexed16SImm7: case Match_InvalidMemoryIndexedSImm9: + case Match_InvalidImm0_1: case Match_InvalidImm0_7: case Match_InvalidImm0_15: case Match_InvalidImm0_31: Index: lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp =================================================================== --- lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -1516,6 +1516,9 @@ uint64_t pstate_field = (op1 << 3) | op2; + if (pstate_field == AArch64PState::PAN && crm > 1) + return Fail; + Inst.addOperand(MCOperand::createImm(pstate_field)); Inst.addOperand(MCOperand::createImm(crm)); Index: test/MC/AArch64/armv8.1a-pan.s =================================================================== --- test/MC/AArch64/armv8.1a-pan.s +++ test/MC/AArch64/armv8.1a-pan.s @@ -13,16 +13,16 @@ // CHECK: mrs x13, PAN // encoding: [0x6d,0x42,0x38,0xd5] msr pan, #-1 - msr pan, #20 + msr pan, #2 msr pan, w0 mrs w0, pan -// CHECK-ERROR: error: immediate must be an integer in range [0, 15]. +// CHECK-ERROR: error: immediate must be an integer in range [0, 1]. // CHECK-ERROR: msr pan, #-1 // CHECK-ERROR: ^ -// CHECK-ERROR: error: immediate must be an integer in range [0, 15]. -// CHECK-ERROR: msr pan, #20 +// CHECK-ERROR: error: immediate must be an integer in range [0, 1]. +// CHECK-ERROR: msr pan, #2 // CHECK-ERROR: ^ -// CHECK-ERROR: error: immediate must be an integer in range [0, 15]. +// CHECK-ERROR: error: immediate must be an integer in range [0, 1]. // CHECK-ERROR: msr pan, w0 // CHECK-ERROR: ^ // CHECK-ERROR: error: invalid operand for instruction Index: test/MC/Disassembler/AArch64/armv8.1a-pan.txt =================================================================== --- test/MC/Disassembler/AArch64/armv8.1a-pan.txt +++ test/MC/Disassembler/AArch64/armv8.1a-pan.txt @@ -2,9 +2,11 @@ 0x9f,0x40,0x00,0xd5 0x9f,0x41,0x00,0xd5 +0x9f,0x42,0x00,0xd5 0x65,0x42,0x18,0xd5 0x6d,0x42,0x38,0xd5 # CHECK: msr PAN, #0 # CHECK: msr PAN, #1 +# CHECK-NOT: msr PAN, #2 # CHECK: msr PAN, x5 # CHECK: mrs x13, PAN