diff --git a/arm-asm.c b/arm-asm.c index 95d02e6d..314ce5c1 100644 --- a/arm-asm.c +++ b/arm-asm.c @@ -1902,6 +1902,127 @@ static void asm_floating_point_reg_arm_reg_transfer_opcode_tail(TCCState *s1, in } } +static void asm_floating_point_vcvt_data_processing_opcode(TCCState *s1, int token) { + uint8_t coprocessor = 0; + Operand ops[3]; + uint8_t opcode1 = 11; + uint8_t opcode2 = 2; + + switch (ARM_INSTRUCTION_GROUP(token)) { + case TOK_ASM_vcvtreq_s32_f64: + case TOK_ASM_vcvtreq_u32_f64: + case TOK_ASM_vcvteq_s32_f64: + case TOK_ASM_vcvteq_u32_f64: + case TOK_ASM_vcvteq_f64_s32: + case TOK_ASM_vcvteq_f64_u32: + case TOK_ASM_vcvteq_f32_f64: + coprocessor = CP_DOUBLE_PRECISION_FLOAT; + break; + case TOK_ASM_vcvtreq_s32_f32: + case TOK_ASM_vcvtreq_u32_f32: + case TOK_ASM_vcvteq_s32_f32: + case TOK_ASM_vcvteq_u32_f32: + case TOK_ASM_vcvteq_f32_s32: + case TOK_ASM_vcvteq_f32_u32: + case TOK_ASM_vcvteq_f64_f32: + coprocessor = CP_SINGLE_PRECISION_FLOAT; + break; + default: + tcc_error("Unknown coprocessor for instruction '%s'", get_tok_str(token, NULL)); + return; + } + + parse_operand(s1, &ops[0]); + ops[1].type = OP_IM8; + ops[1].e.v = 8; + /* floating-point -> integer */ + switch (ARM_INSTRUCTION_GROUP(token)) { + case TOK_ASM_vcvtreq_s32_f32: + case TOK_ASM_vcvtreq_s32_f64: + case TOK_ASM_vcvteq_s32_f32: + case TOK_ASM_vcvteq_s32_f64: + ops[1].e.v |= 1; // signed + /* fall through */ + case TOK_ASM_vcvteq_u32_f32: + case TOK_ASM_vcvteq_u32_f64: + case TOK_ASM_vcvtreq_u32_f32: + case TOK_ASM_vcvtreq_u32_f64: + ops[1].e.v |= 4; // to_integer (opc2) + break; + /* floating-point size conversion */ + case TOK_ASM_vcvteq_f64_f32: + case TOK_ASM_vcvteq_f32_f64: + ops[1].e.v = 7; + break; + } + + if (tok == ',') + next(); + else + expect("','"); + parse_operand(s1, &ops[2]); + + switch (ARM_INSTRUCTION_GROUP(token)) { + /* floating-point -> integer */ + case TOK_ASM_vcvteq_s32_f32: + case TOK_ASM_vcvteq_s32_f64: + case TOK_ASM_vcvteq_u32_f32: + case TOK_ASM_vcvteq_u32_f64: + opcode2 |= 4; // round_zero + break; + + /* integer -> floating-point */ + case TOK_ASM_vcvteq_f64_s32: + case TOK_ASM_vcvteq_f32_s32: + opcode2 |= 4; // signed--special + break; + + /* floating-point size conversion */ + case TOK_ASM_vcvteq_f64_f32: + case TOK_ASM_vcvteq_f32_f64: + opcode2 |= 4; // always set + break; + } + + switch (ARM_INSTRUCTION_GROUP(token)) { + case TOK_ASM_vcvteq_f64_u32: + case TOK_ASM_vcvteq_f64_s32: + case TOK_ASM_vcvteq_f64_f32: + if (ops[0].type == OP_VREG64 && ops[2].type == OP_VREG32) { + } else { + expect("d, s"); + return; + } + break; + default: + if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { + if (ops[0].type == OP_VREG32 && ops[2].type == OP_VREG32) { + } else { + expect("s, s"); + return; + } + } else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) { + if (ops[0].type == OP_VREG32 && ops[2].type == OP_VREG64) { + } else { + expect("s, d"); + return; + } + } + } + + if (ops[2].type == OP_VREG32) { + if (ops[2].reg & 1) + opcode2 |= 1; + ops[2].reg >>= 1; + } + if (ops[0].type == OP_VREG32) { + if (ops[0].reg & 1) + opcode1 |= 4; + ops[0].reg >>= 1; + } + asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, ops[0].reg, (ops[1].type == OP_IM8) ? ops[1].e.v : ops[1].reg, (ops[2].type == OP_IM8) ? ops[2].e.v : ops[2].reg, opcode2, 0); +} + static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT; uint8_t opcode1 = 0; @@ -1920,8 +2041,6 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { VFMA 1?10 ?0? Must be unconditional VFMS 1?10 ?1? Must be unconditional - VCVT* - VMOV Fd, Fm VMOV Sn, Sm, Rd, Rn VMOV Rd, Rn, Sn, Sm @@ -2092,7 +2211,6 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { ops[1].e.v = 0; } break; - // TODO: vcvt; vcvtr default: expect("known floating point instruction"); return; @@ -2580,6 +2698,23 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) asm_floating_point_data_processing_opcode(s1, token); return; + case TOK_ASM_vcvtreq_s32_f32: + case TOK_ASM_vcvtreq_s32_f64: + case TOK_ASM_vcvteq_s32_f32: + case TOK_ASM_vcvteq_s32_f64: + case TOK_ASM_vcvtreq_u32_f32: + case TOK_ASM_vcvtreq_u32_f64: + case TOK_ASM_vcvteq_u32_f32: + case TOK_ASM_vcvteq_u32_f64: + case TOK_ASM_vcvteq_f64_s32: + case TOK_ASM_vcvteq_f32_s32: + case TOK_ASM_vcvteq_f64_u32: + case TOK_ASM_vcvteq_f32_u32: + case TOK_ASM_vcvteq_f64_f32: + case TOK_ASM_vcvteq_f32_f64: + asm_floating_point_vcvt_data_processing_opcode(s1, token); + return; + case TOK_ASM_vpusheq: case TOK_ASM_vpopeq: case TOK_ASM_vldmeq: diff --git a/arm-tok.h b/arm-tok.h index 2ee79ca7..297b1055 100644 --- a/arm-tok.h +++ b/arm-tok.h @@ -186,6 +186,24 @@ DEF_ASM_CONDED_WITH_SUFFIX(x, f32) \ DEF_ASM_CONDED_WITH_SUFFIX(x, f64) +#define DEF_ASM_CONDED_WITH_TWO_SUFFIXES(x, y, z) \ + DEF(TOK_ASM_ ## x ## eq ## _ ## y ## _ ## z, #x "eq." #y "." #z) \ + DEF(TOK_ASM_ ## x ## ne ## _ ## y ## _ ## z, #x "ne." #y "." #z) \ + DEF(TOK_ASM_ ## x ## cs ## _ ## y ## _ ## z, #x "cs." #y "." #z) \ + DEF(TOK_ASM_ ## x ## cc ## _ ## y ## _ ## z, #x "cc." #y "." #z) \ + DEF(TOK_ASM_ ## x ## mi ## _ ## y ## _ ## z, #x "mi." #y "." #z) \ + DEF(TOK_ASM_ ## x ## pl ## _ ## y ## _ ## z, #x "pl." #y "." #z) \ + DEF(TOK_ASM_ ## x ## vs ## _ ## y ## _ ## z, #x "vs." #y "." #z) \ + DEF(TOK_ASM_ ## x ## vc ## _ ## y ## _ ## z, #x "vc." #y "." #z) \ + DEF(TOK_ASM_ ## x ## hi ## _ ## y ## _ ## z, #x "hi." #y "." #z) \ + DEF(TOK_ASM_ ## x ## ls ## _ ## y ## _ ## z, #x "ls." #y "." #z) \ + DEF(TOK_ASM_ ## x ## ge ## _ ## y ## _ ## z, #x "ge." #y "." #z) \ + DEF(TOK_ASM_ ## x ## lt ## _ ## y ## _ ## z, #x "lt." #y "." #z) \ + DEF(TOK_ASM_ ## x ## gt ## _ ## y ## _ ## z, #x "gt." #y "." #z) \ + DEF(TOK_ASM_ ## x ## le ## _ ## y ## _ ## z, #x "le." #y "." #z) \ + DEF(TOK_ASM_ ## x ## _ ## y ## _ ## z, #x "." #y "." #z) \ + DEF(TOK_ASM_ ## x ## rsvd ## _ ## y ## _ ## z, #x "rsvd." #y "." #z) + /* Note: add new tokens after nop (MUST always use DEF_ASM_CONDED) */ DEF_ASM_CONDED(nop) @@ -335,6 +353,24 @@ DEF_ASM_CONDED_VFP_F32_F64(vcmpe) DEF_ASM_CONDED_VFP_F32_F64(vmov) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvtr, s32, f64) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvtr, s32, f32) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvtr, u32, f64) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvtr, u32, f32) + + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, s32, f64) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, s32, f32) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, u32, f64) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, u32, f32) + + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f64, s32) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f32, s32) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f64, u32) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f32, u32) + + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f64, f32) + DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f32, f64) + DEF_ASM_CONDED(vpush) DEF_ASM_CONDED(vpop) DEF_ASM_CONDED(vldm) diff --git a/tests/arm-asm-testsuite.sh b/tests/arm-asm-testsuite.sh index bfa1e108..61c5dadb 100755 --- a/tests/arm-asm-testsuite.sh +++ b/tests/arm-asm-testsuite.sh @@ -13,7 +13,7 @@ cat ../arm-tok.h | \ grep -v 'DEF_ASM_CONDED_WITH_SUFFIX(x' | \ sed -e 's;^[ ]*DEF_ASM_CONDED_VFP_F32_F64[^(]*(\(.*\)).*$; DEF_ASM_CONDED(\1.f32)\ DEF_ASM_CONDED(\1.f64);g' | \ - sed -e 's;^[ ]*DEF_ASM[^(]*(\(.*\)).*$;\1;g' | \ + sed -e 's;^[ ]*DEF_ASM[^(]*(\(.*\)).*$;\1;g' -e 's;, ;.;g' | \ egrep -v '^((r|c|p|s|d)[0-9]+|fp|ip|sp|lr|pc|asl|apsr_nzcv|fpsid|fpscr|fpexc)$' | while read s do as_opts="" @@ -162,6 +162,8 @@ do "fpexc, r2" \ "fpscr, r2" \ "fpsid, r2" \ + "s3, d4" \ + "d4, s3" \ "" do #echo ".syntax unified" > a.s