arm-asm: Implement asm_gen_code

This commit is contained in:
Danny Milosavljevic 2021-01-01 04:15:00 +01:00
parent d66c155239
commit 795d7d5ce6
No known key found for this signature in database
GPG key ID: E71A35542C30BAA5

View file

@ -1247,10 +1247,87 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
/* generate prolog and epilog code for asm statement */ /* generate prolog and epilog code for asm statement */
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
int nb_outputs, int is_output, int nb_outputs, int is_output,
uint8_t *clobber_regs, uint8_t *clobber_regs,
int out_reg) int out_reg)
{ {
uint8_t regs_allocated[NB_ASM_REGS];
ASMOperand *op;
int i, reg;
uint32_t saved_regset = 0;
// TODO: Check non-E ABI.
// Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet
static uint8_t reg_saved[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
/* mark all used registers */
memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
for(i = 0; i < nb_operands;i++) {
op = &operands[i];
if (op->reg >= 0)
regs_allocated[op->reg] = 1;
}
for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) {
reg = reg_saved[i];
if (regs_allocated[reg])
saved_regset |= 1 << reg;
}
if (!is_output) { // prolog
/* generate reg save code */
if (saved_regset)
gen_le32(0xe92d0000 | saved_regset); // push {...}
/* generate load code */
for(i = 0; i < nb_operands; i++) {
op = &operands[i];
if (op->reg >= 0) {
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
op->is_memory) {
/* memory reference case (for both input and
output cases) */
SValue sv;
sv = *op->vt;
sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
sv.type.t = VT_PTR;
load(op->reg, &sv);
} else if (i >= nb_outputs || op->is_rw) { // not write-only
/* load value in register */
load(op->reg, op->vt);
if (op->is_llong)
tcc_error("long long not implemented");
}
}
}
} else { // epilog
/* generate save code */
for(i = 0 ; i < nb_outputs; i++) {
op = &operands[i];
if (op->reg >= 0) {
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
if (!op->is_memory) {
SValue sv;
sv = *op->vt;
sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
sv.type.t = VT_PTR;
load(out_reg, &sv);
sv = *op->vt;
sv.r = (sv.r & ~VT_VALMASK) | out_reg;
store(op->reg, &sv);
}
} else {
store(op->reg, op->vt);
if (op->is_llong)
tcc_error("long long not implemented");
}
}
}
/* generate reg restore code */
if (saved_regset)
gen_le32(0xe8bd0000 | saved_regset); // pop {...}
}
} }
ST_FUNC void asm_compute_constraints(ASMOperand *operands, ST_FUNC void asm_compute_constraints(ASMOperand *operands,