Unified · Split
| @@ -1247,10 +1247,87 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) · 1246 unmodified lines | ||
| 1247 | 1247 | |
| 1248 | 1248 | /* generate prolog and epilog code for asm statement */ |
| 1249 | 1249 | ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, |
| 1250 | − int nb_outputs, int is_output, | |
| 1251 | − uint8_t *clobber_regs, | |
| 1252 | − int out_reg) | |
| 1250 | + int nb_outputs, int is_output, | |
| 1251 | + uint8_t *clobber_regs, | |
| 1252 | + int out_reg) | |
| 1253 | 1253 | { |
| 1254 | + uint8_t regs_allocated[NB_ASM_REGS]; | |
| 1255 | + ASMOperand *op; | |
| 1256 | + int i, reg; | |
| 1257 | + uint32_t saved_regset = 0; | |
| 1258 | + | |
| 1259 | + // TODO: Check non-E ABI. | |
| 1260 | + // Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet | |
| 1261 | + static uint8_t reg_saved[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 }; | |
| 1262 | + | |
| 1263 | + /* mark all used registers */ | |
| 1264 | + memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated)); | |
| 1265 | + for(i = 0; i < nb_operands;i++) { | |
| 1266 | + op = &operands[i]; | |
| 1267 | + if (op->reg >= 0) | |
| 1268 | + regs_allocated[op->reg] = 1; | |
| 1269 | + } | |
| 1270 | + for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) { | |
| 1271 | + reg = reg_saved[i]; | |
| 1272 | + if (regs_allocated[reg]) | |
| 1273 | + saved_regset |= 1 << reg; | |
| 1274 | + } | |
| 1275 | + | |
| 1276 | + if (!is_output) { // prolog | |
| 1277 | + /* generate reg save code */ | |
| 1278 | + if (saved_regset) | |
| 1279 | + gen_le32(0xe92d0000 | saved_regset); // push {...} | |
| 1280 | + | |
| 1281 | + /* generate load code */ | |
| 1282 | + for(i = 0; i < nb_operands; i++) { | |
| 1283 | + op = &operands[i]; | |
| 1284 | + if (op->reg >= 0) { | |
| 1285 | + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && | |
| 1286 | + op->is_memory) { | |
| 1287 | + /* memory reference case (for both input and | |
| 1288 | + output cases) */ | |
| 1289 | + SValue sv; | |
| 1290 | + sv = *op->vt; | |
| 1291 | + sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; | |
| 1292 | + sv.type.t = VT_PTR; | |
| 1293 | + load(op->reg, &sv); | |
| 1294 | + } else if (i >= nb_outputs || op->is_rw) { // not write-only | |
| 1295 | + /* load value in register */ | |
| 1296 | + load(op->reg, op->vt); | |
| 1297 | + if (op->is_llong) | |
| 1298 | + tcc_error("long long not implemented"); | |
| 1299 | + } | |
| 1300 | + } | |
| 1301 | + } | |
| 1302 | + } else { // epilog | |
| 1303 | + /* generate save code */ | |
| 1304 | + for(i = 0 ; i < nb_outputs; i++) { | |
| 1305 | + op = &operands[i]; | |
| 1306 | + if (op->reg >= 0) { | |
| 1307 | + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { | |
| 1308 | + if (!op->is_memory) { | |
| 1309 | + SValue sv; | |
| 1310 | + sv = *op->vt; | |
| 1311 | + sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL; | |
| 1312 | + sv.type.t = VT_PTR; | |
| 1313 | + load(out_reg, &sv); | |
| 1314 | + | |
| 1315 | + sv = *op->vt; | |
| 1316 | + sv.r = (sv.r & ~VT_VALMASK) | out_reg; | |
| 1317 | + store(op->reg, &sv); | |
| 1318 | + } | |
| 1319 | + } else { | |
| 1320 | + store(op->reg, op->vt); | |
| 1321 | + if (op->is_llong) | |
| 1322 | + tcc_error("long long not implemented"); | |
| 1323 | + } | |
| 1324 | + } | |
| 1325 | + } | |
| 1326 | + | |
| 1327 | + /* generate reg restore code */ | |
| 1328 | + if (saved_regset) | |
| 1329 | + gen_le32(0xe8bd0000 | saved_regset); // pop {...} | |
| 1330 | + } | |
| 1254 | 1331 | } |
| 1255 | 1332 | |
| 1256 | 1333 | ST_FUNC void asm_compute_constraints(ASMOperand *operands, |