From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 36339 invoked by alias); 1 May 2019 17:38:22 -0000 Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org Received: (qmail 36331 invoked by uid 89); 1 May 2019 17:38:22 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.7 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.1 spammy=distinguished, regno, sk:michael, decoding X-HELO: foss.arm.com Received: from usa-sjc-mx-foss1.foss.arm.com (HELO foss.arm.com) (217.140.101.70) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 01 May 2019 17:38:19 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 46FF980D; Wed, 1 May 2019 10:38:18 -0700 (PDT) Received: from [10.2.207.62] (e107157-lin.cambridge.arm.com [10.2.207.62]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 753713F719; Wed, 1 May 2019 10:38:17 -0700 (PDT) Subject: [PATCH 37/57][Arm][OBJDUMP] Add framework for MVE instructions To: binutils@sourceware.org References: <19569550-4d2e-0bb3-592a-d91050d490f6@arm.com> Cc: Nick Clifton , Richard Earnshaw From: "Andre Vieira (lists)" Message-ID: <195c38ed-37e2-3e5e-16db-8e8782e22b5c@arm.com> Date: Wed, 01 May 2019 17:38:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 In-Reply-To: <19569550-4d2e-0bb3-592a-d91050d490f6@arm.com> Content-Type: multipart/mixed; boundary="------------B7BD5736D5942434EE0D71EB" X-IsSubscribed: yes X-SW-Source: 2019-05/txt/msg00067.txt.bz2 This is a multi-part message in MIME format. --------------B7BD5736D5942434EE0D71EB Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-length: 2112 Hi, This patch adds a framework to OBJDUMP to support MVE instructions. Since MVE and NEON share some encoding space, but may need a slightly different decoding, we decided to split up instruction decoding based on whether '-marmv8.1-m.main' has been passed to OBJDUMP. The new function 'is_mve_architecture' will check this and direct 'print_insn_thumb32' to either use 'print_insn_neon' or 'print_insn_mve'. This framework also includes helper functions to determine encoding conflicts, undefined encodings and unpredictable encodings. These are further implemented for each relevant instruction in subsequent patches. By encoding conflicts we refer to encodings where two different instructions have overlapping base opcodes, but can be distinguished based on specific operand values. In the ISA specification such 'conflicts' can be identified by looking for clauses that redirect you to 'Related Encodings' or specific instructions. The VMLALDAV instruction is an example of the latter, where if RdaHi (bits 20-22) has value 7, then the encoding is actually to be decoded as the VMLADAV instruction. This patch also sets force_thumb when passing '-marmv8.1-m.main' to objdump. This makes it unnecessary to use '-M force-thumb' when disassembling for non-elf targets. opcodes/ChangeLog: 2019-05-01 Andre Vieira Michael Collison * arm-dis.c (enum mve_instructions): New enum. (enum mve_unpredictable): Likewise. (enum mve_undefined): Likewise. (struct mopcode32): New struct. (is_mve_okay_in_it): New function. (is_mve_architecture): Likewise. (arm_decode_field): Likewise. (arm_decode_field_multiple): Likewise. (is_mve_encoding_conflict): Likewise. (is_mve_undefined): Likewise. (is_mve_unpredictable): Likewise. (print_mve_undefined): Likewise. (print_mve_unpredictable): Likewise. (print_insn_coprocessor_1): Use arm_decode_field_multiple. (print_insn_mve): New function. (print_insn_thumb32): Handle MVE architecture. (select_arm_features): Force thumb for Armv8.1-m Mainline. --------------B7BD5736D5942434EE0D71EB Content-Type: text/x-patch; name="37.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="37.patch" Content-length: 9456 diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index 15d4d7248ea66f4b61278c708b796b3a5a23570b..6452d7c514bea751430a4906fa0ad4c8c8a136e8 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -68,6 +68,23 @@ struct arm_private_data bfd_vma last_mapping_addr; }; +enum mve_instructions +{ + MVE_NONE +}; + +enum mve_unpredictable +{ + UNPRED_IT_BLOCK, /* Unpredictable because mve insn in it block. + */ + UNPRED_NONE /* No unpredictable behavior. */ +}; + +enum mve_undefined +{ + UNDEF_NONE /* no undefined behavior. */ +}; + struct opcode32 { arm_feature_set arch; /* Architecture defining this insn. */ @@ -76,6 +93,18 @@ struct opcode32 const char * assembler; /* How to disassemble this insn. */ }; +/* MVE opcodes. */ + +struct mopcode32 +{ + arm_feature_set arch; /* Architecture defining this insn. */ + enum mve_instructions mve_op; /* Specific mve instruction for faster + decoding. */ + unsigned long value; /* If arch is 0 then value is a sentinel. */ + unsigned long mask; /* Recognise insn if (op & mask) == value. */ + const char * assembler; /* How to disassemble this insn. */ +}; + enum isa { ANY, T32, @@ -1756,6 +1785,18 @@ static const struct opcode32 neon_opcodes[] = {ARM_FEATURE_CORE_LOW (0), 0 ,0, 0} }; +/* mve opcode table. */ + +/* print_insn_mve recognizes the following format control codes: + + %% % + + */ + +static const struct mopcode32 mve_opcodes[] = +{ +}; + /* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb. All three are partially ordered: they must be searched linearly from the top to obtain a correct match. */ @@ -3449,6 +3490,105 @@ arm_decode_shift (long given, fprintf_ftype func, void *stream, } } +/* Return TRUE if the MATCHED_INSN can be inside an IT block. */ + +static bfd_boolean +is_mve_okay_in_it (enum mve_instructions matched_insn) +{ + return FALSE; +} + +static bfd_boolean +is_mve_architecture (struct disassemble_info *info) +{ + struct arm_private_data *private_data = info->private_data; + arm_feature_set allowed_arches = private_data->features; + + arm_feature_set arm_ext_v8_1m_main + = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN); + + if (ARM_CPU_HAS_FEATURE (arm_ext_v8_1m_main, allowed_arches) + && !ARM_CPU_IS_ANY (allowed_arches)) + return TRUE; + else + return FALSE; +} + +/* Decode a bitfield from opcode GIVEN, with starting bitfield = START + and ending bitfield = END. END must be greater than START. */ + +static unsigned long +arm_decode_field (unsigned long given, unsigned int start, unsigned int end) +{ + int bits = end - start; + + if (bits < 0) + abort (); + + return ((given >> start) & ((2ul << bits) - 1)); +} + +/* Decode a bitfield from opcode GIVEN, with multiple bitfields: + START:END and START2:END2. END/END2 must be greater than + START/START2. */ + +static unsigned long +arm_decode_field_multiple (unsigned long given, unsigned int start, + unsigned int end, unsigned int start2, + unsigned int end2) +{ + int bits = end - start; + int bits2 = end2 - start2; + unsigned long value = 0; + int width = 0; + + if (bits2 < 0) + abort (); + + value = arm_decode_field (given, start, end); + width += bits + 1; + + value |= ((given >> start2) & ((2ul << bits2) - 1)) << width; + return value; +} + +/* Return TRUE if the GIVEN encoding should not be decoded as MATCHED_INSN. + This helps us decode instructions that change mnemonic depending on specific + operand values/encodings. */ + +static bfd_boolean +is_mve_encoding_conflict (unsigned long given, + enum mve_instructions matched_insn) +{ + return FALSE; +} + +/* Return FALSE if GIVEN is not an undefined encoding for MATCHED_INSN. + Otherwise, return TRUE and set UNDEFINED_CODE to give a reason as to why + this encoding is undefined. */ + +static bfd_boolean +is_mve_undefined (unsigned long given, enum mve_instructions matched_insn, + enum mve_undefined *undefined_code) +{ + *undefined_code = UNDEF_NONE; + + return FALSE; +} + +/* Return FALSE if GIVEN is not an unpredictable encoding for MATCHED_INSN. + Otherwise, return TRUE and set UNPREDICTABLE_CODE to give a reason as to + why this encoding is unpredictable. */ + +static bfd_boolean +is_mve_unpredictable (unsigned long given, enum mve_instructions matched_insn, + enum mve_unpredictable *unpredictable_code) +{ + *unpredictable_code = UNPRED_NONE; + + return FALSE; +} + #define W_BIT 21 #define I_BIT 22 #define U_BIT 23 @@ -3459,6 +3599,43 @@ arm_decode_shift (long given, fprintf_ftype func, void *stream, #define NEGATIVE_BIT_SET ((given & (1 << U_BIT)) == 0) #define PRE_BIT_SET (given & (1 << P_BIT)) +static void +print_mve_undefined (struct disassemble_info *info, + enum mve_undefined undefined_code) +{ + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + func (stream, "\t\tundefined instruction: "); + + switch (undefined_code) + { + case UNDEF_NONE: + break; + } + +} + +static void +print_mve_unpredictable (struct disassemble_info *info, + enum mve_unpredictable unpredict_code) +{ + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + func (stream, "%s: ", UNPREDICTABLE_INSTRUCTION); + + switch (unpredict_code) + { + case UNPRED_IT_BLOCK: + func (stream, "mve instruction in it block"); + break; + + case UNPRED_NONE: + break; + } +} + /* Print one coprocessor instruction on INFO->STREAM. Return TRUE if the instuction matched, FALSE if this is not a recognised coprocessor instruction. */ @@ -3737,7 +3914,8 @@ print_insn_coprocessor_1 (const struct sopcode32 *opcodes, case 'J': { - int regno = ((given >> 19) & 0x8) | ((given >> 13) & 0x7); + unsigned long regno + = arm_decode_field_multiple (given, 13, 15, 22, 22); switch (regno) { @@ -3760,7 +3938,7 @@ print_insn_coprocessor_1 (const struct sopcode32 *opcodes, func (stream, "FPCXTS"); break; default: - func (stream, "", regno); + func (stream, "", regno); break; } } @@ -4774,6 +4952,75 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) return FALSE; } +/* Print one mve instruction on INFO->STREAM. + Return TRUE if the instuction matched, FALSE if this is not a + recognised mve instruction. */ + +static bfd_boolean +print_insn_mve (struct disassemble_info *info, long given) +{ + const struct mopcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + for (insn = mve_opcodes; insn->assembler; insn++) + { + if (((given & insn->mask) == insn->value) + && !is_mve_encoding_conflict (given, insn->mve_op)) + { + signed long value_in_comment = 0; + bfd_boolean is_unpredictable = FALSE; + bfd_boolean is_undefined = FALSE; + const char *c; + enum mve_unpredictable unpredictable_cond = UNPRED_NONE; + enum mve_undefined undefined_cond = UNDEF_NONE; + + /* Most vector mve instruction are illegal in a it block. + There are a few exceptions; check for them. */ + if (ifthen_state && !is_mve_okay_in_it (insn->mve_op)) + { + is_unpredictable = TRUE; + unpredictable_cond = UNPRED_IT_BLOCK; + } + else if (is_mve_unpredictable (given, insn->mve_op, + &unpredictable_cond)) + is_unpredictable = TRUE; + + if (is_mve_undefined (given, insn->mve_op, &undefined_cond)) + is_undefined = TRUE; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + } + } + else + func (stream, "%c", *c); + } + + if (value_in_comment > 32 || value_in_comment < -16) + func (stream, "\t; 0x%lx", value_in_comment); + + if (is_unpredictable) + print_mve_unpredictable (info, unpredictable_cond); + + if (is_undefined) + print_mve_undefined (info, undefined_cond); + + return TRUE; + } + } + return FALSE; +} + + /* Return the name of a v7A special register. */ static const char * @@ -5687,11 +5934,15 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) const struct opcode32 *insn; void *stream = info->stream; fprintf_ftype func = info->fprintf_func; + bfd_boolean is_mve = is_mve_architecture (info); if (print_insn_coprocessor (pc, info, given, TRUE)) return; - if (print_insn_neon (info, given, TRUE)) + if ((is_mve == FALSE) && print_insn_neon (info, given, TRUE)) + return; + + if (is_mve && print_insn_mve (info, given)) return; if (print_insn_generic_coprocessor (pc, info, given, TRUE)) @@ -6739,7 +6990,10 @@ select_arm_features (unsigned long mach, case bfd_mach_arm_8R: ARM_SET_FEATURES (ARM_ARCH_V8R); break; case bfd_mach_arm_8M_BASE: ARM_SET_FEATURES (ARM_ARCH_V8M_BASE); break; case bfd_mach_arm_8M_MAIN: ARM_SET_FEATURES (ARM_ARCH_V8M_MAIN); break; - case bfd_mach_arm_8_1M_MAIN: ARM_SET_FEATURES (ARM_ARCH_V8_1M_MAIN); break; + case bfd_mach_arm_8_1M_MAIN: + ARM_SET_FEATURES (ARM_ARCH_V8_1M_MAIN); + force_thumb = 1; + break; /* If the machine type is unknown allow all architecture types and all extensions. */ case bfd_mach_arm_unknown: ARM_SET_FEATURES (ARM_FEATURE_ALL); break; --------------B7BD5736D5942434EE0D71EB--