[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Tinycc-devel] [PATCH 11/16] arm-asm: Add mul, mla, smull, umull, smlal,
From: |
Danny Milosavljevic |
Subject: |
[Tinycc-devel] [PATCH 11/16] arm-asm: Add mul, mla, smull, umull, smlal, umlal |
Date: |
Sat, 26 Dec 2020 22:58:12 +0100 |
---
arm-asm.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
arm-tok.h | 15 +++++
2 files changed, 190 insertions(+)
diff --git a/arm-asm.c b/arm-asm.c
index c2598a8..792b914 100644
--- a/arm-asm.c
+++ b/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)
{
while (token == TOK_LINEFEED) {
@@ -315,6 +474,22 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
case TOK_ASM_uxtbeq:
case TOK_ASM_uxtheq:
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:
expect("known instruction");
}
diff --git a/arm-tok.h b/arm-tok.h
index 06cee7a..5106250 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -66,6 +66,21 @@
DEF_ASM_CONDED(uxtb)
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 */
DEF_ASM_CONDED(push)
- [Tinycc-devel] [PATCH 00/16] Add ARM inline assembler, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 03/16] arm-asm: Update copyright header, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 06/16] arm-asm: Add wfe, wfi, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 05/16] arm-asm: Add nop, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 08/16] arm-asm: Add push, pop, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 01/16] arm-asm: Publish g, gen_le16, gen_le32 in tcc.h, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 09/16] arm-asm: Add swi, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 07/16] arm-asm: Add parse_operand, Operand, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 10/16] arm-asm: Add clz, sxtb, sxth, uxtb, uxth, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 12/16] arm-asm: Add stmda, ldmda, stm, ldm, stmia, ldmia, stmdb, ldmdb, stmib, ldmib, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 11/16] arm-asm: Add mul, mla, smull, umull, smlal, umlal,
Danny Milosavljevic <=
- [Tinycc-devel] [PATCH 13/16] arm-asm: Add ldr, ldrb, str, strb, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 16/16] arm-asm: Optimize gen_le32, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 15/16] arm-asm: Add b, bl, bx, blx, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 14/16] arm-asm: Add and, eor, sub, rsb, add, adc, sbc, rsc, tst, teq, cmp, cmn, orr, mov, bic, mvn, Danny Milosavljevic, 2020/12/26
- Re: [Tinycc-devel] [PATCH 00/16] Add ARM inline assembler, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 02/16] arm-asm: Implement asm_parse_regvar and asm_clobber, Danny Milosavljevic, 2020/12/26
- [Tinycc-devel] [PATCH 04/16] arm-asm: Remove asm_error, Danny Milosavljevic, 2020/12/26
- Re: [Tinycc-devel] [PATCH 00/16] Add ARM inline assembler, Jan Nieuwenhuizen, 2020/12/27
- Re: [Tinycc-devel] [PATCH 00/16] Add ARM inline assembler, Michael Matz, 2020/12/27
- Prev by Date:
[Tinycc-devel] [PATCH 12/16] arm-asm: Add stmda, ldmda, stm, ldm, stmia, ldmia, stmdb, ldmdb, stmib, ldmib
- Next by Date:
[Tinycc-devel] [PATCH 13/16] arm-asm: Add ldr, ldrb, str, strb
- Previous by thread:
[Tinycc-devel] [PATCH 12/16] arm-asm: Add stmda, ldmda, stm, ldm, stmia, ldmia, stmdb, ldmdb, stmib, ldmib
- Next by thread:
[Tinycc-devel] [PATCH 13/16] arm-asm: Add ldr, ldrb, str, strb
- Index(es):