This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[GAS][ARM][2/3]Add SE_H shape to represent fp16 type.
- From: Renlin Li <renlin dot li at foss dot arm dot com>
- To: "binutils at sourceware dot org" <binutils at sourceware dot org>
- Cc: Nicholas Clifton <nickc at redhat dot com>, Marcus Shawcroft <Marcus dot Shawcroft at arm dot com>, Ramana Radhakrishnan <Ramana dot Radhakrishnan at arm dot com>, Richard Earnshaw <Richard dot Earnshaw at arm dot com>
- Date: Fri, 19 Feb 2016 11:30:48 +0000
- Subject: [GAS][ARM][2/3]Add SE_H shape to represent fp16 type.
- Authentication-results: sourceware.org; auth=none
- References: <56C6FB4A dot 7000302 at foss dot arm dot com>
Hi all,
This patch makes generic change to add a new neon shape SE_H to
represent VFP single
precision register operand whose type specifier is .f16, .16, u16, s16.
This will facilitate further patch to add ARMv8.2 fp16 instruction
support into GAS.
for example, after the change, the new instruction share for the
following instruction is changed:
vcvtt.f16.f64 s0, d0: NS_HD, instead of NS_FD
vcvtt.f64.f16 d0, s0: NS_DH, instead of NS_DF
vcvtb s2.f16, s5.f32: NS_HF, instead of NS_FF
vcvtb.f16.f32 s2, s5: NS_HF, instead of NS_FF
The logic here is that:
for a VFP single precision register operand:
(inst.operands[j].isreg && inst.operands[j].isvec &&
inst.operands[j].issingle && !inst.operands[j].isquad),
the following cases are considered:
Only one type specifier as the following, this applies to all single
precision register operand.
mnemonic.type reg1, reg2, reg3
For this illegal case, type1 is ignored. The error should be caught by
existing code. type and type1 cannot
specified at the same time.
mnemonic.type reg1.type1, reg2, reg3
Type specifier given as the following. Inside gas, it allows some
"flexibility". It allows the following situations
if the key operands has type specifier. It will try to infer the others
from the key operand.
However, I don't think those cases are encouraged. The type specifier
applies to associated register operand.
Other operands shape is derived from register class.
mnemonic reg1.type1, reg2.type2, reg3
mnemonic reg1.type1, reg2, reg3
Multiple type specifier (each register have one). Decided by related
type specifier associated with the register operand.
mnemonic.type1.type2 reg1, reg2
mnemonic reg1.type1, reg2.type2
Binutils checked without any issues. Okay to commit?
Regards,
Renlin Li
gas/ChangeLog:
2016-02-19 Renlin Li <renlin.li@arm.com>
* config/tc-arm.c (NEON_ENC_TAB): Add fp16 instruction shape.
(neon_shape_class): New SC_HALF.
(neon_shape_el): New SE_H.
(neon_shape_el_size): New size for SE_H.
(N_F_ALL): New macro to aggregate N_F16, N_F32, N_64.
(neon_select_shape): Add SE_H support code.
(el_type_of_type_chk): Use N_F_ALL.
(do_vfp_nsyn_cvt): Add SE_H shape support.
(do_neon_cvtz): Likewise.
(do_neon_cvt_1): Likewise.
(do_neon_cvttb_1): Likewise.
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index e4ab6c2d2e9d27de0ef3c474a476c67687821e8f..8d2078bab4a051f47e77bf419ed5de6fee3957de 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -13197,7 +13197,19 @@ NEON_ENC_TAB
X(2, (S, R), SINGLE), \
X(2, (R, S), SINGLE), \
X(2, (F, R), SINGLE), \
- X(2, (R, F), SINGLE)
+ X(2, (R, F), SINGLE), \
+/* Half float shape supported so far. */\
+ X (2, (H, D), MIXED), \
+ X (2, (D, H), MIXED), \
+ X (2, (H, F), MIXED), \
+ X (2, (F, H), MIXED), \
+ X (2, (H, H), HALF), \
+ X (2, (H, R), HALF), \
+ X (2, (R, H), HALF), \
+ X (2, (H, I), HALF), \
+ X (3, (H, H, H), HALF), \
+ X (3, (H, F, I), MIXED), \
+ X (3, (F, H, I), MIXED)
#define S2(A,B) NS_##A##B
#define S3(A,B,C) NS_##A##B##C
@@ -13218,6 +13230,7 @@ enum neon_shape
enum neon_shape_class
{
+ SC_HALF,
SC_SINGLE,
SC_DOUBLE,
SC_QUAD,
@@ -13235,6 +13248,7 @@ static enum neon_shape_class neon_shape_class[] =
enum neon_shape_el
{
+ SE_H,
SE_F,
SE_D,
SE_Q,
@@ -13247,6 +13261,7 @@ enum neon_shape_el
/* Register widths of above. */
static unsigned neon_shape_el_size[] =
{
+ 16,
32,
64,
128,
@@ -13331,6 +13346,7 @@ enum neon_type_mask
#define N_SUF_32 (N_SU_32 | N_F32)
#define N_I_ALL (N_I8 | N_I16 | N_I32 | N_I64)
#define N_IF_32 (N_I8 | N_I16 | N_I32 | N_F32)
+#define N_F_ALL (N_F16 | N_F32 | N_F64)
/* Pass this as the first type argument to neon_check_type to ignore types
altogether. */
@@ -13372,11 +13388,56 @@ neon_select_shape (enum neon_shape shape, ...)
switch (neon_shape_tab[shape].el[j])
{
+ /* If a .f16, .16, .u16, .s16 type specifier is given over
+ a VFP single precision register operand, it's essentially
+ means only half of the register is used.
+
+ If the type specifier is given after the mnemonics, the
+ information is stored in inst.vectype. If the type specifier
+ is given after register operand, the information is stored
+ in inst.operands[].vectype.
+
+ When there is only one type specifier, and all the register
+ operands are the same type of hardware register, the type
+ specifier applies to all register operands.
+
+ If no type specifier is given, the shape is inferred from
+ operand information.
+
+ for example:
+ vadd.f16 s0, s1, s2: NS_HHH
+ vabs.f16 s0, s1: NS_HH
+ vmov.f16 s0, r1: NS_HR
+ vmov.f16 r0, s1: NS_RH
+ vcvt.f16 r0, s1: NS_RH
+ vcvt.f16.s32 s2, s2, #29: NS_HFI
+ vcvt.f16.s32 s2, s2: NS_HF
+ */
+ case SE_H:
+ if (!(inst.operands[j].isreg
+ && inst.operands[j].isvec
+ && inst.operands[j].issingle
+ && !inst.operands[j].isquad
+ && ((inst.vectype.elems == 1
+ && inst.vectype.el[0].size == 16)
+ || (inst.vectype.elems > 1
+ && inst.vectype.el[j].size == 16)
+ || (inst.vectype.elems == 0
+ && inst.operands[j].vectype.type != NT_invtype
+ && inst.operands[j].vectype.size == 16))))
+ matches = 0;
+ break;
+
case SE_F:
if (!(inst.operands[j].isreg
&& inst.operands[j].isvec
&& inst.operands[j].issingle
- && !inst.operands[j].isquad))
+ && !inst.operands[j].isquad
+ && ((inst.vectype.elems == 1 && inst.vectype.el[0].size == 32)
+ || (inst.vectype.elems > 1 && inst.vectype.el[j].size == 32)
+ || (inst.vectype.elems == 0
+ && (inst.operands[j].vectype.size == 32
+ || inst.operands[j].vectype.type == NT_invtype)))))
matches = 0;
break;
@@ -13592,7 +13653,7 @@ el_type_of_type_chk (enum neon_el_type *type, unsigned *size,
*type = NT_untyped;
else if ((mask & (N_P8 | N_P16 | N_P64)) != 0)
*type = NT_poly;
- else if ((mask & (N_F16 | N_F32 | N_F64)) != 0)
+ else if ((mask & (N_F_ALL)) != 0)
*type = NT_float;
else
return FAIL;
@@ -15152,7 +15213,8 @@ do_vfp_nsyn_cvt (enum neon_shape rs, enum neon_cvt_flavour flavour)
{
const char *opname = 0;
- if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI)
+ if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI
+ || rs == NS_FHI || rs == NS_HFI)
{
/* Conversions with immediate bitshift. */
const char *enc[] =
@@ -15194,7 +15256,7 @@ do_vfp_nsyn_cvt (enum neon_shape rs, enum neon_cvt_flavour flavour)
static void
do_vfp_nsyn_cvtz (void)
{
- enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_NULL);
+ enum neon_shape rs = neon_select_shape (NS_FH, NS_FF, NS_FD, NS_NULL);
enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
const char *enc[] =
{
@@ -15270,7 +15332,9 @@ static void
do_neon_cvt_1 (enum neon_cvt_mode mode)
{
enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
- NS_FD, NS_DF, NS_FF, NS_QD, NS_DQ, NS_NULL);
+ NS_FD, NS_DF, NS_FF, NS_QD, NS_DQ,
+ NS_FH, NS_HF, NS_FHI, NS_HFI,
+ NS_NULL);
enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
/* PR11109: Handle round-to-zero for VCVT conversions. */
@@ -15470,7 +15534,8 @@ do_neon_cvttb_2 (bfd_boolean t, bfd_boolean to, bfd_boolean is_double)
static void
do_neon_cvttb_1 (bfd_boolean t)
{
- enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_DF, NS_NULL);
+ enum neon_shape rs = neon_select_shape (NS_HF, NS_HD, NS_FH, NS_FF, NS_FD,
+ NS_DF, NS_DH, NS_NULL);
if (rs == NS_NULL)
return;