Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -82,6 +82,7 @@ bool parseDirectiveUnreq(SMLoc L); bool validateInstruction(MCInst &Inst, SmallVectorImpl &Loc); + void canonizeSystemInstruction(MCInst &Inst); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, @@ -3450,6 +3451,116 @@ } } +void AArch64AsmParser::canonizeSystemInstruction(MCInst &Inst) { + // Assembler accepts extended MSR/MRS format with the having + // in <0,3>. However, such MCInst instructions can alias to other + // system instructions and so two different MCInsts could encode to a same + // bitpattern. This function fixes the problem by rewriting the problematic + // instructions to their canonical MCInst. + + uint64_t Bits; + if (Inst.getOpcode() == AArch64::MSR) + Bits = Inst.getOperand(0).getImm(); + else if (Inst.getOpcode() == AArch64::MRS) + Bits = Inst.getOperand(1).getImm(); + else + return; + + // Bits encodes . + uint64_t Op0 = (Bits >> 14) & 0x3; + uint64_t Op1 = (Bits >> 11) & 0x7; + uint64_t CRn = (Bits >> 7) & 0xF; + uint64_t CRm = (Bits >> 3) & 0xF; + uint64_t Op2 = (Bits >> 0) & 0x7; + + switch (Inst.getOpcode()) { + case AArch64::MSR: { + // MSR can be rewritten to HINT, CLREX, DMB, DSB, ISB, MSRpstate, or + // SYSxt. + + if (Op0 == 0x0 && Inst.getOperand(1).getReg() == AArch64::XZR) { + // If is 0b00 and is 0b11111 then it can be HINT, CLREX, DMB, + // DSB, ISB, or MSRpstate. + + if (CRn == 0x4) { + // If is 0b0100 and represent a valid + // then it is MSRpstate. + + uint64_t PStateField = (Op1 << 3) | Op2; + bool ValidNamed; + (void)AArch64PState::PStateMapper().toString(PStateField, ValidNamed); + + if (ValidNamed) { + Inst.setOpcode(AArch64::MSRpstate); + Inst.clear(); + Inst.addOperand(MCOperand::CreateImm(PStateField)); + Inst.addOperand(MCOperand::CreateImm(CRm)); + } + } else if (Op1 == 0x3) { + // If is 0b011 then it can be HINT, CLREX, DMB, DSB, or ISB. + + if (CRn == 0x2) { + // If is 0b0010 then it is HINT. + Inst.setOpcode(AArch64::HINT); + Inst.clear(); + Inst.addOperand(MCOperand::CreateImm((CRm << 4 ) | Op2)); + } else if (Op1 == 0x3 && CRn == 0x3) { + // If is 0b011 and is 0b0011 then it can be CLREX, DMB, + // DSB, or ISB. + if (Op2 == 0x2) { + // If is 0b010 then it is CLREX. + Inst.setOpcode(AArch64::CLREX); + Inst.clear(); + Inst.addOperand(MCOperand::CreateImm(CRm)); + } else if (Op2 == 0x4) { + // If is 0b100 then it is DMB. + Inst.setOpcode(AArch64::DMB); + Inst.clear(); + Inst.addOperand(MCOperand::CreateImm(CRm)); + } else if (Op2 == 0x5) { + // If is 0b101 then it is DSB. + Inst.setOpcode(AArch64::DSB); + Inst.clear(); + Inst.addOperand(MCOperand::CreateImm(CRm)); + } else if (Op2 == 0x6) { + // If is 0b110 then it is ISB. + Inst.setOpcode(AArch64::ISB); + Inst.clear(); + Inst.addOperand(MCOperand::CreateImm(CRm)); + } + } + } + } else if (Op0 == 0x1) { + // If is 0b01 then it is SYSxt. + Inst.setOpcode(AArch64::SYSxt); + unsigned Reg = Inst.getOperand(1).getReg(); + Inst.clear(); + Inst.addOperand(MCOperand::CreateImm(Op1)); + Inst.addOperand(MCOperand::CreateImm(CRn)); + Inst.addOperand(MCOperand::CreateImm(CRm)); + Inst.addOperand(MCOperand::CreateImm(Op2)); + Inst.addOperand(MCOperand::CreateReg(Reg)); + } + break; + } + case AArch64::MRS: + // MRS can be rewritten to SYSLXt. + + if (Op0 == 0x1) { + // If is 0b01 then it is SYSLxt. + Inst.setOpcode(AArch64::SYSLxt); + unsigned Reg = Inst.getOperand(0).getReg(); + Inst.clear(); + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateImm(Op1)); + Inst.addOperand(MCOperand::CreateImm(CRn)); + Inst.addOperand(MCOperand::CreateImm(CRm)); + Inst.addOperand(MCOperand::CreateImm(Op2)); + } + break; + } +} + bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode) { switch (ErrCode) { case Match_MissingFeature: @@ -3822,6 +3933,9 @@ if (validateInstruction(Inst, OperandLocs)) return true; + // Rewrite any MSR/MRS to their canonical form. + canonizeSystemInstruction(Inst); + Inst.setLoc(IDLoc); Out.EmitInstruction(Inst, STI); return false; Index: lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp =================================================================== --- lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -1496,17 +1496,35 @@ const void *Decoder) { uint64_t op1 = fieldFromInstruction(insn, 16, 3); uint64_t op2 = fieldFromInstruction(insn, 5, 3); - uint64_t crm = fieldFromInstruction(insn, 8, 4); uint64_t pstate_field = (op1 << 3) | op2; - Inst.addOperand(MCOperand::CreateImm(pstate_field)); - Inst.addOperand(MCOperand::CreateImm(crm)); - bool ValidNamed; (void)AArch64PState::PStateMapper().toString(pstate_field, ValidNamed); - return ValidNamed ? Success : Fail; + // If the name is not valid then the instruction must be threated as the + // extended MSR. + // FIXME This should be specified in TableGen but it is not currently + // possible due to TableGen limitations. + if (!ValidNamed) { + uint64_t systemreg = fieldFromInstruction(insn, 5, 16); + uint64_t Rt = fieldFromInstruction(insn, 0, 5); + unsigned Register = GPR64DecoderTable[Rt]; + + Inst.setOpcode(AArch64::MSR); + Inst.addOperand(MCOperand::CreateImm(systemreg)); + Inst.addOperand(MCOperand::CreateReg(Register)); + + return Success; + } + + // Valid MSR , #. + uint64_t crm = fieldFromInstruction(insn, 8, 4); + + Inst.addOperand(MCOperand::CreateImm(pstate_field)); + Inst.addOperand(MCOperand::CreateImm(crm)); + + return Success; } static DecodeStatus DecodeTestAndBranch(llvm::MCInst &Inst, uint32_t insn, Index: test/MC/AArch64/arm64-system-encoding.s =================================================================== --- test/MC/AArch64/arm64-system-encoding.s +++ test/MC/AArch64/arm64-system-encoding.s @@ -136,7 +136,6 @@ msr SPSel, x3 msr S3_2_C11_C6_4, x1 msr S0_0_C0_C0_0, x0 - msr S1_2_C3_C4_5, x2 ; CHECK: msr ACTLR_EL1, x3 ; encoding: [0x23,0x10,0x18,0xd5] ; CHECK: msr ACTLR_EL2, x3 ; encoding: [0x23,0x10,0x1c,0xd5] ; CHECK: msr ACTLR_EL3, x3 ; encoding: [0x23,0x10,0x1e,0xd5] @@ -216,7 +215,6 @@ ; CHECK: msr SPSEL, x3 ; encoding: [0x03,0x42,0x18,0xd5] ; CHECK: msr S3_2_C11_C6_4, x1 ; encoding: [0x81,0xb6,0x1a,0xd5] ; CHECK: msr S0_0_C0_C0_0, x0 ; encoding: [0x00,0x00,0x00,0xd5] -; CHECK: msr S1_2_C3_C4_5, x2 ; encoding: [0xa2,0x34,0x0a,0xd5] mrs x3, ACTLR_EL1 mrs x3, ACTLR_EL2 @@ -625,3 +623,43 @@ ; CHECK: mrs x0, AFSR1_EL1 ; encoding: [0x20,0x51,0x38,0xd5] ; CHECK: mrs x0, AFSR0_EL1 ; encoding: [0x00,0x51,0x38,0xd5] ; CHECK: mrs x0, REVIDR_EL1 ; encoding: [0xc0,0x00,0x38,0xd5] + +;----------------------------------------------------------------------------- +; Generic MSR/MRS instructions that alias more specific system instructions +;----------------------------------------------------------------------------- + +msr S0_3_C2_C0_0, xzr +msr S0_3_C2_C0_1, xzr +msr S0_3_C2_C0_2, xzr +msr S0_3_C2_C0_3, xzr +msr S0_3_C2_C0_4, xzr +msr S0_3_C2_C0_5, xzr +msr S0_3_C2_C1_0, xzr +msr S0_3_C3_C0_2, xzr +msr S0_3_C3_C0_4, xzr +msr S0_3_C3_C0_5, xzr +msr S0_3_C3_C0_6, xzr +msr S0_0_C4_C1_5, xzr +msr S0_3_C4_C2_6, xzr +msr S0_3_C4_C3_7, xzr +msr S1_2_C3_C4_5, x0 +msr S1_2_C3_C4_5, xzr +mrs x0, S1_2_C3_C4_5 + +; CHECK: nop ; encoding: [0x1f,0x20,0x03,0xd5] +; CHECK: yield ; encoding: [0x3f,0x20,0x03,0xd5] +; CHECK: wfe ; encoding: [0x5f,0x20,0x03,0xd5] +; CHECK: wfi ; encoding: [0x7f,0x20,0x03,0xd5] +; CHECK: sev ; encoding: [0x9f,0x20,0x03,0xd5] +; CHECK: sevl ; encoding: [0xbf,0x20,0x03,0xd5] +; CHECK: hint #0x10 ; encoding: [0x1f,0x22,0x03,0xd5] +; CHECK: clrex #0 ; encoding: [0x5f,0x30,0x03,0xd5] +; CHECK: dmb #0 ; encoding: [0xbf,0x30,0x03,0xd5] +; CHECK: dsb #0 ; encoding: [0x9f,0x30,0x03,0xd5] +; CHECK: isb #0 ; encoding: [0xdf,0x30,0x03,0xd5] +; CHECK: msr SPSEL, #1 ; encoding: [0xbf,0x41,0x00,0xd5] +; CHECK: msr DAIFSET, #2 ; encoding: [0xdf,0x42,0x03,0xd5] +; CHECK: msr DAIFCLR, #3 ; encoding: [0xff,0x43,0x03,0xd5] +; CHECK: sys #2, c3, c4, #5, x0 ; encoding: [0xa0,0x34,0x0a,0xd5] +; CHECK: sys #2, c3, c4, #5 ; encoding: [0xbf,0x34,0x0a,0xd5] +; CHECK: sysl x0, #2, c3, c4, #5 ; encoding: [0xa0,0x34,0x2a,0xd5] Index: test/MC/AArch64/basic-a64-instructions.s =================================================================== --- test/MC/AArch64/basic-a64-instructions.s +++ test/MC/AArch64/basic-a64-instructions.s @@ -4798,16 +4798,12 @@ mrs x12, s3_7_c15_c1_5 mrs x13, s3_2_c11_c15_7 - mrs x14, s1_3_c9_c2_1 msr s3_0_c15_c0_0, x12 msr s3_7_c11_c13_7, x5 - msr s1_3_c9_c2_1, x4 // CHECK: mrs x12, {{s3_7_c15_c1_5|S3_7_C15_C1_5}} // encoding: [0xac,0xf1,0x3f,0xd5] // CHECK: mrs x13, {{s3_2_c11_c15_7|S3_2_C11_C15_7}} // encoding: [0xed,0xbf,0x3a,0xd5] -// CHECK: mrs x14, {{s1_3_c9_c2_1|S1_3_C9_C2_1}} // encoding: [0x2e,0x92,0x2b,0xd5] // CHECK: msr {{s3_0_c15_c0_0|S3_0_C15_C0_0}}, x12 // encoding: [0x0c,0xf0,0x18,0xd5] // CHECK: msr {{s3_7_c11_c13_7|S3_7_C11_C13_7}}, x5 // encoding: [0xe5,0xbd,0x1f,0xd5] -// CHECK: msr {{s1_3_c9_c2_1|S1_3_C9_C2_1}}, x4 // encoding: [0x24,0x92,0x0b,0xd5] //------------------------------------------------------------------------------ // Unconditional branch (immediate) Index: test/MC/Disassembler/AArch64/basic-a64-instructions.txt =================================================================== --- test/MC/Disassembler/AArch64/basic-a64-instructions.txt +++ test/MC/Disassembler/AArch64/basic-a64-instructions.txt @@ -4170,12 +4170,16 @@ # CHECK: mrs x12, {{s3_7_c15_c1_5|S3_7_C15_C1_5}} # CHECK: mrs x13, {{s3_2_c11_c15_7|S3_2_C11_C15_7}} +# CHECK: mrs xzr, {{s0_0_c4_c0_0|S0_0_C4_C0_0}} # CHECK: msr {{s3_0_c15_c0_0|S3_0_C15_C0_0}}, x12 # CHECK: msr {{s3_7_c11_c13_7|S3_7_C11_C13_7}}, x5 +# CHECK: msr {{s0_0_c4_c0_0|S0_0_C4_C0_0}}, xzr 0xac 0xf1 0x3f 0xd5 0xed 0xbf 0x3a 0xd5 +0x1f 0x40 0x20 0xd5 0x0c 0xf0 0x18 0xd5 0xe5 0xbd 0x1f 0xd5 +0x1f 0x40 0x00 0xd5 #------------------------------------------------------------------------------ # Test and branch (immediate)