From 82e78e2e9da77fb00f10ac3d1121e27a80f478a4 Mon Sep 17 00:00:00 2001 From: Alexandros Lamprineas Date: Mon, 5 Oct 2015 13:42:31 +0000 Subject: [PATCH] [MC layer][AArch64] llvm-mc accepts 4-bit immediate values for "msr pan, #imm", while only 1-bit immediate values should be valid. Changed encoding and decoding for msr pstate instructions. Differential Revision: http://reviews.llvm.org/D13011 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249313 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 10 +++- lib/Target/AArch64/AArch64InstrFormats.td | 50 ++++++++++++++++--- lib/Target/AArch64/AArch64InstrInfo.td | 3 +- .../AArch64/AsmParser/AArch64AsmParser.cpp | 34 +++++++++++-- .../Disassembler/AArch64Disassembler.cpp | 3 ++ test/MC/AArch64/armv8.1a-pan.s | 10 ++-- test/MC/Disassembler/AArch64/armv8.1a-pan.txt | 2 + 7 files changed, 94 insertions(+), 18 deletions(-) diff --git a/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index 46c80e8b46a..e5293f011ba 100644 --- a/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -2265,7 +2265,15 @@ SDNode *AArch64DAGToDAGISel::SelectWriteRegister(SDNode *N) { 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, + unsigned State; + if (Reg == AArch64PState::PAN) { + assert(Immed < 2 && "Bad imm"); + State = AArch64::MSRpstateImm1; + } else { + assert(Immed < 16 && "Bad imm"); + State = AArch64::MSRpstateImm4; + } + return CurDAG->getMachineNode(State, DL, MVT::Other, CurDAG->getTargetConstant(Reg, DL, MVT::i32), CurDAG->getTargetConstant(Immed, DL, MVT::i16), N->getOperand(0)); diff --git a/lib/Target/AArch64/AArch64InstrFormats.td b/lib/Target/AArch64/AArch64InstrFormats.td index 39310cb5084..977c7d3f0bb 100644 --- a/lib/Target/AArch64/AArch64InstrFormats.td +++ b/lib/Target/AArch64/AArch64InstrFormats.td @@ -408,6 +408,7 @@ def vecshiftR64Narrow : Operand, ImmLeaf; def Imm0_7Operand : AsmImmRange<0, 7>; def Imm0_15Operand : AsmImmRange<0, 15>; def Imm0_31Operand : AsmImmRange<0, 31>; @@ -538,6 +539,13 @@ def imm32_0_31 : Operand, ImmLeaf, 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 @@ class MSRpstateI 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"; diff --git a/lib/Target/AArch64/AArch64InstrInfo.td b/lib/Target/AArch64/AArch64InstrInfo.td index 4533afdf41d..994a3e73a2c 100644 --- a/lib/Target/AArch64/AArch64InstrInfo.td +++ b/lib/Target/AArch64/AArch64InstrInfo.td @@ -399,7 +399,8 @@ def : InstAlias<"isb", (ISB 0xf)>; 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. diff --git a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 20db170fb3e..e3af43d1948 100644 --- a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -497,6 +497,15 @@ public: 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 @@ public: } 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 @@ public: 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 @@ public: 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 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode) { 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 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, 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: diff --git a/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp index db9fb0e775d..00e0eef266a 100644 --- a/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ b/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -1516,6 +1516,9 @@ static DecodeStatus DecodeSystemPStateInstruction(llvm::MCInst &Inst, 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)); diff --git a/test/MC/AArch64/armv8.1a-pan.s b/test/MC/AArch64/armv8.1a-pan.s index 2068c81d939..c283cb818e2 100644 --- a/test/MC/AArch64/armv8.1a-pan.s +++ b/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 diff --git a/test/MC/Disassembler/AArch64/armv8.1a-pan.txt b/test/MC/Disassembler/AArch64/armv8.1a-pan.txt index 2af5c2aa21e..22dc5fd5894 100644 --- a/test/MC/Disassembler/AArch64/armv8.1a-pan.txt +++ b/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 -- 2.34.1