[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Tinycc-devel] [PATCH 14/16] arm-asm: Add and, eor, sub, rsb, add, adc,
From: |
Danny Milosavljevic |
Subject: |
[Tinycc-devel] [PATCH 14/16] arm-asm: Add and, eor, sub, rsb, add, adc, sbc, rsc, tst, teq, cmp, cmn, orr, mov, bic, mvn |
Date: |
Sat, 26 Dec 2020 22:58:15 +0100 |
---
arm-asm.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
arm-tok.h | 35 ++++++++++++
2 files changed, 200 insertions(+)
diff --git a/arm-asm.c b/arm-asm.c
index 9e9fb93..58853f6 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -347,6 +347,137 @@ static void asm_block_data_transfer_opcode(TCCState *s1,
int token)
}
}
+static void asm_data_processing_opcode(TCCState *s1, int token)
+{
+ Operand ops[3];
+ int nb_ops;
+
+ /* 16 entries per instruction for the different condition codes */
+ uint32_t opcode_idx = (ARM_INSTRUCTION_GROUP(token) - TOK_ASM_andeq) >> 4;
+
+ 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) {
+ 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_ops != 3) {
+ expect("two or three operands");
+ return;
+ } else {
+ uint32_t opcode = 0;
+ uint32_t operands = 0;
+
+ // data processing (general case):
+ // operands:
+ // Rn: bits 19...16 (first operand)
+ // Rd: bits 15...12 (destination)
+ // Operand2: bits 11...0 (second operand); depending on I that's
either a register or an immediate
+ // operator:
+ // bits 24...21: "OpCode"--see below
+
+ /* operations in the token list are ordered by opcode */
+ opcode = (opcode_idx >> 1) << 21; // drop "s"
+ if (ops[0].type != OP_REG32)
+ expect("(destination operand) register");
+ else if (opcode == 0xa << 21 || opcode == 0xb << 21 || opcode == 0x8
<< 21 || opcode == 0x9 << 21 ) // cmp, cmn, tst, teq
+ operands |= ENCODE_SET_CONDITION_CODES; // force S set, otherwise
it's a completely different instruction.
+ else
+ operands |= ENCODE_RD(ops[0].reg);
+ if (ops[1].type != OP_REG32)
+ expect("(first source operand) register");
+ else if (!(opcode == 0xd << 21 || opcode == 0xf << 21)) // not: mov,
mvn (those have only one source operand)
+ operands |= ENCODE_RN(ops[1].reg);
+ switch (ops[2].type) {
+ case OP_REG32:
+ // TODO: Parse and encode shift.
+ operands |= ops[2].reg;
+ break;
+ case OP_IM8:
+ // TODO: Parse and encode rotation.
+ operands |= ENCODE_IMMEDIATE_FLAG;
+ operands |= ops[2].e.v;
+ break;
+ case OP_IM8N: // immediate negative value
+ // TODO: Parse and encode rotation.
+ operands |= ENCODE_IMMEDIATE_FLAG;
+ /* Instruction swapping:
+ 0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
+ 0011 = RSB - Rd:= Op2 - Op1 -> difficult
+ 0111 = RSC - Rd:= Op2 - Op1 + C -> difficult
+ 1000 = TST - CC on: Op1 AND Op2 -> difficult
+ 1001 = TEQ - CC on: Op1 EOR Op2 -> difficult
+ 1100 = ORR - Rd:= Op1 OR Op2 -> difficult
+ */
+ switch (opcode_idx >> 1) { // "OpCode" in ARM docs
+#if 1
+ case 0x0: // AND - Rd:= Op1 AND Op2
+ opcode = 0xe << 21; // BIC
+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+ break;
+ case 0x2: // SUB - Rd:= Op1 - Op2
+ opcode = 0x4 << 21; // ADD
+ operands |= (-ops[2].e.v) & 0xFF;
+ break;
+ case 0x4: // ADD - Rd:= Op1 + Op2
+ opcode = 0x2 << 21; // SUB
+ operands |= (-ops[2].e.v) & 0xFF;
+ break;
+ case 0x5: // ADC - Rd:= Op1 + Op2 + C
+ opcode = 0x6 << 21; // SBC
+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+ break;
+ case 0x6: // SBC - Rd:= Op1 - Op2 + C
+ opcode = 0x5 << 21; // ADC
+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+ break;
+#endif
+ case 0xa: // CMP - CC on: Op1 - Op2
+ opcode = 0xb << 21; // CMN
+ operands |= (-ops[2].e.v) & 0xFF;
+ break;
+ case 0xb: // CMN - CC on: Op1 + Op2
+ opcode = 0xa << 21; // CMP
+ operands |= (-ops[2].e.v) & 0xFF;
+ break;
+ // moveq r1, r3: 0x01a01003; mov Rd, Op2
+ case 0xd: // MOV - Rd:= Op2
+ opcode = 0xf << 21; // MVN
+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+ break;
+#if 1
+ case 0xe: // BIC - Rd:= Op1 AND NOT Op2
+ opcode = 0x0 << 21; // AND
+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+ break;
+#endif
+ case 0xf: // MVN - Rd:= NOT Op2
+ opcode = 0xd << 21; // MOV
+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+ break;
+ default:
+ tcc_error("cannot use '%s' with a negative immediate value",
get_tok_str(token, NULL));
+ }
+ break;
+ default:
+ expect("(second source operand) register or immediate value");
+ }
+
+ /* S=0 and S=1 entries alternate one after another, in that order */
+ opcode |= (opcode_idx & 1) ? ENCODE_SET_CONDITION_CODES : 0;
+ asm_emit_opcode(token, opcode | operands);
+ }
+}
+
static void asm_multiplication_opcode(TCCState *s1, int token)
{
Operand ops[4];
@@ -669,6 +800,40 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
case TOK_ASM_strbeq:
return asm_single_data_transfer_opcode(s1, token);
+ case TOK_ASM_andeq:
+ case TOK_ASM_eoreq:
+ case TOK_ASM_subeq:
+ case TOK_ASM_rsbeq:
+ case TOK_ASM_addeq:
+ case TOK_ASM_adceq:
+ case TOK_ASM_sbceq:
+ case TOK_ASM_rsceq:
+ case TOK_ASM_tsteq:
+ case TOK_ASM_teqeq:
+ case TOK_ASM_cmpeq:
+ case TOK_ASM_cmneq:
+ case TOK_ASM_orreq:
+ case TOK_ASM_moveq:
+ case TOK_ASM_biceq:
+ case TOK_ASM_mvneq:
+ case TOK_ASM_andseq:
+ case TOK_ASM_eorseq:
+ case TOK_ASM_subseq:
+ case TOK_ASM_rsbseq:
+ case TOK_ASM_addseq:
+ case TOK_ASM_adcseq:
+ case TOK_ASM_sbcseq:
+ case TOK_ASM_rscseq:
+// case TOK_ASM_tstseq:
+// case TOK_ASM_teqseq:
+// case TOK_ASM_cmpseq:
+// case TOK_ASM_cmnseq:
+ case TOK_ASM_orrseq:
+ case TOK_ASM_movseq:
+ case TOK_ASM_bicseq:
+ case TOK_ASM_mvnseq:
+ return asm_data_processing_opcode(s1, token);
+
case TOK_ASM_muleq:
case TOK_ASM_mulseq:
case TOK_ASM_mlaeq:
diff --git a/arm-tok.h b/arm-tok.h
index a2a2f70..023b01a 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -103,3 +103,38 @@
DEF_ASM_CONDED(push)
DEF_ASM_CONDED(pop)
+
+ /* data processing instructions; order is important */
+
+ DEF_ASM_CONDED(and)
+ DEF_ASM_CONDED(ands)
+ DEF_ASM_CONDED(eor)
+ DEF_ASM_CONDED(eors)
+ DEF_ASM_CONDED(sub)
+ DEF_ASM_CONDED(subs)
+ DEF_ASM_CONDED(rsb)
+ DEF_ASM_CONDED(rsbs)
+ DEF_ASM_CONDED(add)
+ DEF_ASM_CONDED(adds)
+ DEF_ASM_CONDED(adc)
+ DEF_ASM_CONDED(adcs)
+ DEF_ASM_CONDED(sbc)
+ DEF_ASM_CONDED(sbcs)
+ DEF_ASM_CONDED(rsc)
+ DEF_ASM_CONDED(rscs)
+ DEF_ASM_CONDED(tst)
+ DEF_ASM_CONDED(tsts) // necessary here--but not useful to the user
+ DEF_ASM_CONDED(teq)
+ DEF_ASM_CONDED(teqs) // necessary here--but not useful to the user
+ DEF_ASM_CONDED(cmp)
+ DEF_ASM_CONDED(cmps) // necessary here--but not useful to the user
+ DEF_ASM_CONDED(cmn)
+ DEF_ASM_CONDED(cmns) // necessary here--but not useful to the user
+ DEF_ASM_CONDED(orr)
+ DEF_ASM_CONDED(orrs)
+ DEF_ASM_CONDED(mov)
+ DEF_ASM_CONDED(movs)
+ DEF_ASM_CONDED(bic)
+ DEF_ASM_CONDED(bics)
+ DEF_ASM_CONDED(mvn)
+ DEF_ASM_CONDED(mvns)
- [Tinycc-devel] [PATCH 08/16] arm-asm: Add push, pop, (continued)
- [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, 2020/12/26
- [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 <=
- 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