arm-asm: Add mul, mla, smull, umull, smlal, umlal
This commit is contained in:
parent
c4e13c1ef9
commit
82663d33bb
2 changed files with 190 additions and 0 deletions
175
arm-asm.c
175
arm-asm.c
|
@ -286,6 +286,165 @@ static void asm_block_data_transfer_opcode(TCCState *s1, int token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void asm_multiplication_opcode(TCCState *s1, int token)
|
||||||
|
{
|
||||||
|
Operand ops[4];
|
||||||
|
int nb_ops = 0;
|
||||||
|
uint32_t opcode = 0x90;
|
||||||
|
|
||||||
|
for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
|
||||||
|
parse_operand(s1, &ops[nb_ops]);
|
||||||
|
if (tok != ',') {
|
||||||
|
++nb_ops;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next(); // skip ','
|
||||||
|
}
|
||||||
|
if (nb_ops < 2)
|
||||||
|
expect("at least two operands");
|
||||||
|
else if (nb_ops == 2) {
|
||||||
|
switch (ARM_INSTRUCTION_GROUP(token)) {
|
||||||
|
case TOK_ASM_mulseq:
|
||||||
|
case TOK_ASM_muleq:
|
||||||
|
memcpy(&ops[2], &ops[0], sizeof(ops[1])); // ARM is actually like this!
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiply (special case):
|
||||||
|
// operands:
|
||||||
|
// Rd: bits 19...16
|
||||||
|
// Rm: bits 3...0
|
||||||
|
// Rs: bits 11...8
|
||||||
|
// Rn: bits 15...12
|
||||||
|
|
||||||
|
if (ops[0].type == OP_REG32)
|
||||||
|
opcode |= ops[0].reg << 16;
|
||||||
|
else
|
||||||
|
expect("(destination operand) register");
|
||||||
|
if (ops[1].type == OP_REG32)
|
||||||
|
opcode |= ops[1].reg;
|
||||||
|
else
|
||||||
|
expect("(first source operand) register");
|
||||||
|
if (ops[2].type == OP_REG32)
|
||||||
|
opcode |= ops[2].reg << 8;
|
||||||
|
else
|
||||||
|
expect("(second source operand) register");
|
||||||
|
if (nb_ops > 3) {
|
||||||
|
if (ops[3].type == OP_REG32)
|
||||||
|
opcode |= ops[3].reg << 12;
|
||||||
|
else
|
||||||
|
expect("(third source operand) register");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ARM_INSTRUCTION_GROUP(token)) {
|
||||||
|
case TOK_ASM_mulseq:
|
||||||
|
opcode |= 1 << 20; // Status
|
||||||
|
/* fallthrough */
|
||||||
|
case TOK_ASM_muleq:
|
||||||
|
if (nb_ops != 3)
|
||||||
|
expect("three operands");
|
||||||
|
else {
|
||||||
|
asm_emit_opcode(token, opcode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TOK_ASM_mlaseq:
|
||||||
|
opcode |= 1 << 20; // Status
|
||||||
|
/* fallthrough */
|
||||||
|
case TOK_ASM_mlaeq:
|
||||||
|
if (nb_ops != 4)
|
||||||
|
expect("four operands");
|
||||||
|
else {
|
||||||
|
opcode |= 1 << 21; // Accumulate
|
||||||
|
asm_emit_opcode(token, opcode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
expect("known multiplication instruction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_long_multiplication_opcode(TCCState *s1, int token)
|
||||||
|
{
|
||||||
|
Operand ops[4];
|
||||||
|
int nb_ops = 0;
|
||||||
|
uint32_t opcode = 0x90 | (1 << 23);
|
||||||
|
|
||||||
|
for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
|
||||||
|
parse_operand(s1, &ops[nb_ops]);
|
||||||
|
if (tok != ',') {
|
||||||
|
++nb_ops;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next(); // skip ','
|
||||||
|
}
|
||||||
|
if (nb_ops != 4) {
|
||||||
|
expect("four operands");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// long multiply (special case):
|
||||||
|
// operands:
|
||||||
|
// RdLo: bits 15...12
|
||||||
|
// RdHi: bits 19...16
|
||||||
|
// Rs: bits 11...8
|
||||||
|
// Rm: bits 3...0
|
||||||
|
|
||||||
|
if (ops[0].type == OP_REG32)
|
||||||
|
opcode |= ops[0].reg << 12;
|
||||||
|
else
|
||||||
|
expect("(destination lo accumulator) register");
|
||||||
|
if (ops[1].type == OP_REG32)
|
||||||
|
opcode |= ops[1].reg << 16;
|
||||||
|
else
|
||||||
|
expect("(destination hi accumulator) register");
|
||||||
|
if (ops[2].type == OP_REG32)
|
||||||
|
opcode |= ops[2].reg;
|
||||||
|
else
|
||||||
|
expect("(first source operand) register");
|
||||||
|
if (ops[3].type == OP_REG32)
|
||||||
|
opcode |= ops[3].reg << 8;
|
||||||
|
else
|
||||||
|
expect("(second source operand) register");
|
||||||
|
|
||||||
|
switch (ARM_INSTRUCTION_GROUP(token)) {
|
||||||
|
case TOK_ASM_smullseq:
|
||||||
|
opcode |= 1 << 20; // Status
|
||||||
|
/* fallthrough */
|
||||||
|
case TOK_ASM_smulleq:
|
||||||
|
opcode |= 1 << 22; // signed
|
||||||
|
asm_emit_opcode(token, opcode);
|
||||||
|
break;
|
||||||
|
case TOK_ASM_umullseq:
|
||||||
|
opcode |= 1 << 20; // Status
|
||||||
|
/* fallthrough */
|
||||||
|
case TOK_ASM_umulleq:
|
||||||
|
asm_emit_opcode(token, opcode);
|
||||||
|
break;
|
||||||
|
case TOK_ASM_smlalseq:
|
||||||
|
opcode |= 1 << 20; // Status
|
||||||
|
/* fallthrough */
|
||||||
|
case TOK_ASM_smlaleq:
|
||||||
|
opcode |= 1 << 22; // signed
|
||||||
|
opcode |= 1 << 21; // Accumulate
|
||||||
|
asm_emit_opcode(token, opcode);
|
||||||
|
break;
|
||||||
|
case TOK_ASM_umlalseq:
|
||||||
|
opcode |= 1 << 20; // Status
|
||||||
|
/* fallthrough */
|
||||||
|
case TOK_ASM_umlaleq:
|
||||||
|
opcode |= 1 << 21; // Accumulate
|
||||||
|
asm_emit_opcode(token, opcode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
expect("known long multiplication instruction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ST_FUNC void asm_opcode(TCCState *s1, int token)
|
ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||||
{
|
{
|
||||||
while (token == TOK_LINEFEED) {
|
while (token == TOK_LINEFEED) {
|
||||||
|
@ -315,6 +474,22 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||||
case TOK_ASM_uxtbeq:
|
case TOK_ASM_uxtbeq:
|
||||||
case TOK_ASM_uxtheq:
|
case TOK_ASM_uxtheq:
|
||||||
return asm_binary_opcode(s1, token);
|
return asm_binary_opcode(s1, token);
|
||||||
|
|
||||||
|
case TOK_ASM_muleq:
|
||||||
|
case TOK_ASM_mulseq:
|
||||||
|
case TOK_ASM_mlaeq:
|
||||||
|
case TOK_ASM_mlaseq:
|
||||||
|
return asm_multiplication_opcode(s1, token);
|
||||||
|
|
||||||
|
case TOK_ASM_smulleq:
|
||||||
|
case TOK_ASM_smullseq:
|
||||||
|
case TOK_ASM_umulleq:
|
||||||
|
case TOK_ASM_umullseq:
|
||||||
|
case TOK_ASM_smlaleq:
|
||||||
|
case TOK_ASM_smlalseq:
|
||||||
|
case TOK_ASM_umlaleq:
|
||||||
|
case TOK_ASM_umlalseq:
|
||||||
|
return asm_long_multiplication_opcode(s1, token);
|
||||||
default:
|
default:
|
||||||
expect("known instruction");
|
expect("known instruction");
|
||||||
}
|
}
|
||||||
|
|
15
arm-tok.h
15
arm-tok.h
|
@ -66,6 +66,21 @@
|
||||||
DEF_ASM_CONDED(uxtb)
|
DEF_ASM_CONDED(uxtb)
|
||||||
DEF_ASM_CONDED(uxth)
|
DEF_ASM_CONDED(uxth)
|
||||||
|
|
||||||
|
/* multiplication */
|
||||||
|
|
||||||
|
DEF_ASM_CONDED(mul)
|
||||||
|
DEF_ASM_CONDED(muls)
|
||||||
|
DEF_ASM_CONDED(mla)
|
||||||
|
DEF_ASM_CONDED(mlas)
|
||||||
|
DEF_ASM_CONDED(smull)
|
||||||
|
DEF_ASM_CONDED(smulls)
|
||||||
|
DEF_ASM_CONDED(umull)
|
||||||
|
DEF_ASM_CONDED(umulls)
|
||||||
|
DEF_ASM_CONDED(smlal)
|
||||||
|
DEF_ASM_CONDED(smlals)
|
||||||
|
DEF_ASM_CONDED(umlal)
|
||||||
|
DEF_ASM_CONDED(umlals)
|
||||||
|
|
||||||
/* instruction macros */
|
/* instruction macros */
|
||||||
|
|
||||||
DEF_ASM_CONDED(push)
|
DEF_ASM_CONDED(push)
|
||||||
|
|
Loading…
Add table
Reference in a new issue