[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Tinycc-devel] [PATCH] arm-asm: Implement ldr and str with shifted regis
From: |
Danny Milosavljevic |
Subject: |
[Tinycc-devel] [PATCH] arm-asm: Implement ldr and str with shifted register offset |
Date: |
Tue, 12 Jan 2021 15:59:29 +0100 |
Factor out asm_parse_optional_shift
---
arm-asm.c | 102 +++++++++++++++++++++++--------------
tests/arm-asm-testsuite.sh | 11 ++++
2 files changed, 76 insertions(+), 37 deletions(-)
diff --git a/arm-asm.c b/arm-asm.c
index e33422d..7a3d2e2 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -433,6 +433,50 @@ static void asm_block_data_transfer_opcode(TCCState *s1,
int token)
}
}
+/* Parses shift directive and returns the parts that would have to be set in
the opcode because of it.
+ Does not encode the actual shift amount.
+ It's not an error if there is no shift directive.
+
+ NB_SHIFT: will be set to 1 iff SHIFT is filled. Note that for rrx, there's
no need to fill SHIFT.
+ SHIFT: will be filled in with the shift operand to use, if any. */
+static uint32_t asm_parse_optional_shift(TCCState* s1, int* nb_shift, Operand*
shift)
+{
+ uint32_t opcode = 0;
+ *nb_shift = 0;
+ switch (tok) {
+ case TOK_ASM_asl:
+ case TOK_ASM_lsl:
+ case TOK_ASM_asr:
+ case TOK_ASM_lsr:
+ case TOK_ASM_ror:
+ switch (tok) {
+ case TOK_ASM_asl:
+ /* fallthrough */
+ case TOK_ASM_lsl:
+ opcode = ENCODE_BARREL_SHIFTER_MODE_LSL;
+ break;
+ case TOK_ASM_asr:
+ opcode = ENCODE_BARREL_SHIFTER_MODE_ASR;
+ break;
+ case TOK_ASM_lsr:
+ opcode = ENCODE_BARREL_SHIFTER_MODE_LSR;
+ break;
+ case TOK_ASM_ror:
+ opcode = ENCODE_BARREL_SHIFTER_MODE_ROR;
+ break;
+ }
+ next();
+ parse_operand(s1, shift);
+ *nb_shift = 1;
+ break;
+ case TOK_ASM_rrx:
+ next();
+ opcode = ENCODE_BARREL_SHIFTER_MODE_ROR;
+ break;
+ }
+ return opcode;
+}
+
static uint32_t asm_encode_shift(Operand* shift)
{
uint64_t amount;
@@ -482,37 +526,7 @@ static void asm_data_processing_opcode(TCCState *s1, int
token)
}
if (tok == ',')
next();
- switch (tok) {
- case TOK_ASM_asl:
- case TOK_ASM_lsl:
- case TOK_ASM_asr:
- case TOK_ASM_lsr:
- case TOK_ASM_ror:
- switch (tok) {
- case TOK_ASM_asl:
- /* fallthrough */
- case TOK_ASM_lsl:
- operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
- break;
- case TOK_ASM_asr:
- operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
- break;
- case TOK_ASM_lsr:
- operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
- break;
- case TOK_ASM_ror:
- operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
- break;
- }
- next();
- parse_operand(s1, &shift);
- nb_shift = 1;
- break;
- case TOK_ASM_rrx:
- next();
- operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
- break;
- }
+ operands |= asm_parse_optional_shift(s1, &nb_shift, &shift);
if (nb_ops < 2)
expect("at least two operands");
else if (nb_ops == 2) {
@@ -940,6 +954,8 @@ static void asm_single_data_transfer_opcode(TCCState *s1,
int token)
{
Operand ops[3];
Operand strex_operand;
+ Operand shift;
+ int nb_shift = 0;
int exclam = 0;
int closed_bracket = 0;
int op2_minus = 0;
@@ -999,6 +1015,14 @@ static void asm_single_data_transfer_opcode(TCCState *s1,
int token)
next();
}
parse_operand(s1, &ops[2]);
+ if (ops[2].type == OP_REG32) {
+ if (tok == ',') {
+ next();
+ opcode |= asm_parse_optional_shift(s1, &nb_shift, &shift);
+ if (opcode == 0)
+ expect("shift directive, or no comma");
+ }
+ }
} else {
// end of input expression in brackets--assume 0 offset
ops[2].type = OP_IM8;
@@ -1061,6 +1085,8 @@ static void asm_single_data_transfer_opcode(TCCState *s1,
int token)
/* fallthrough */
case TOK_ASM_streq:
opcode |= 1 << 26; // Load/Store
+ if (nb_shift)
+ opcode |= asm_encode_shift(&shift);
asm_emit_opcode(token, opcode);
break;
case TOK_ASM_ldrbeq:
@@ -1069,14 +1095,16 @@ static void asm_single_data_transfer_opcode(TCCState
*s1, int token)
case TOK_ASM_ldreq:
opcode |= 1 << 20; // L
opcode |= 1 << 26; // Load/Store
+ if (nb_shift)
+ opcode |= asm_encode_shift(&shift);
asm_emit_opcode(token, opcode);
break;
case TOK_ASM_strexbeq:
opcode |= 1 << 22; // B
/* fallthrough */
case TOK_ASM_strexeq:
- if (opcode & 0xFFF) {
- tcc_error("offset not allowed with 'strex'");
+ if ((opcode & 0xFFF) || nb_shift) {
+ tcc_error("neither offset nor shift allowed with 'strex'");
return;
} else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's
NOT immediate
tcc_error("offset not allowed with 'strex'");
@@ -1087,7 +1115,7 @@ static void asm_single_data_transfer_opcode(TCCState *s1,
int token)
return;
}
- opcode |= 0xf90;
+ opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel
shift register is r15, mode is LSL
opcode |= strex_operand.reg;
asm_emit_opcode(token, opcode);
break;
@@ -1095,8 +1123,8 @@ static void asm_single_data_transfer_opcode(TCCState *s1,
int token)
opcode |= 1 << 22; // B
/* fallthrough */
case TOK_ASM_ldrexeq:
- if (opcode & 0xFFF) {
- tcc_error("offset not allowed with 'ldrex'");
+ if ((opcode & 0xFFF) || nb_shift) {
+ tcc_error("neither offset nor shift allowed with 'ldrex'");
return;
} else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's
NOT immediate
tcc_error("offset not allowed with 'ldrex'");
@@ -1108,7 +1136,7 @@ static void asm_single_data_transfer_opcode(TCCState *s1,
int token)
}
opcode |= 1 << 20; // L
opcode |= 0x00f;
- opcode |= 0xf90;
+ opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel
shift register is r15, mode is LSL
asm_emit_opcode(token, opcode);
break;
default:
diff --git a/tests/arm-asm-testsuite.sh b/tests/arm-asm-testsuite.sh
index e997e07..0180628 100755
--- a/tests/arm-asm-testsuite.sh
+++ b/tests/arm-asm-testsuite.sh
@@ -61,6 +61,17 @@ do
"r2, [r3, -r4]" \
"r2, [r3, -r4]!" \
"r2, [r3], r4" \
+ "r2, [r3], -r4" \
+ "r2, [r3]" \
+ "r2, r3, [r4, lsl# 2]" \
+ "r2, [r3, r4, lsr# 1]" \
+ "r2, [r3, r4, lsr# 2]!" \
+ "r2, [r3, -r4, ror# 3]" \
+ "r2, [r3, -r4, lsl# 1]!" \
+ "r2, [r3], r4, lsl# 3" \
+ "r2, [r3], -r4, asr# 31" \
+ "r2, [r3], -r4, asl# 1" \
+ "r2, [r3], -r4, rrx" \
"r2, [r3]" \
"r2, r3, [r4]" \
"r2, [r3, #4]" \
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Tinycc-devel] [PATCH] arm-asm: Implement ldr and str with shifted register offset,
Danny Milosavljevic <=