[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Tinycc-devel] [PATCH 3/4] arm-asm: Mostly factor out VFP register refer
From: |
Danny Milosavljevic |
Subject: |
[Tinycc-devel] [PATCH 3/4] arm-asm: Mostly factor out VFP register reference parsing to parse_operand |
Date: |
Sat, 23 Jan 2021 15:41:49 +0100 |
---
arm-asm.c | 159 +++++++++++++++++++++++++++---------------------------
1 file changed, 81 insertions(+), 78 deletions(-)
diff --git a/arm-asm.c b/arm-asm.c
index 5040d25..d064b8f 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -41,9 +41,13 @@ enum {
OPT_IM8,
OPT_IM8N,
OPT_IM32,
+ OPT_VREG32,
+ OPT_VREG64,
};
#define OP_REG32 (1 << OPT_REG32)
-#define OP_REG (OP_REG32)
+#define OP_VREG32 (1 << OPT_VREG32)
+#define OP_VREG64 (1 << OPT_VREG64)
+#define OP_REG (OP_REG32 | OP_VREG32 | OP_VREG64)
#define OP_IM32 (1 << OPT_IM32)
#define OP_IM8 (1 << OPT_IM8)
#define OP_IM8N (1 << OPT_IM8N)
@@ -58,6 +62,21 @@ typedef struct Operand {
};
} Operand;
+/* Read the VFP register referred to by T.
+ If OK, returns its number.
+ If not OK, returns -1. */
+static int asm_parse_vfp_regvar(int t, int double_precision)
+{
+ if (double_precision) {
+ if (t >= TOK_ASM_d0 && t <= TOK_ASM_d15)
+ return t - TOK_ASM_d0;
+ } else {
+ if (t >= TOK_ASM_s0 && t <= TOK_ASM_s31)
+ return t - TOK_ASM_s0;
+ }
+ return -1;
+}
+
/* Parse a text containing operand and store the result in OP */
static void parse_operand(TCCState *s1, Operand *op)
{
@@ -111,6 +130,14 @@ static void parse_operand(TCCState *s1, Operand *op)
next(); // skip register name
op->type = OP_REG32;
op->reg = (uint8_t) reg;
+ } else if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) {
+ next(); // skip register name
+ op->type = OP_VREG32;
+ op->reg = (uint8_t) reg;
+ } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) {
+ next(); // skip register name
+ op->type = OP_VREG64;
+ op->reg = (uint8_t) reg;
} else
expect("operand");
}
@@ -1448,41 +1475,25 @@ static void
asm_coprocessor_data_transfer_opcode(TCCState *s1, int token)
#define CP_SINGLE_PRECISION_FLOAT 10
#define CP_DOUBLE_PRECISION_FLOAT 11
-/* Read the VFP register referred to by T.
- If OK, returns its number.
- If not OK, returns -1. */
-static int asm_parse_vfp_regvar(int t, int double_precision)
-{
- if (double_precision) {
- if (t >= TOK_ASM_d0 && t <= TOK_ASM_d15)
- return t - TOK_ASM_d0;
- } else {
- if (t >= TOK_ASM_s0 && t <= TOK_ASM_s31)
- return t - TOK_ASM_s0;
- }
- return -1;
-}
-
static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int
token)
{
Operand ops[3];
uint8_t coprocessor = 0;
uint8_t coprocessor_destination_register = 0;
int long_transfer = 0;
- int reg;
// Note: vldr p1, c0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4
unchanged
// Note: Not allowed: vldr p2, c0, [r4, #4]! ; pre-indexed: r0 =
*(int*)(r4+4); r4 = r4+4
// Note: Not allowed: vldr p3, c0, [r4], #4 ; post-indexed: r0 =
*(int*)(r4+0); r4 = r4+4
- if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) {
+ parse_operand(s1, &ops[0]);
+ if (ops[0].type == OP_VREG32) {
coprocessor = CP_SINGLE_PRECISION_FLOAT;
- coprocessor_destination_register = reg;
+ coprocessor_destination_register = ops[0].reg;
long_transfer = coprocessor_destination_register & 1;
coprocessor_destination_register >>= 1;
- next();
- } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) {
+ } else if (ops[0].type == OP_VREG64) {
coprocessor = CP_DOUBLE_PRECISION_FLOAT;
- coprocessor_destination_register = reg;
+ coprocessor_destination_register = ops[0].reg;
next();
} else {
expect("floating point register");
@@ -1807,10 +1818,8 @@ static void
asm_floating_point_data_processing_opcode(TCCState *s1, int token) {
uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT;
uint8_t opcode1 = 0;
uint8_t opcode2 = 0; // (0 || 2) | register selection
- uint8_t operands[3];
- uint8_t nb_operands = 0;
- int operand_1_register = 1;
- int reg;
+ Operand ops[3];
+ uint8_t nb_ops = 0;
/* TODO:
Instruction opcode opcode2 Reason
@@ -1859,51 +1868,40 @@ static void
asm_floating_point_data_processing_opcode(TCCState *s1, int token) {
coprocessor = CP_DOUBLE_PRECISION_FLOAT;
}
- for (nb_operands = 0; nb_operands < 3; ) {
- if (nb_operands == 1 && (tok == '#' || tok == '$')) {
- asm_floating_point_immediate_data_processing_opcode_tail(s1,
token, coprocessor, operands[0]);
+ for (nb_ops = 0; nb_ops < 3; ) {
+ if (nb_ops == 1 && (tok == '#' || tok == '$')) {
+ asm_floating_point_immediate_data_processing_opcode_tail(s1,
token, coprocessor, ops[0].reg);
return;
}
- if (coprocessor == CP_SINGLE_PRECISION_FLOAT) {
- if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) {
- operands[nb_operands] = reg;
- next();
- } else {
+ parse_operand(s1, &ops[nb_ops]);
+ if (ops[nb_ops].type == OP_VREG32) {
+ if (coprocessor != CP_SINGLE_PRECISION_FLOAT) {
expect("'s<number>'");
return;
}
- } else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) {
- if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) {
- operands[nb_operands] = reg;
- next();
- } else {
+ } else if (ops[nb_ops].type == OP_VREG64) {
+ if (coprocessor != CP_DOUBLE_PRECISION_FLOAT) {
expect("'d<number>'");
return;
}
- } else if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) {
- coprocessor = CP_SINGLE_PRECISION_FLOAT;
- operands[nb_operands] = reg;
- next();
- } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) {
- coprocessor = CP_DOUBLE_PRECISION_FLOAT;
- operands[nb_operands] = reg;
- next();
- } else
- tcc_internal_error("unknown coprocessor");
- ++nb_operands;
+ } else {
+ expect("floating point register");
+ return;
+ }
+ ++nb_ops;
if (tok == ',')
next();
else
break;
}
- if (nb_operands == 2) { // implicit
- operands[2] = operands[1];
- operands[1] = operands[0];
- nb_operands = 3;
+ if (nb_ops == 2) { // implicit
+ memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
+ memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
+ nb_ops = 3;
}
- if (nb_operands < 3) {
- tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token,
NULL), nb_operands);
+ if (nb_ops < 3) {
+ tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token,
NULL), nb_ops);
return;
}
@@ -1957,43 +1955,44 @@ static void
asm_floating_point_data_processing_opcode(TCCState *s1, int token) {
case TOK_ASM_vnegeq_f64:
opcode1 = 11; // Other" instruction
opcode2 = 2;
- operands[1] = 1;
- operand_1_register = 0;
+ ops[1].type = OP_IM8;
+ ops[1].e.v = 1;
break;
case TOK_ASM_vabseq_f32:
case TOK_ASM_vabseq_f64:
opcode1 = 11; // "Other" instruction
opcode2 = 6;
- operands[1] = 0;
- operand_1_register = 0;
+ ops[1].type = OP_IM8;
+ ops[1].e.v = 0;
break;
case TOK_ASM_vsqrteq_f32:
case TOK_ASM_vsqrteq_f64:
opcode1 = 11; // "Other" instruction
opcode2 = 6;
- operands[1] = 1;
- operand_1_register = 0;
+ ops[1].type = OP_IM8;
+ ops[1].e.v = 1;
break;
case TOK_ASM_vcmpeq_f32:
case TOK_ASM_vcmpeq_f64:
opcode1 = 11; // "Other" instruction
opcode2 = 2;
- operands[1] = 4;
- operand_1_register = 0;
+ ops[1].type = OP_IM8;
+ ops[1].e.v = 4;
break;
case TOK_ASM_vcmpeeq_f32:
case TOK_ASM_vcmpeeq_f64:
opcode1 = 11; // "Other" instruction
opcode2 = 6;
- operands[1] = 4;
- operand_1_register = 0;
+ ops[1].type = OP_IM8;
+ ops[1].e.v = 4;
break;
case TOK_ASM_vmoveq_f32:
case TOK_ASM_vmoveq_f64:
+ // FIXME: Check for ARM registers--and allow only very little.
opcode1 = 11; // "Other" instruction
opcode2 = 2;
- operands[1] = 0;
- operand_1_register = 0;
+ ops[1].type = OP_IM8;
+ ops[1].e.v = 0;
break;
// TODO: vcvt; vcvtr
default:
@@ -2002,22 +2001,26 @@ static void
asm_floating_point_data_processing_opcode(TCCState *s1, int token) {
}
if (coprocessor == CP_SINGLE_PRECISION_FLOAT) {
- if (operands[2] & 1)
- opcode2 |= 1;
- operands[2] >>= 1;
+ if (ops[2].type == OP_VREG32) {
+ if (ops[2].reg & 1)
+ opcode2 |= 1;
+ ops[2].reg >>= 1;
+ }
- if (operand_1_register) {
- if (operands[1] & 1)
+ if (ops[1].type == OP_VREG32) {
+ if (ops[1].reg & 1)
opcode2 |= 4;
- operands[1] >>= 1;
+ ops[1].reg >>= 1;
}
- if (operands[0] & 1)
- opcode1 |= 4;
- operands[0] >>= 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, operands[0], operands[1], operands[2], opcode2, 0);
+ 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);
}
#endif
--
2.29.2
- [Tinycc-devel] [PATCH 0/4] Implement ARM VFP arithmetic instructions in ARM inline assembler, Danny Milosavljevic, 2021/01/23
- [Tinycc-devel] [PATCH 1/4] arm-asm: Add vmla, vmls, vnmls, vnmla, vmul, vnmul, vadd, vsub, vdiv, vneg, vabs, vsqrt, vcmp, vcmpe, Danny Milosavljevic, 2021/01/23
- [Tinycc-devel] [PATCH 2/4] arm-asm: Add vmov, Danny Milosavljevic, 2021/01/23
- [Tinycc-devel] [PATCH 3/4] arm-asm: Mostly factor out VFP register reference parsing to parse_operand,
Danny Milosavljevic <=
- [Tinycc-devel] [PATCH 4/4] arm-asm: Implement "vmov.f32 Sn, Rd", "vmov.f32 Rd, Sn", "vmov.f64 Dm, Rd, Rn", "vmov.f64 Rd, Rn, Dm", Danny Milosavljevic, 2021/01/23