From 5ade5fcee498b561b944f81987e8fa82ab0832bd Mon Sep 17 00:00:00 2001 From: Vladimir Sukharev Date: Thu, 16 Apr 2015 11:34:25 +0000 Subject: [PATCH] [ARM] Add v8.1a "Privileged Access Never" extension Reviewers: jmolloy Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D8504 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235087 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstrInfo.td | 31 ++++++++++- lib/Target/ARM/ARMInstrThumb2.td | 17 ++++++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 2 +- .../ARM/Disassembler/ARMDisassembler.cpp | 52 +++++++++++++++++++ test/MC/ARM/basic-arm-instructions-v8.1a.s | 32 ++++++++++++ test/MC/Disassembler/ARM/armv8.1a.txt | 16 ++++++ test/MC/Disassembler/ARM/thumb-v8.1a.txt | 12 +++++ 7 files changed, 159 insertions(+), 3 deletions(-) diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 3f9fbf9ee8b..52f35554995 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -1420,7 +1420,8 @@ multiclass AsI1_rbin_s_is opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, - PatFrag opnode, bit Commutable = 0> { + PatFrag opnode, bit Commutable = 0, + string rrDecoderMethod = ""> { def ri : AI1, @@ -1448,6 +1449,7 @@ multiclass AI1_cmp_irs opcod, string opc, let Inst{15-12} = 0b0000; let Inst{11-4} = 0b00000000; let Inst{3-0} = Rm; + let DecoderMethod = rrDecoderMethod; let Unpredictable{15-12} = 0b1111; } @@ -4265,6 +4267,30 @@ def CRC32CH : AI_crc32<1, 0b01, "ch", int_arm_crc32ch>; def CRC32W : AI_crc32<0, 0b10, "w", int_arm_crc32w>; def CRC32CW : AI_crc32<1, 0b10, "cw", int_arm_crc32cw>; +//===----------------------------------------------------------------------===// +// ARMv8.1a Privilege Access Never extension +// +// SETPAN #imm1 + +def SETPAN : AInoP<(outs), (ins imm0_1:$imm), MiscFrm, NoItinerary, "setpan", + "\t$imm", []>, Requires<[IsARM, HasV8, HasV8_1a]> { + bits<1> imm; + + let Inst{31-28} = 0b1111; + let Inst{27-20} = 0b00010001; + let Inst{19-16} = 0b0000; + let Inst{15-10} = 0b000000; + let Inst{9} = imm; + let Inst{8} = 0b0; + let Inst{7-4} = 0b0000; + let Inst{3-0} = 0b0000; + + let Unpredictable{19-16} = 0b1111; + let Unpredictable{15-10} = 0b111111; + let Unpredictable{8} = 0b1; + let Unpredictable{3-0} = 0b1111; +} + //===----------------------------------------------------------------------===// // Comparison Instructions... // @@ -4369,7 +4395,8 @@ def : ARMPat<(ARMcmpZ GPR:$src, mod_imm_neg:$imm), // Note that TST/TEQ don't set all the same flags that CMP does! defm TST : AI1_cmp_irs<0b1000, "tst", IIC_iTSTi, IIC_iTSTr, IIC_iTSTsr, - BinOpFrag<(ARMcmpZ (and_su node:$LHS, node:$RHS), 0)>, 1>; + BinOpFrag<(ARMcmpZ (and_su node:$LHS, node:$RHS), 0)>, 1, + "DecodeTSTInstruction">; defm TEQ : AI1_cmp_irs<0b1001, "teq", IIC_iTSTi, IIC_iTSTr, IIC_iTSTsr, BinOpFrag<(ARMcmpZ (xor_su node:$LHS, node:$RHS), 0)>, 1>; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 4515a8129f7..103ee002cac 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -4280,6 +4280,23 @@ def t2CDP2 : T2Cop<0b1111, (outs), (ins p_imm:$cop, imm0_15:$opc1, +//===----------------------------------------------------------------------===// +// ARMv8.1 Privilege Access Never extension +// +// SETPAN #imm1 + +def t2SETPAN : T1I<(outs), (ins imm0_1:$imm), NoItinerary, "setpan\t$imm", []>, + T1Misc<0b0110000>, Requires<[IsThumb2, HasV8, HasV8_1a]> { + bits<1> imm; + + let Inst{4} = 0b1; + let Inst{3} = imm; + let Inst{2-0} = 0b000; + + let Unpredictable{4} = 0b1; + let Unpredictable{2-0} = 0b111; +} + //===----------------------------------------------------------------------===// // Non-Instruction Patterns // diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 4b9fcbe38fc..b9ad2c8bcd2 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -5441,7 +5441,7 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst, Mnemonic == "vminnm" || Mnemonic == "vcvta" || Mnemonic == "vcvtn" || Mnemonic == "vcvtp" || Mnemonic == "vcvtm" || Mnemonic == "vrinta" || Mnemonic == "vrintn" || Mnemonic == "vrintp" || Mnemonic == "vrintm" || - Mnemonic.startswith("aes") || Mnemonic == "hvc" || + Mnemonic.startswith("aes") || Mnemonic == "hvc" || Mnemonic == "setpan" || Mnemonic.startswith("sha1") || Mnemonic.startswith("sha256") || (FullInst.startswith("vmull") && FullInst.endswith(".p64"))) { // These mnemonics are never predicable diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 4a53e96906d..4c169a8ef55 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -212,6 +212,10 @@ static DecodeStatus DecodeSMLAInstruction(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeCPSInstruction(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeTSTInstruction(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); +static DecodeStatus DecodeSETPANInstruction(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeT2CPSInstruction(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeAddrModeImm12Operand(MCInst &Inst, unsigned Val, @@ -2119,6 +2123,54 @@ static DecodeStatus DecodeSMLAInstruction(MCInst &Inst, unsigned Insn, return S; } +static DecodeStatus DecodeTSTInstruction(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + unsigned Pred = fieldFromInstruction(Insn, 28, 4); + unsigned Rn = fieldFromInstruction(Insn, 16, 4); + unsigned Rm = fieldFromInstruction(Insn, 0, 4); + + if (Pred == 0xF) + return DecodeSETPANInstruction(Inst, Insn, Address, Decoder); + + if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder))) + return MCDisassembler::Fail; + if (!Check(S, DecodeGPRRegisterClass(Inst, Rm, Address, Decoder))) + return MCDisassembler::Fail; + if (!Check(S, DecodePredicateOperand(Inst, Pred, Address, Decoder))) + return MCDisassembler::Fail; + + return S; +} + +static DecodeStatus DecodeSETPANInstruction(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + unsigned Imm = fieldFromInstruction(Insn, 9, 1); + + const MCDisassembler *Dis = static_cast(Decoder); + uint64_t FeatureBits = Dis->getSubtargetInfo().getFeatureBits(); + if ((FeatureBits & ARM::HasV8_1aOps) == 0 || + (FeatureBits & ARM::HasV8Ops) == 0 ) + return MCDisassembler::Fail; + + // Decoder can be called from DecodeTST, which does not check the full + // encoding is valid. + if (fieldFromInstruction(Insn, 20,12) != 0xf11 || + fieldFromInstruction(Insn, 4,4) != 0) + return MCDisassembler::Fail; + if (fieldFromInstruction(Insn, 10,10) != 0 || + fieldFromInstruction(Insn, 0,4) != 0) + S = MCDisassembler::SoftFail; + + Inst.setOpcode(ARM::SETPAN); + Inst.addOperand(MCOperand::CreateImm(Imm)); + + return S; +} + static DecodeStatus DecodeAddrModeImm12Operand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder) { DecodeStatus S = MCDisassembler::Success; diff --git a/test/MC/ARM/basic-arm-instructions-v8.1a.s b/test/MC/ARM/basic-arm-instructions-v8.1a.s index 3101d19284e..005f27bb398 100644 --- a/test/MC/ARM/basic-arm-instructions-v8.1a.s +++ b/test/MC/ARM/basic-arm-instructions-v8.1a.s @@ -172,3 +172,35 @@ //CHECK-V8: error: instruction requires: armv8.1a //CHECK-V8: vqrdmlsh.s32 q0, q1, d2[0] //CHECK-V8: ^ + + setpan #0 +//CHECK-V81aTHUMB: setpan #0 @ encoding: [0x10,0xb6] +//CHECK-V81aARM: setpan #0 @ encoding: [0x00,0x00,0x10,0xf1] +//CHECK-V8: error: instruction requires: armv8.1a +//CHECK-V8: setpan #0 +//CHECK-V8: ^ + + setpan #1 +//CHECK-V81aTHUMB: setpan #1 @ encoding: [0x18,0xb6] +//CHECK-V81aARM: setpan #1 @ encoding: [0x00,0x02,0x10,0xf1] +//CHECK-V8: error: instruction requires: armv8.1a +//CHECK-V8: setpan #1 +//CHECK-V8: ^ + setpan + setpan #-1 + setpan #2 +//CHECK-ERROR: error: too few operands for instruction +//CHECK-ERROR: setpan +//CHECK-ERROR: ^ +//CHECK-ERROR: error: invalid operand for instruction +//CHECK-ERROR: setpan #-1 +//CHECK-ERROR: ^ +//CHECK-ERROR: error: invalid operand for instruction +//CHECK-ERROR: setpan #2 +//CHECK-ERROR: ^ + + it eq + setpaneq #0 +//CHECK-THUMB-ERROR: error: instruction 'setpan' is not predicable, but condition code specified +//CHECK-THUMB-ERROR: setpaneq #0 +//CHECK-THUMB-ERROR: ^ diff --git a/test/MC/Disassembler/ARM/armv8.1a.txt b/test/MC/Disassembler/ARM/armv8.1a.txt index de0c89ee790..929643bd561 100644 --- a/test/MC/Disassembler/ARM/armv8.1a.txt +++ b/test/MC/Disassembler/ARM/armv8.1a.txt @@ -34,3 +34,19 @@ # CHECK-V8: [0x42,0x0f,0x92,0xf3] # CHECK-V8: warning: invalid instruction encoding # CHECK-V8: [0x42,0x0f,0xa1,0xf2] + +# The SETPAN(v8.1a) and TST(v8) instructions occupy the same space, but SETPAN +# uses the encoding for the invalid NV predicate operand. This test checks that +# the disassembler is correctly disambiguating and decoding these instructions. + +[0x00 0x00 0x10 0xf1] +# CHECK: setpan #0 + +[0x00 0x02 0x10 0xf1] +# CHECK: setpan #1 + +[0x00 0x00 0x10 0xe1] +# CHECK: tst r0, r0 + +[0x00 0x02 0x10 0xe1] +# CHECK: tst r0, r0, lsl #4 diff --git a/test/MC/Disassembler/ARM/thumb-v8.1a.txt b/test/MC/Disassembler/ARM/thumb-v8.1a.txt index 10fea46694e..3de8c272ffa 100644 --- a/test/MC/Disassembler/ARM/thumb-v8.1a.txt +++ b/test/MC/Disassembler/ARM/thumb-v8.1a.txt @@ -96,3 +96,15 @@ # CHECK-V8: warning: invalid instruction encoding # CHECK-V8: [0xa2,0xff,0x42,0x0f] # CHECK-V8: ^ + +[0x10,0xb6] +# CHECK-V81a: setpan #0 +# CHECK-V8: warning: invalid instruction encoding +# CHECK-V8: [0x10,0xb6] +# CHECK-V8: ^ + +[0x18,0xb6] +# CHECK-V81a: setpan #1 +# CHECK-V8: warning: invalid instruction encoding +# CHECK-V8: [0x18,0xb6] +# CHECK-V8: ^