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 | /* generate prolog and epilog code for asm statement */ | 1248 | /* generate prolog and epilog code for asm statement */ |
| 1249 | ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, | 1249 | ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, |
| 1250 | int nb_outputs, int is_output, | 1250 | int nb_outputs, int is_output, |
| 1251 | uint8_t *clobber_regs, | 1251 | uint8_t *clobber_regs, |
| 1252 | int out_reg) | 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 | ST_FUNC void asm_compute_constraints(ASMOperand *operands, | 1333 | ST_FUNC void asm_compute_constraints(ASMOperand *operands, |