From c3f624153a3c7b7ba3fd64512d5e15ebc1ff7796 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 25 Jun 2018 18:35:36 +0100 Subject: [PATCH] i#2626 AArch64 enc: Add FP data-processing instrs (1 source) (#3061) This patch adds support for the instructions in the Armv8-a 'Floating-point data-processing' encoding groups with 1 source. Issue #2626 --- core/arch/aarch64/codec.c | 41 ++++++ core/arch/aarch64/codec.txt | 23 ++++ core/arch/aarch64/instr_create.h | 110 ++++++++++++++++ suite/tests/api/dis-a64.txt | 41 ++++++ suite/tests/api/ir_aarch64.c | 205 ++++++++++++++++++++++++++++++ suite/tests/api/ir_aarch64.expect | 40 ++++++ 6 files changed, 460 insertions(+) diff --git a/core/arch/aarch64/codec.c b/core/arch/aarch64/codec.c index 8b305ad3827..ab14eb134e0 100644 --- a/core/arch/aarch64/codec.c +++ b/core/arch/aarch64/codec.c @@ -2304,6 +2304,47 @@ encode_opnd_w5(uint enc, int opcode, byte *pc, opnd_t opnd, OUT uint *enc_out) return encode_opnd_wxn(false, false, 5, opnd, enc_out); } +/* h5: H register at bit position 5 */ + +static inline bool +decode_opnd_h5(uint enc, int opcode, byte *pc, OUT opnd_t *opnd) +{ + return decode_opnd_vector_reg(5, 1, enc, opnd); +} + +static inline bool +encode_opnd_h5(uint enc, int opcode, byte *pc, opnd_t opnd, OUT uint *enc_out) +{ + return encode_opnd_vector_reg(5, 1, opnd, enc_out); +} + +/* s5: S register at bit position 5 */ + +static inline bool +decode_opnd_s5(uint enc, int opcode, byte *pc, OUT opnd_t *opnd) +{ + return decode_opnd_vector_reg(5, 2, enc, opnd); +} + +static inline bool +encode_opnd_s5(uint enc, int opcode, byte *pc, opnd_t opnd, OUT uint *enc_out) +{ + return encode_opnd_vector_reg(5, 2, opnd, enc_out); +} + +/* d5: D register at bit position 5 */ + +static inline bool +decode_opnd_d5(uint enc, int opcode, byte *pc, OUT opnd_t *opnd) +{ + return decode_opnd_vector_reg(5, 3, enc, opnd); +} + +static inline bool +encode_opnd_d5(uint enc, int opcode, byte *pc, opnd_t opnd, OUT uint *enc_out) +{ + return encode_opnd_vector_reg(5, 3, opnd, enc_out); +} /* wx0: W/X register or WZR/XZR at bit position 0; bit 31 selects X reg */ static inline bool diff --git a/core/arch/aarch64/codec.txt b/core/arch/aarch64/codec.txt index 9d15d8a76dc..cbae45ccb9d 100644 --- a/core/arch/aarch64/codec.txt +++ b/core/arch/aarch64/codec.txt @@ -77,6 +77,9 @@ ----------------------xxxxx----- w5 # W register (or WZR) ----------------------xxxxx----- x5 # X register (or XZR) ----------------------xxxxx----- x5sp # X register or XSP +----------------------xxxxx----- h5 # H register +----------------------xxxxx----- s5 # S register +----------------------xxxxx----- d5 # D register ??--------------------xxxxx----- mem0 # gets size from 31:30; no offset -?--------------------xxxxx----- mem0p # gets size from 30; no offset, pair ??---?----------------xxxxx----- mem7post # gets size from 31:30 and 26; post-index @@ -1077,3 +1080,23 @@ x101101011000000000101xxxxxxxxxx cls wx0 : wx5 0x1011101x1xxxxx111101xxxxxxxxxx fminp dq0 : dq5 dq16 sd_sz 0x101110101xxxxx000111xxxxxxxxxx bit dq0 : dq5 dq16 0x101110111xxxxx000111xxxxxxxxxx bif dq0 : dq5 dq16 + + +# Floating-point data-processing (1 source) +00011110xx100000010000xxxxxxxxxx fmov float_reg0 : float_reg5 +00011110xx100000110000xxxxxxxxxx fabs float_reg0 : float_reg5 +00011110xx100001010000xxxxxxxxxx fneg float_reg0 : float_reg5 +00011110xx100001110000xxxxxxxxxx fsqrt float_reg0 : float_reg5 +0001111000100010110000xxxxxxxxxx fcvt d0 : s5 +0001111000100011110000xxxxxxxxxx fcvt h0 : s5 +00011110xx100100010000xxxxxxxxxx frintn float_reg0 : float_reg5 +00011110xx100100110000xxxxxxxxxx frintp float_reg0 : float_reg5 +00011110xx100101010000xxxxxxxxxx frintm float_reg0 : float_reg5 +00011110xx100101110000xxxxxxxxxx frintz float_reg0 : float_reg5 +00011110xx100110010000xxxxxxxxxx frinta float_reg0 : float_reg5 +00011110xx100111010000xxxxxxxxxx frintx float_reg0 : float_reg5 +00011110xx100111110000xxxxxxxxxx frinti float_reg0 : float_reg5 +0001111001100010010000xxxxxxxxxx fcvt s0 : d5 +0001111001100011110000xxxxxxxxxx fcvt h0 : d5 +0001111011100010010000xxxxxxxxxx fcvt s0 : h5 +0001111011100010110000xxxxxxxxxx fcvt d0 : h5 diff --git a/core/arch/aarch64/instr_create.h b/core/arch/aarch64/instr_create.h index 5b276e54471..d0b2d61c947 100644 --- a/core/arch/aarch64/instr_create.h +++ b/core/arch/aarch64/instr_create.h @@ -1566,5 +1566,115 @@ #define INSTR_CREATE_bif_vector(dc, Rd, Rm, Rn) \ instr_create_1dst_2src(dc, OP_bif, Rd, Rm, Rn) +/* -------- Floating-point data-processing (1 source) ------------------ */ + +/** + * Creates a FMOV floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_fmov_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_fmov, Rd, Rm) + +/** + * Creates a FABS floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_fabs_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_fabs, Rd, Rm) + +/** + * Creates a FNEG floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_fneg_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_fneg, Rd, Rm) + +/** + * Creates a FSQRT floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_fsqrt_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_fsqrt, Rd, Rm) + +/** + * Creates a FCVT floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_fcvt_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_fcvt, Rd, Rm) + +/** + * Creates a FRINTN floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_frintn_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_frintn, Rd, Rm) + +/** + * Creates a FRINTP floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_frintp_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_frintp, Rd, Rm) + +/** + * Creates a FRINTM floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_frintm_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_frintm, Rd, Rm) + +/** + * Creates a FRINTZ floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_frintz_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_frintz, Rd, Rm) + +/** + * Creates a FRINTA floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_frinta_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_frinta, Rd, Rm) + +/** + * Creates a FRINTX floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_frintx_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_frintx, Rd, Rm) + +/** + * Creates a FRINTI floating point instruction. + * \param dc The void * dcontext used to allocate memory for the instr_t. + * \param Rd The output register. + * \param Rm The first input register. + */ +#define INSTR_CREATE_frinti_scalar(dc, Rd, Rm) \ + instr_create_1dst_1src(dc, OP_frinti, Rd, Rm) + /* DR_API EXPORT END */ #endif /* INSTR_CREATE_H */ diff --git a/suite/tests/api/dis-a64.txt b/suite/tests/api/dis-a64.txt index 28e00e54a59..8478abf3b2e 100644 --- a/suite/tests/api/dis-a64.txt +++ b/suite/tests/api/dis-a64.txt @@ -1991,3 +1991,44 @@ fd7fffff : ldr d31, [sp,#32760] : ldr +0x7ff8(%sp)[8byte] -> %d31 6eac1eac : bit v12.16b, v21.16b, v12.16b : bit %q21 %q12 -> %q12 2ee31c74 : bif v20.8b, v3.8b, v3.8b : bif %d3 %d3 -> %d20 6ee31c74 : bif v20.16b, v3.16b, v3.16b : bif %q3 %q3 -> %q20 + +# Floating-point data-processing (1 source) +1e604362 : fmov d2, d27 : fmov %d27 -> %d2 +1e204362 : fmov s2, s27 : fmov %s27 -> %s2 +1ee04362 : fmov h2, h27 : fmov %h27 -> %h2 +1e60c01e : fabs d30, d0 : fabs %d0 -> %d30 +1e20c01e : fabs s30, s0 : fabs %s0 -> %s30 +1ee0c01e : fabs h30, h0 : fabs %h0 -> %h30 +1e6143ad : fneg d13, d29 : fneg %d29 -> %d13 +1e2143ad : fneg s13, s29 : fneg %s29 -> %s13 +1ee143ad : fneg h13, h29 : fneg %h29 -> %h13 +1e61c23f : fsqrt d31, d17 : fsqrt %d17 -> %d31 +1e21c23f : fsqrt s31, s17 : fsqrt %s17 -> %s31 +1ee1c23f : fsqrt h31, h17 : fsqrt %h17 -> %h31 +1e22c04a : fcvt d10, s2 : fcvt %s2 -> %d10 +1e23c29f : fcvt h31, s20 : fcvt %s20 -> %h31 +1e6441e4 : frintn d4, d15 : frintn %d15 -> %d4 +1e2441e4 : frintn s4, s15 : frintn %s15 -> %s4 +1ee441e4 : frintn h4, h15 : frintn %h15 -> %h4 +1e64c057 : frintp d23, d2 : frintp %d2 -> %d23 +1e24c057 : frintp s23, s2 : frintp %s2 -> %s23 +1ee4c057 : frintp h23, h2 : frintp %h2 -> %h23 +1e65411a : frintm d26, d8 : frintm %d8 -> %d26 +1e25411a : frintm s26, s8 : frintm %s8 -> %s26 +1ee5411a : frintm h26, h8 : frintm %h8 -> %h26 +1e65c316 : frintz d22, d24 : frintz %d24 -> %d22 +1e25c316 : frintz s22, s24 : frintz %s24 -> %s22 +1ee5c316 : frintz h22, h24 : frintz %h24 -> %h22 +1e66425a : frinta d26, d18 : frinta %d18 -> %d26 +1e26425a : frinta s26, s18 : frinta %s18 -> %s26 +1ee6425a : frinta h26, h18 : frinta %h18 -> %h26 +1e6743b0 : frintx d16, d29 : frintx %d29 -> %d16 +1e2743b0 : frintx s16, s29 : frintx %s29 -> %s16 +1ee743b0 : frintx h16, h29 : frintx %h29 -> %h16 +1e67c26b : frinti d11, d19 : frinti %d19 -> %d11 +1e27c26b : frinti s11, s19 : frinti %s19 -> %s11 +1ee7c26b : frinti h11, h19 : frinti %h19 -> %h11 +1e624117 : fcvt s23, d8 : fcvt %d8 -> %s23 +1e63c1fd : fcvt h29, d15 : fcvt %d15 -> %h29 +1ee2431c : fcvt s28, h24 : fcvt %h24 -> %s28 +1ee2c002 : fcvt d2, h0 : fcvt %h0 -> %d2 diff --git a/suite/tests/api/ir_aarch64.c b/suite/tests/api/ir_aarch64.c index 8b7896098ac..26def0769f4 100644 --- a/suite/tests/api/ir_aarch64.c +++ b/suite/tests/api/ir_aarch64.c @@ -3314,7 +3314,209 @@ test_asimdsame(void *dc) test_instr_encoding(dc, OP_bif, instr); } +static void +test_floatdp1(void *dc) +{ + byte *pc; + instr_t *instr; + + /* Floating-point data-processing (1 source) */ + + instr = INSTR_CREATE_fmov_scalar(dc, + opnd_create_reg(DR_REG_D2), + opnd_create_reg(DR_REG_D27)); + test_instr_encoding(dc, OP_fmov, instr); + + instr = INSTR_CREATE_fmov_scalar(dc, + opnd_create_reg(DR_REG_S2), + opnd_create_reg(DR_REG_S27)); + test_instr_encoding(dc, OP_fmov, instr); + + instr = INSTR_CREATE_fmov_scalar(dc, + opnd_create_reg(DR_REG_H2), + opnd_create_reg(DR_REG_H27)); + test_instr_encoding(dc, OP_fmov, instr); + + instr = INSTR_CREATE_fabs_scalar(dc, + opnd_create_reg(DR_REG_D30), + opnd_create_reg(DR_REG_D0)); + test_instr_encoding(dc, OP_fabs, instr); + + instr = INSTR_CREATE_fabs_scalar(dc, + opnd_create_reg(DR_REG_S30), + opnd_create_reg(DR_REG_S0)); + test_instr_encoding(dc, OP_fabs, instr); + + instr = INSTR_CREATE_fabs_scalar(dc, + opnd_create_reg(DR_REG_H30), + opnd_create_reg(DR_REG_H0)); + test_instr_encoding(dc, OP_fabs, instr); + + instr = INSTR_CREATE_fneg_scalar(dc, + opnd_create_reg(DR_REG_D13), + opnd_create_reg(DR_REG_D29)); + test_instr_encoding(dc, OP_fneg, instr); + + instr = INSTR_CREATE_fneg_scalar(dc, + opnd_create_reg(DR_REG_S13), + opnd_create_reg(DR_REG_S29)); + test_instr_encoding(dc, OP_fneg, instr); + instr = INSTR_CREATE_fneg_scalar(dc, + opnd_create_reg(DR_REG_H13), + opnd_create_reg(DR_REG_H29)); + test_instr_encoding(dc, OP_fneg, instr); + + instr = INSTR_CREATE_fsqrt_scalar(dc, + opnd_create_reg(DR_REG_D31), + opnd_create_reg(DR_REG_D17)); + test_instr_encoding(dc, OP_fsqrt, instr); + + instr = INSTR_CREATE_fsqrt_scalar(dc, + opnd_create_reg(DR_REG_S31), + opnd_create_reg(DR_REG_S17)); + test_instr_encoding(dc, OP_fsqrt, instr); + + instr = INSTR_CREATE_fsqrt_scalar(dc, + opnd_create_reg(DR_REG_H31), + opnd_create_reg(DR_REG_H17)); + test_instr_encoding(dc, OP_fsqrt, instr); + + instr = INSTR_CREATE_fcvt_scalar(dc, + opnd_create_reg(DR_REG_D10), + opnd_create_reg(DR_REG_S2)); + test_instr_encoding(dc, OP_fcvt, instr); + + instr = INSTR_CREATE_fcvt_scalar(dc, + opnd_create_reg(DR_REG_H31), + opnd_create_reg(DR_REG_S20)); + test_instr_encoding(dc, OP_fcvt, instr); + + instr = INSTR_CREATE_frintn_scalar(dc, + opnd_create_reg(DR_REG_D4), + opnd_create_reg(DR_REG_D15)); + test_instr_encoding(dc, OP_frintn, instr); + + instr = INSTR_CREATE_frintn_scalar(dc, + opnd_create_reg(DR_REG_S4), + opnd_create_reg(DR_REG_S15)); + test_instr_encoding(dc, OP_frintn, instr); + + instr = INSTR_CREATE_frintn_scalar(dc, + opnd_create_reg(DR_REG_H4), + opnd_create_reg(DR_REG_H15)); + test_instr_encoding(dc, OP_frintn, instr); + + instr = INSTR_CREATE_frintp_scalar(dc, + opnd_create_reg(DR_REG_D23), + opnd_create_reg(DR_REG_D2)); + test_instr_encoding(dc, OP_frintp, instr); + + instr = INSTR_CREATE_frintp_scalar(dc, + opnd_create_reg(DR_REG_S23), + opnd_create_reg(DR_REG_S2)); + test_instr_encoding(dc, OP_frintp, instr); + + instr = INSTR_CREATE_frintp_scalar(dc, + opnd_create_reg(DR_REG_H23), + opnd_create_reg(DR_REG_H2)); + test_instr_encoding(dc, OP_frintp, instr); + + instr = INSTR_CREATE_frintm_scalar(dc, + opnd_create_reg(DR_REG_D26), + opnd_create_reg(DR_REG_D8)); + test_instr_encoding(dc, OP_frintm, instr); + + instr = INSTR_CREATE_frintm_scalar(dc, + opnd_create_reg(DR_REG_S26), + opnd_create_reg(DR_REG_S8)); + test_instr_encoding(dc, OP_frintm, instr); + + instr = INSTR_CREATE_frintm_scalar(dc, + opnd_create_reg(DR_REG_H26), + opnd_create_reg(DR_REG_H8)); + test_instr_encoding(dc, OP_frintm, instr); + + instr = INSTR_CREATE_frintz_scalar(dc, + opnd_create_reg(DR_REG_D22), + opnd_create_reg(DR_REG_D24)); + test_instr_encoding(dc, OP_frintz, instr); + + instr = INSTR_CREATE_frintz_scalar(dc, + opnd_create_reg(DR_REG_S22), + opnd_create_reg(DR_REG_S24)); + test_instr_encoding(dc, OP_frintz, instr); + + instr = INSTR_CREATE_frintz_scalar(dc, + opnd_create_reg(DR_REG_H22), + opnd_create_reg(DR_REG_H24)); + test_instr_encoding(dc, OP_frintz, instr); + + instr = INSTR_CREATE_frinta_scalar(dc, + opnd_create_reg(DR_REG_D26), + opnd_create_reg(DR_REG_D18)); + test_instr_encoding(dc, OP_frinta, instr); + + instr = INSTR_CREATE_frinta_scalar(dc, + opnd_create_reg(DR_REG_S26), + opnd_create_reg(DR_REG_S18)); + test_instr_encoding(dc, OP_frinta, instr); + + instr = INSTR_CREATE_frinta_scalar(dc, + opnd_create_reg(DR_REG_H26), + opnd_create_reg(DR_REG_H18)); + test_instr_encoding(dc, OP_frinta, instr); + + instr = INSTR_CREATE_frintx_scalar(dc, + opnd_create_reg(DR_REG_D16), + opnd_create_reg(DR_REG_D29)); + test_instr_encoding(dc, OP_frintx, instr); + + instr = INSTR_CREATE_frintx_scalar(dc, + opnd_create_reg(DR_REG_S16), + opnd_create_reg(DR_REG_S29)); + test_instr_encoding(dc, OP_frintx, instr); + + instr = INSTR_CREATE_frintx_scalar(dc, + opnd_create_reg(DR_REG_H16), + opnd_create_reg(DR_REG_H29)); + test_instr_encoding(dc, OP_frintx, instr); + + instr = INSTR_CREATE_frinti_scalar(dc, + opnd_create_reg(DR_REG_D11), + opnd_create_reg(DR_REG_D19)); + test_instr_encoding(dc, OP_frinti, instr); + + instr = INSTR_CREATE_frinti_scalar(dc, + opnd_create_reg(DR_REG_S11), + opnd_create_reg(DR_REG_S19)); + test_instr_encoding(dc, OP_frinti, instr); + + instr = INSTR_CREATE_frinti_scalar(dc, + opnd_create_reg(DR_REG_H11), + opnd_create_reg(DR_REG_H19)); + test_instr_encoding(dc, OP_frinti, instr); + + instr = INSTR_CREATE_fcvt_scalar(dc, + opnd_create_reg(DR_REG_S23), + opnd_create_reg(DR_REG_D8)); + test_instr_encoding(dc, OP_fcvt, instr); + + instr = INSTR_CREATE_fcvt_scalar(dc, + opnd_create_reg(DR_REG_H29), + opnd_create_reg(DR_REG_D15)); + test_instr_encoding(dc, OP_fcvt, instr); + + instr = INSTR_CREATE_fcvt_scalar(dc, + opnd_create_reg(DR_REG_S28), + opnd_create_reg(DR_REG_H24)); + test_instr_encoding(dc, OP_fcvt, instr); + + instr = INSTR_CREATE_fcvt_scalar(dc, + opnd_create_reg(DR_REG_D2), + opnd_create_reg(DR_REG_H0)); + test_instr_encoding(dc, OP_fcvt, instr); +} int main(int argc, char *argv[]) @@ -3346,6 +3548,9 @@ main(int argc, char *argv[]) test_asimdsame(dcontext); print("test_asimdsame complete\n"); + test_floatdp1(dcontext); + print("test_floatdp1 complete\n"); + print("All tests complete\n"); return 0; } diff --git a/suite/tests/api/ir_aarch64.expect b/suite/tests/api/ir_aarch64.expect index 234a7ef83fe..a03d62569f3 100644 --- a/suite/tests/api/ir_aarch64.expect +++ b/suite/tests/api/ir_aarch64.expect @@ -481,4 +481,44 @@ bit %q21 %q12 -> %q12 bif %d3 %d3 -> %d20 bif %q3 %q3 -> %q20 test_asimdsame complete +fmov %d27 -> %d2 +fmov %s27 -> %s2 +fmov %h27 -> %h2 +fabs %d0 -> %d30 +fabs %s0 -> %s30 +fabs %h0 -> %h30 +fneg %d29 -> %d13 +fneg %s29 -> %s13 +fneg %h29 -> %h13 +fsqrt %d17 -> %d31 +fsqrt %s17 -> %s31 +fsqrt %h17 -> %h31 +fcvt %s2 -> %d10 +fcvt %s20 -> %h31 +frintn %d15 -> %d4 +frintn %s15 -> %s4 +frintn %h15 -> %h4 +frintp %d2 -> %d23 +frintp %s2 -> %s23 +frintp %h2 -> %h23 +frintm %d8 -> %d26 +frintm %s8 -> %s26 +frintm %h8 -> %h26 +frintz %d24 -> %d22 +frintz %s24 -> %s22 +frintz %h24 -> %h22 +frinta %d18 -> %d26 +frinta %s18 -> %s26 +frinta %h18 -> %h26 +frintx %d29 -> %d16 +frintx %s29 -> %s16 +frintx %h29 -> %h16 +frinti %d19 -> %d11 +frinti %s19 -> %s11 +frinti %h19 -> %h11 +fcvt %d8 -> %s23 +fcvt %d15 -> %h29 +fcvt %h24 -> %s28 +fcvt %h0 -> %d2 +test_floatdp1 complete All tests complete