mirror of
https://github.com/mirror/tinycc.git
synced 2025-03-12 09:00:09 +08:00
arm-asm: Implement ldr and str with shifted register offset
Factor out asm_parse_optional_shift
This commit is contained in:
parent
1d7b233562
commit
007839597f
102
arm-asm.c
102
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:
|
||||
|
@ -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]" \
|
||||
|
Loading…
Reference in New Issue
Block a user