arm-asm: Support bigger immediates for data processing instructions
This commit is contained in:
parent
14b7973ab5
commit
d66c155239
1 changed files with 40 additions and 17 deletions
55
arm-asm.c
55
arm-asm.c
|
@ -550,6 +550,8 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
uint32_t opcode = 0;
|
uint32_t opcode = 0;
|
||||||
|
uint32_t immediate_value;
|
||||||
|
uint8_t half_immediate_rotation;
|
||||||
if (nb_shift && shift.type == OP_REG32) {
|
if (nb_shift && shift.type == OP_REG32) {
|
||||||
if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
|
if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
|
||||||
(ops[1].type == OP_REG32 && ops[1].reg == 15)) {
|
(ops[1].type == OP_REG32 && ops[1].reg == 15)) {
|
||||||
|
@ -583,11 +585,25 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
|
||||||
operands |= ops[2].reg;
|
operands |= ops[2].reg;
|
||||||
break;
|
break;
|
||||||
case OP_IM8:
|
case OP_IM8:
|
||||||
|
case OP_IM32:
|
||||||
operands |= ENCODE_IMMEDIATE_FLAG;
|
operands |= ENCODE_IMMEDIATE_FLAG;
|
||||||
operands |= ops[2].e.v;
|
immediate_value = ops[2].e.v;
|
||||||
|
for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
|
||||||
|
if (immediate_value >= 0x00 && immediate_value < 0x100)
|
||||||
break;
|
break;
|
||||||
|
// rotate left by two
|
||||||
|
immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
|
||||||
|
}
|
||||||
|
if (half_immediate_rotation >= 16) {
|
||||||
|
/* fallthrough */
|
||||||
|
} else {
|
||||||
|
operands |= immediate_value;
|
||||||
|
operands |= half_immediate_rotation << 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OP_IM8N: // immediate negative value
|
case OP_IM8N: // immediate negative value
|
||||||
operands |= ENCODE_IMMEDIATE_FLAG;
|
operands |= ENCODE_IMMEDIATE_FLAG;
|
||||||
|
immediate_value = ops[2].e.v;
|
||||||
/* Instruction swapping:
|
/* Instruction swapping:
|
||||||
0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
|
0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
|
||||||
0011 = RSB - Rd:= Op2 - Op1 -> difficult
|
0011 = RSB - Rd:= Op2 - Op1 -> difficult
|
||||||
|
@ -597,54 +613,61 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
|
||||||
1100 = ORR - Rd:= Op1 OR Op2 -> difficult
|
1100 = ORR - Rd:= Op1 OR Op2 -> difficult
|
||||||
*/
|
*/
|
||||||
switch (opcode_nos) {
|
switch (opcode_nos) {
|
||||||
#if 0
|
|
||||||
case 0x0: // AND - Rd:= Op1 AND Op2
|
case 0x0: // AND - Rd:= Op1 AND Op2
|
||||||
opcode = 0xe << 21; // BIC
|
opcode = 0xe << 21; // BIC
|
||||||
operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
|
immediate_value = ~immediate_value;
|
||||||
break;
|
break;
|
||||||
case 0x2: // SUB - Rd:= Op1 - Op2
|
case 0x2: // SUB - Rd:= Op1 - Op2
|
||||||
opcode = 0x4 << 21; // ADD
|
opcode = 0x4 << 21; // ADD
|
||||||
operands |= (-ops[2].e.v) & 0xFF;
|
immediate_value = -immediate_value;
|
||||||
break;
|
break;
|
||||||
case 0x4: // ADD - Rd:= Op1 + Op2
|
case 0x4: // ADD - Rd:= Op1 + Op2
|
||||||
opcode = 0x2 << 21; // SUB
|
opcode = 0x2 << 21; // SUB
|
||||||
operands |= (-ops[2].e.v) & 0xFF;
|
immediate_value = -immediate_value;
|
||||||
break;
|
break;
|
||||||
case 0x5: // ADC - Rd:= Op1 + Op2 + C
|
case 0x5: // ADC - Rd:= Op1 + Op2 + C
|
||||||
opcode = 0x6 << 21; // SBC
|
opcode = 0x6 << 21; // SBC
|
||||||
operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
|
immediate_value = ~immediate_value;
|
||||||
break;
|
break;
|
||||||
case 0x6: // SBC - Rd:= Op1 - Op2 + C
|
case 0x6: // SBC - Rd:= Op1 - Op2 + C
|
||||||
opcode = 0x5 << 21; // ADC
|
opcode = 0x5 << 21; // ADC
|
||||||
operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
|
immediate_value = ~immediate_value;
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case 0xa: // CMP - CC on: Op1 - Op2
|
case 0xa: // CMP - CC on: Op1 - Op2
|
||||||
opcode = 0xb << 21; // CMN
|
opcode = 0xb << 21; // CMN
|
||||||
operands |= (-ops[2].e.v) & 0xFF;
|
immediate_value = -immediate_value;
|
||||||
break;
|
break;
|
||||||
case 0xb: // CMN - CC on: Op1 + Op2
|
case 0xb: // CMN - CC on: Op1 + Op2
|
||||||
opcode = 0xa << 21; // CMP
|
opcode = 0xa << 21; // CMP
|
||||||
operands |= (-ops[2].e.v) & 0xFF;
|
immediate_value = -immediate_value;
|
||||||
break;
|
break;
|
||||||
// moveq r1, r3: 0x01a01003; mov Rd, Op2
|
|
||||||
case 0xd: // MOV - Rd:= Op2
|
case 0xd: // MOV - Rd:= Op2
|
||||||
opcode = 0xf << 21; // MVN
|
opcode = 0xf << 21; // MVN
|
||||||
operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
|
immediate_value = ~immediate_value;
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
case 0xe: // BIC - Rd:= Op1 AND NOT Op2
|
case 0xe: // BIC - Rd:= Op1 AND NOT Op2
|
||||||
opcode = 0x0 << 21; // AND
|
opcode = 0x0 << 21; // AND
|
||||||
operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
|
immediate_value = ~immediate_value;
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case 0xf: // MVN - Rd:= NOT Op2
|
case 0xf: // MVN - Rd:= NOT Op2
|
||||||
opcode = 0xd << 21; // MOV
|
opcode = 0xd << 21; // MOV
|
||||||
operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
|
immediate_value = ~immediate_value;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token, NULL));
|
tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token, NULL));
|
||||||
}
|
}
|
||||||
|
for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
|
||||||
|
if (immediate_value >= 0x00 && immediate_value < 0x100)
|
||||||
|
break;
|
||||||
|
// rotate left by two
|
||||||
|
immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
|
||||||
|
}
|
||||||
|
if (half_immediate_rotation >= 16) {
|
||||||
|
tcc_error("immediate value 0x%X cannot be encoded into ARM immediate", (unsigned) immediate_value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
operands |= immediate_value;
|
||||||
|
operands |= half_immediate_rotation << 8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
expect("(second source operand) register or immediate value");
|
expect("(second source operand) register or immediate value");
|
||||||
|
|
Loading…
Reference in a new issue