[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Tinycc-devel] [PATCH 1/9] arm-asm: Add lsl, lsr, asr, ror, rrx
From: |
Danny Milosavljevic |
Subject: |
[Tinycc-devel] [PATCH 1/9] arm-asm: Add lsl, lsr, asr, ror, rrx |
Date: |
Mon, 28 Dec 2020 02:44:05 +0100 |
---
arm-asm.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
arm-tok.h | 11 ++++
2 files changed, 173 insertions(+)
diff --git a/arm-asm.c b/arm-asm.c
index ce3ac80..6dc24c0 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -248,6 +248,14 @@ static void asm_binary_opcode(TCCState *s1, int token)
Note: For single data transfer instructions, "0" means immediate. */
#define ENCODE_IMMEDIATE_FLAG (1 << 25)
+#define ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER (1 << 4)
+#define ENCODE_BARREL_SHIFTER_MODE_LSL (0 << 5)
+#define ENCODE_BARREL_SHIFTER_MODE_LSR (1 << 5)
+#define ENCODE_BARREL_SHIFTER_MODE_ASR (2 << 5)
+#define ENCODE_BARREL_SHIFTER_MODE_ROR (3 << 5)
+#define ENCODE_BARREL_SHIFTER_REGISTER(register_index) ((register_index) << 8)
+#define ENCODE_BARREL_SHIFTER_IMMEDIATE(value) ((value) << 7)
+
static void asm_block_data_transfer_opcode(TCCState *s1, int token)
{
uint32_t opcode;
@@ -355,6 +363,52 @@ static void asm_block_data_transfer_opcode(TCCState *s1,
int token)
}
}
+static uint32_t asm_encode_rotation(Operand* rotation)
+{
+ uint64_t amount;
+ switch (rotation->type) {
+ case OP_REG32:
+ tcc_error("cannot rotate immediate value by register");
+ return 0;
+ case OP_IM8:
+ amount = rotation->e.v;
+ if (amount >= 0 && amount < 32 && (amount & 1) == 0)
+ return (amount >> 1) << 8;
+ else
+ tcc_error("rotating is only possible by a multiple of 2");
+ break;
+ default:
+ tcc_error("unknown rotation amount");
+ return 0;
+ }
+}
+
+static uint32_t asm_encode_shift(Operand* shift)
+{
+ uint64_t amount;
+ uint32_t operands = 0;
+ switch (shift->type) {
+ case OP_REG32:
+ if (shift->reg == 15)
+ tcc_error("r15 cannot be used as a shift count");
+ else {
+ operands = ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER;
+ operands |= ENCODE_BARREL_SHIFTER_REGISTER(shift->reg);
+ }
+ break;
+ case OP_IM8:
+ amount = shift->e.v;
+ if (amount > 0 && amount < 32)
+ operands = ENCODE_BARREL_SHIFTER_IMMEDIATE(amount);
+ else
+ tcc_error("shift count out of range");
+ break;
+ default:
+ tcc_error("unknown shift amount");
+ }
+ return operands;
+}
+
static void asm_data_processing_opcode(TCCState *s1, int token)
{
Operand ops[3];
@@ -486,6 +540,102 @@ static void asm_data_processing_opcode(TCCState *s1, int
token)
}
}
+static void asm_shift_opcode(TCCState *s1, int token)
+{
+ Operand ops[3];
+ int nb_ops;
+ uint32_t opcode = 0xd << 21; // MOV
+ uint32_t operands = 0;
+
+ 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");
+ return;
+ }
+
+ if (ops[0].type != OP_REG32)
+ expect("(destination operand) register");
+ else
+ operands |= ENCODE_RD(ops[0].reg);
+
+ if (nb_ops == 2) {
+ switch (ARM_INSTRUCTION_GROUP(token)) {
+ case TOK_ASM_rrxseq:
+ opcode |= ENCODE_SET_CONDITION_CODES;
+ /* fallthrough */
+ case TOK_ASM_rrxeq:
+ if (ops[1].type == OP_REG32) {
+ operands |= ops[1].reg;
+ operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
+ asm_emit_opcode(token, opcode | operands);
+ } else
+ tcc_error("(first source operand) register");
+ return;
+ 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;
+ }
+ }
+ if (nb_ops != 3) {
+ expect("two or three operands");
+ return;
+ }
+
+ switch (ops[1].type) {
+ case OP_REG32:
+ operands |= ops[1].reg;
+ break;
+ case OP_IM8:
+ operands |= ENCODE_IMMEDIATE_FLAG;
+ operands |= ops[1].e.v;
+ break;
+ }
+
+ if (operands & ENCODE_IMMEDIATE_FLAG)
+ operands |= asm_encode_rotation(&ops[2]);
+ else
+ operands |= asm_encode_shift(&ops[2]);
+
+ switch (ARM_INSTRUCTION_GROUP(token)) {
+ case TOK_ASM_lslseq:
+ opcode |= ENCODE_SET_CONDITION_CODES;
+ /* fallthrough */
+ case TOK_ASM_lsleq:
+ operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
+ break;
+ case TOK_ASM_lsrseq:
+ opcode |= ENCODE_SET_CONDITION_CODES;
+ /* fallthrough */
+ case TOK_ASM_lsreq:
+ operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
+ break;
+ case TOK_ASM_asrseq:
+ opcode |= ENCODE_SET_CONDITION_CODES;
+ /* fallthrough */
+ case TOK_ASM_asreq:
+ operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
+ break;
+ case TOK_ASM_rorseq:
+ opcode |= ENCODE_SET_CONDITION_CODES;
+ /* fallthrough */
+ case TOK_ASM_roreq:
+ operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
+ break;
+ default:
+ expect("shift instruction");
+ return;
+ }
+ asm_emit_opcode(token, opcode | operands);
+}
+
static void asm_multiplication_opcode(TCCState *s1, int token)
{
Operand ops[4];
@@ -902,6 +1052,18 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
case TOK_ASM_mvnseq:
return asm_data_processing_opcode(s1, token);
+ case TOK_ASM_lsleq:
+ case TOK_ASM_lslseq:
+ case TOK_ASM_lsreq:
+ case TOK_ASM_lsrseq:
+ case TOK_ASM_asreq:
+ case TOK_ASM_asrseq:
+ case TOK_ASM_roreq:
+ case TOK_ASM_rorseq:
+ case TOK_ASM_rrxseq:
+ case TOK_ASM_rrxeq:
+ return asm_shift_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 2f1798b..a1fb158 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -145,3 +145,14 @@
DEF_ASM_CONDED(bics)
DEF_ASM_CONDED(mvn)
DEF_ASM_CONDED(mvns)
+
+ DEF_ASM_CONDED(lsl)
+ DEF_ASM_CONDED(lsls)
+ DEF_ASM_CONDED(lsr)
+ DEF_ASM_CONDED(lsrs)
+ DEF_ASM_CONDED(asr)
+ DEF_ASM_CONDED(asrs)
+ DEF_ASM_CONDED(ror)
+ DEF_ASM_CONDED(rors)
+ DEF_ASM_CONDED(rrx)
+ DEF_ASM_CONDED(rrxs)
- [Tinycc-devel] [PATCH 0/9] Improve ARM inline assembler, Danny Milosavljevic, 2020/12/27
- [Tinycc-devel] [PATCH 4/9] arm-asm: Warn if regset registers are not specified in ascending order, Danny Milosavljevic, 2020/12/27
- [Tinycc-devel] [PATCH 2/9] arm-asm: For data processing instructions, support shifts and rotations., Danny Milosavljevic, 2020/12/27
- [Tinycc-devel] [PATCH 3/9] arm-asm: Support rotation for sxtb, sxth, uxtb, uxth, Danny Milosavljevic, 2020/12/27
- [Tinycc-devel] [PATCH 7/9] arm-asm: Print a warning if asm_binary_opcode is used with SP as operand, Danny Milosavljevic, 2020/12/27
- [Tinycc-devel] [PATCH 1/9] arm-asm: Add lsl, lsr, asr, ror, rrx,
Danny Milosavljevic <=
- [Tinycc-devel] [PATCH 5/9] arm-asm: Add error case in asm_multiplication_opcode, Danny Milosavljevic, 2020/12/27
- [Tinycc-devel] [PATCH 9/9] arm-asm: Raise error if asm_data_processing_opcode and asm_shift_opcode try to use PC for register-controlled shifts, Danny Milosavljevic, 2020/12/27
- [Tinycc-devel] [PATCH 6/9] arm-asm: Raise an error if asm_binary_opcode is used with PC as operand, Danny Milosavljevic, 2020/12/27
- [Tinycc-devel] [PATCH 8/9] arm-asm: Raise error if more than two operands are specified on mov, mvn, cmp, cmn, tst, teq, Danny Milosavljevic, 2020/12/27
- Re: [Tinycc-devel] [PATCH 0/9] Improve ARM inline assembler, Danny Milosavljevic, 2020/12/27