[v1,7/8] aarch64: add flag OPD_F_UNSIGNED to distinguish signedness of immediate operands
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
This patch introduces a new operand flag OPD_F_UNSIGNED to signal that
the immediate value should be treated as an unsigned value. The default
signedness of immediate operands is signed.
---
opcodes/aarch64-opc.c | 93 ++++++++++++++++++++++++++++++++-----------
opcodes/aarch64-opc.h | 7 ++++
2 files changed, 77 insertions(+), 23 deletions(-)
Comments
On 23/10/2024 11:48, Matthieu Longo wrote:
> This patch introduces a new operand flag OPD_F_UNSIGNED to signal that
> the immediate value should be treated as an unsigned value. The default
> signedness of immediate operands is signed.
> ---
> opcodes/aarch64-opc.c | 93 ++++++++++++++++++++++++++++++++-----------
> opcodes/aarch64-opc.h | 7 ++++
> 2 files changed, 77 insertions(+), 23 deletions(-)
>
> diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
> index 93ae8767dfe..43c7348d331 100644
> --- a/opcodes/aarch64-opc.c
> +++ b/opcodes/aarch64-opc.c
> @@ -1620,6 +1620,55 @@ check_reglist (const aarch64_opnd_info *opnd,
> return true;
> }
>
> +typedef struct
> +{
> + int64_t min;
> + int64_t max;
> +} imm_range_t;
> +
> +static imm_range_t
> +imm_range_min_max (unsigned size, bool signed_rng)
> +{
> + assert (size < 63);
> + imm_range_t r;
> + if (signed_rng)
> + {
> + r.max = (((int64_t) 0x1) << (size - 1)) - 1;
> + r.min = - r.max - 1;
> + }
> + else
> + {
> + r.max = (((int64_t) 0x1) << size) - 1;
> + r.min = 0;
> + }
> + return r;
> +}
> +
> +/* Check that an immediate value is in the range provided by the
> + operand type. */
> +static bool
> +check_immediate_out_of_range (int64_t imm,
> + enum aarch64_opnd type,
> + aarch64_operand_error *mismatch_detail,
> + int idx)
> +{
> + const aarch64_operand *operand = get_operand_from_code (type);
> + uint8_t size = get_operand_fields_width (operand);
> + bool unsigned_imm = operand_need_unsigned_offset (operand);
> + bool (*value_fit_field) (int64_t, unsigned)
> + = (unsigned_imm
> + ? value_fit_unsigned_field_p
> + : value_fit_signed_field_p);
> +
> + if (!value_fit_field (imm, size))
> + {
> + imm_range_t rng = imm_range_min_max (size, !unsigned_imm);
> + set_imm_out_of_range_error (mismatch_detail, idx, rng.min, rng.max);
> + return false;
> + }
> + return true;
> +}
> +
> /* Check that indexed ZA operand OPND has:
>
> - a selection register in the range [MIN_WREG, MIN_WREG + 3]
> @@ -2375,27 +2424,25 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
> case AARCH64_OPND_ADDR_PCREL19:
> case AARCH64_OPND_ADDR_PCREL21:
> case AARCH64_OPND_ADDR_PCREL26:
> - imm = opnd->imm.value;
> - if (operand_need_shift_by_two (get_operand_from_code (type)))
> - {
> - /* The offset value in a PC-relative branch instruction is alway
> - 4-byte aligned and is encoded without the lowest 2 bits. */
> - if (!value_aligned_p (imm, 4))
> - {
> - set_unaligned_error (mismatch_detail, idx, 4);
> - return false;
> - }
> - /* Right shift by 2 so that we can carry out the following check
> - canonically. */
> - imm >>= 2;
> - }
> - size = get_operand_fields_width (get_operand_from_code (type));
> - if (!value_fit_signed_field_p (imm, size))
> - {
> - set_other_error (mismatch_detail, idx,
> - _("immediate out of range"));
> + {
> + imm = opnd->imm.value;
> + if (operand_need_shift_by_two (get_operand_from_code (type)))
> + {
> + /* The offset value in a PC-relative branch instruction is alway
> + 4-byte aligned and is encoded without the lowest 2 bits. */
> + if (!value_aligned_p (imm, 4))
> + {
> + set_unaligned_error (mismatch_detail, idx, 4);
> + return false;
> + }
> + /* Right shift by 2 so that we can carry out the following check
> + canonically. */
> + imm >>= 2;
> + }
> +
> + if (!check_immediate_out_of_range (imm, type, mismatch_detail, idx))
> return false;
> - }
> + }
> break;
>
> case AARCH64_OPND_SME_ADDR_RI_U4xVL:
> @@ -2809,9 +2856,9 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
> assert (size < 32);
> if (!value_fit_signed_field_p (opnd->imm.value, size))
> {
> - set_imm_out_of_range_error (mismatch_detail, idx,
> - -(1 << (size - 1)),
> - (1 << (size - 1)) - 1);
> + imm_range_t rng = imm_range_min_max (size, true);
> + set_imm_out_of_range_error (mismatch_detail, idx, rng.min,
> + rng.max);
> return false;
> }
> break;
> diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
> index d600f40cf5c..e7495cdb5fb 100644
> --- a/opcodes/aarch64-opc.h
> +++ b/opcodes/aarch64-opc.h
> @@ -298,6 +298,7 @@ verify_constraints (const struct aarch64_inst *, const aarch64_insn, bfd_vma,
> #define OPD_F_SHIFT_BY_4 0x00000800 /* Need to left shift the field
> value by 4 to get the value
> of an immediate operand. */
> +#define OPD_F_UNSIGNED 0x00001000 /* Expect an unsigned value. */
>
>
> /* Register flags. */
> @@ -401,6 +402,12 @@ operand_need_shift_by_four (const aarch64_operand *operand)
> return (operand->flags & OPD_F_SHIFT_BY_4) != 0;
> }
>
> +static inline bool
> +operand_need_unsigned_offset (const aarch64_operand *operand)
> +{
> + return (operand->flags & OPD_F_UNSIGNED) != 0;
> +}
> +
> static inline bool
> operand_maybe_stack_pointer (const aarch64_operand *operand)
> {
OK.
R.
@@ -1620,6 +1620,55 @@ check_reglist (const aarch64_opnd_info *opnd,
return true;
}
+typedef struct
+{
+ int64_t min;
+ int64_t max;
+} imm_range_t;
+
+static imm_range_t
+imm_range_min_max (unsigned size, bool signed_rng)
+{
+ assert (size < 63);
+ imm_range_t r;
+ if (signed_rng)
+ {
+ r.max = (((int64_t) 0x1) << (size - 1)) - 1;
+ r.min = - r.max - 1;
+ }
+ else
+ {
+ r.max = (((int64_t) 0x1) << size) - 1;
+ r.min = 0;
+ }
+ return r;
+}
+
+/* Check that an immediate value is in the range provided by the
+ operand type. */
+static bool
+check_immediate_out_of_range (int64_t imm,
+ enum aarch64_opnd type,
+ aarch64_operand_error *mismatch_detail,
+ int idx)
+{
+ const aarch64_operand *operand = get_operand_from_code (type);
+ uint8_t size = get_operand_fields_width (operand);
+ bool unsigned_imm = operand_need_unsigned_offset (operand);
+ bool (*value_fit_field) (int64_t, unsigned)
+ = (unsigned_imm
+ ? value_fit_unsigned_field_p
+ : value_fit_signed_field_p);
+
+ if (!value_fit_field (imm, size))
+ {
+ imm_range_t rng = imm_range_min_max (size, !unsigned_imm);
+ set_imm_out_of_range_error (mismatch_detail, idx, rng.min, rng.max);
+ return false;
+ }
+ return true;
+}
+
/* Check that indexed ZA operand OPND has:
- a selection register in the range [MIN_WREG, MIN_WREG + 3]
@@ -2375,27 +2424,25 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
case AARCH64_OPND_ADDR_PCREL19:
case AARCH64_OPND_ADDR_PCREL21:
case AARCH64_OPND_ADDR_PCREL26:
- imm = opnd->imm.value;
- if (operand_need_shift_by_two (get_operand_from_code (type)))
- {
- /* The offset value in a PC-relative branch instruction is alway
- 4-byte aligned and is encoded without the lowest 2 bits. */
- if (!value_aligned_p (imm, 4))
- {
- set_unaligned_error (mismatch_detail, idx, 4);
- return false;
- }
- /* Right shift by 2 so that we can carry out the following check
- canonically. */
- imm >>= 2;
- }
- size = get_operand_fields_width (get_operand_from_code (type));
- if (!value_fit_signed_field_p (imm, size))
- {
- set_other_error (mismatch_detail, idx,
- _("immediate out of range"));
+ {
+ imm = opnd->imm.value;
+ if (operand_need_shift_by_two (get_operand_from_code (type)))
+ {
+ /* The offset value in a PC-relative branch instruction is alway
+ 4-byte aligned and is encoded without the lowest 2 bits. */
+ if (!value_aligned_p (imm, 4))
+ {
+ set_unaligned_error (mismatch_detail, idx, 4);
+ return false;
+ }
+ /* Right shift by 2 so that we can carry out the following check
+ canonically. */
+ imm >>= 2;
+ }
+
+ if (!check_immediate_out_of_range (imm, type, mismatch_detail, idx))
return false;
- }
+ }
break;
case AARCH64_OPND_SME_ADDR_RI_U4xVL:
@@ -2809,9 +2856,9 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
assert (size < 32);
if (!value_fit_signed_field_p (opnd->imm.value, size))
{
- set_imm_out_of_range_error (mismatch_detail, idx,
- -(1 << (size - 1)),
- (1 << (size - 1)) - 1);
+ imm_range_t rng = imm_range_min_max (size, true);
+ set_imm_out_of_range_error (mismatch_detail, idx, rng.min,
+ rng.max);
return false;
}
break;
@@ -298,6 +298,7 @@ verify_constraints (const struct aarch64_inst *, const aarch64_insn, bfd_vma,
#define OPD_F_SHIFT_BY_4 0x00000800 /* Need to left shift the field
value by 4 to get the value
of an immediate operand. */
+#define OPD_F_UNSIGNED 0x00001000 /* Expect an unsigned value. */
/* Register flags. */
@@ -401,6 +402,12 @@ operand_need_shift_by_four (const aarch64_operand *operand)
return (operand->flags & OPD_F_SHIFT_BY_4) != 0;
}
+static inline bool
+operand_need_unsigned_offset (const aarch64_operand *operand)
+{
+ return (operand->flags & OPD_F_UNSIGNED) != 0;
+}
+
static inline bool
operand_maybe_stack_pointer (const aarch64_operand *operand)
{