| @@ -58,6 +58,16 @@ static int ireg(int r) · 57 unmodified lines |
| 58 | 58 | return r + 10; // tccrX --> aX == x(10+X) |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | +static int is_ireg(int r) |
| 62 | +{ |
| 63 | + return r < 8; |
| 64 | +} |
| 65 | + |
| 66 | +static int is_freg(int r) |
| 67 | +{ |
| 68 | + return r >= 8 && r < 16; |
| 69 | +} |
| 70 | + |
| 61 | 71 | ST_FUNC void o(unsigned int c) |
| 62 | 72 | { |
| 63 | 73 | int ind1 = ind + 4; |
| @@ -92,11 +102,14 @@ ST_FUNC void gsym_addr(int t_, int a_) · 28 unmodified lines |
| 92 | 102 | while (t) { |
| 93 | 103 | unsigned char *ptr = cur_text_section->data + t; |
| 94 | 104 | uint32_t next = read32le(ptr); |
| 95 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 96 | | − if (a - t + 0x8000000 >= 0x10000000) |
| 97 | | − tcc_error("branch out of range"); |
| 98 | | − write32le(ptr, (a - t == 4 ? 0xd503201f : // nop |
| 99 | | − 0x14000000 | ((a - t) >> 2 & 0x3ffffff))); // b |
| 105 | + uint32_t r = a - t, imm; |
| 106 | + if ((r + (1 << 21)) & ~((1U << 22) - 2)) |
| 107 | + tcc_error("out-of-range branch chain"); |
| 108 | + imm = (((r >> 12) & 0xff) << 12) |
| 109 | + | (((r >> 11) & 1) << 20) |
| 110 | + | (((r >> 1) & 0x3ff) << 21) |
| 111 | + | (((r >> 20) & 1) << 31); |
| 112 | + write32le(ptr, r == 4 ? 0x33 : 0x6f | imm); // nop || j imm |
| 100 | 113 | t = next; |
| 101 | 114 | } |
| 102 | 115 | } |
| @@ -109,9 +122,19 @@ ST_FUNC void load(int r, SValue *sv) · 6 unmodified lines |
| 109 | 122 | int fc = sv->c.i; |
| 110 | 123 | if (fr & VT_LVAL) { |
| 111 | 124 | if (v == VT_LOCAL) { |
| 125 | + int bt = sv->type.t & VT_BTYPE; |
| 126 | + int align, size = type_size(&sv->type, &align); |
| 127 | + int func3; |
| 112 | 128 | if (((unsigned)fc + (1 << 11)) >> 12) |
| 113 | 129 | tcc_error("unimp: load(large local ofs) (0x%x)", fc); |
| 114 | | − EI(0x03, 3, rr, 8, fc); // ld RR, fc(s0) |
| 130 | + if (is_float(bt)) |
| 131 | + tcc_error("unimp: load-local(float)"); |
| 132 | + else if (bt == VT_FUNC) |
| 133 | + size = PTR_SIZE; |
| 134 | + func3 = size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3; |
| 135 | + if (size < 8 && (sv->type.t & VT_UNSIGNED)) |
| 136 | + func3 |= 4; |
| 137 | + EI(0x03, func3, rr, 8, fc); // l[bhwd][u] RR, fc(s0) |
| 115 | 138 | } else { |
| 116 | 139 | tcc_error("unimp: load(non-local lval)"); |
| 117 | 140 | } |
| @@ -139,13 +162,41 @@ ST_FUNC void load(int r, SValue *sv) · 21 unmodified lines |
| 139 | 162 | if (is_float(sv->type.t)) |
| 140 | 163 | tcc_error("unimp: load(float)"); |
| 141 | 164 | EI(0x13, 0, rr, rb, fc); // addi R, x0|R, FC |
| 165 | + } else if (v < VT_CONST) { |
| 166 | + /* reg-reg */ |
| 167 | + if (is_freg(r) && is_freg(v)) |
| 168 | + tcc_error("unimp load: float reg-reg move"); |
| 169 | + else if (is_ireg(r) && is_ireg(v)) |
| 170 | + EI(0x13, 0, rr, ireg(v), 0); // addi RR, V, 0 == mv RR, V |
| 171 | + else |
| 172 | + tcc_error("ICE: inter-unit reg-reg move"); |
| 173 | + } else if (v == VT_CMP) { // we rely on cmp_r to be the correct result |
| 174 | + EI(0x13, 0, rr, vtop->cmp_r, 0); // mv RR, CMP_R |
| 142 | 175 | } else |
| 143 | 176 | tcc_error("unimp: load(non-const)"); |
| 144 | 177 | } |
| 145 | 178 | |
| 146 | 179 | ST_FUNC void store(int r, SValue *sv) |
| 147 | 180 | { |
| 148 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 181 | + int fr = sv->r & VT_VALMASK; |
| 182 | + int rr = ireg(r); |
| 183 | + int fc = sv->c.i; |
| 184 | + int ft = sv->type.t; |
| 185 | + int bt = ft & VT_BTYPE; |
| 186 | + int align, size = type_size(&sv->type, &align); |
| 187 | + if (fr == VT_LOCAL) { |
| 188 | + if (((unsigned)fc + (1 << 11)) >> 12) |
| 189 | + tcc_error("unimp: store(large local off) (0x%x)", fc); |
| 190 | + if (is_float(bt)) |
| 191 | + tcc_error("unimp: store(float)"); |
| 192 | + if (bt == VT_STRUCT) |
| 193 | + tcc_error("unimp: store(struct)"); |
| 194 | + if (size > 8) |
| 195 | + tcc_error("unimp: large sized store"); |
| 196 | + ES(0x23, size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3, |
| 197 | + 8, rr, fc); // s[bhwd] RR, fc(s0) |
| 198 | + } else |
| 199 | + tcc_error("implement me: %s(!local)", __FUNCTION__); |
| 149 | 200 | } |
| 150 | 201 | |
| 151 | 202 | static void gcall(void) |
| @@ -174,7 +225,7 @@ ST_FUNC void gfunc_call(int nb_args) · 22 unmodified lines |
| 174 | 225 | if (aireg >= 8) |
| 175 | 226 | tcc_error("unimp: too many register args"); |
| 176 | 227 | vrotb(i+1); |
| 177 | | − gv(RC_R(aireg)); |
| 228 | + gv(RC_R(nb_args - 1 - aireg)); |
| 178 | 229 | vrott(i+1); |
| 179 | 230 | aireg++; |
| 180 | 231 | } |
| @@ -233,6 +284,7 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 52 unmodified lines |
| 233 | 284 | tcc_error("unimp: float args"); |
| 234 | 285 | } else { |
| 235 | 286 | ES(0x23, 3, 8, 10 + aireg, loc + i*8); // sd aX, loc(s0) // XXX |
| 287 | + aireg++; |
| 236 | 288 | } |
| 237 | 289 | } |
| 238 | 290 | } |
| @@ -303,38 +355,125 @@ ST_FUNC void gen_fill_nops(int bytes) · 64 unmodified lines |
| 303 | 355 | // Generate forward branch to label: |
| 304 | 356 | ST_FUNC int gjmp(int t) |
| 305 | 357 | { |
| 306 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 358 | + if (nocode_wanted) |
| 359 | + return t; |
| 360 | + o(t); |
| 361 | + return ind - 4; |
| 307 | 362 | } |
| 308 | 363 | |
| 309 | 364 | // Generate branch to known address: |
| 310 | 365 | ST_FUNC void gjmp_addr(int a) |
| 311 | 366 | { |
| 312 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 367 | + uint32_t r = a - ind, imm; |
| 368 | + if ((r + (1 << 21)) & ~((1U << 22) - 2)) |
| 369 | + tcc_error("out-of-range jump"); |
| 370 | + imm = (((r >> 12) & 0xff) << 12) |
| 371 | + | (((r >> 11) & 1) << 20) |
| 372 | + | (((r >> 1) & 0x3ff) << 21) |
| 373 | + | (((r >> 20) & 1) << 31); |
| 374 | + o(0x6f | imm); // jal x0, imm == j imm |
| 313 | 375 | } |
| 314 | 376 | |
| 315 | 377 | ST_FUNC int gjmp_cond(int op, int t) |
| 316 | 378 | { |
| 317 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 379 | + int inv = op & 1; |
| 380 | + assert(op == TOK_EQ || op == TOK_NE); |
| 381 | + assert(vtop->cmp_r >= 10 && vtop->cmp_r < 18); |
| 382 | + o(0x63 | (!inv << 12) | (vtop->cmp_r << 15) | (8 << 7)); // bne/beq x0,r,+4 |
| 383 | + return gjmp(t); |
| 318 | 384 | } |
| 319 | 385 | |
| 320 | 386 | ST_FUNC int gjmp_append(int n, int t) |
| 321 | 387 | { |
| 322 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 323 | | −} |
| 324 | | − |
| 325 | | −ST_FUNC int gtst(int inv, int t) |
| 326 | | −{ |
| 327 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 388 | + void *p; |
| 389 | + /* insert jump list n into t */ |
| 390 | + if (n) { |
| 391 | + uint32_t n1 = n, n2; |
| 392 | + while ((n2 = read32le(p = cur_text_section->data + n1))) |
| 393 | + n1 = n2; |
| 394 | + write32le(p, t); |
| 395 | + t = n; |
| 396 | + } |
| 397 | + return t; |
| 398 | +} |
| 399 | + |
| 400 | +static void gen_opil(int op, int ll) |
| 401 | +{ |
| 402 | + int a, b, d; |
| 403 | + int inv = 0; |
| 404 | + /* XXX We could special-case some constant args. */ |
| 405 | + gv2(RC_INT, RC_INT); |
| 406 | + a = ireg(vtop[-1].r); |
| 407 | + b = ireg(vtop[0].r); |
| 408 | + vtop -= 2; |
| 409 | + d = get_reg(RC_INT); |
| 410 | + vtop++; |
| 411 | + vtop[0].r = d; |
| 412 | + d = ireg(d); |
| 413 | + switch (op) { |
| 414 | + case '%': |
| 415 | + case '&': |
| 416 | + case '*': |
| 417 | + case '-': |
| 418 | + case '/': |
| 419 | + case '^': |
| 420 | + case '|': |
| 421 | + case TOK_SAR: |
| 422 | + case TOK_SHL: |
| 423 | + case TOK_SHR: |
| 424 | + case TOK_UDIV: |
| 425 | + case TOK_PDIV: |
| 426 | + case TOK_UMOD: |
| 427 | + default: |
| 428 | + tcc_error("implement me: %s(%s)", __FUNCTION__, get_tok_str(op, NULL)); |
| 429 | + |
| 430 | + case '+': |
| 431 | + o(0x33 | (d << 7) | (a << 15) | (b << 20)); // add d, a, b |
| 432 | + break; |
| 433 | + |
| 434 | + case TOK_ULT: |
| 435 | + case TOK_UGE: |
| 436 | + case TOK_ULE: |
| 437 | + case TOK_UGT: |
| 438 | + case TOK_LT: |
| 439 | + case TOK_GE: |
| 440 | + case TOK_LE: |
| 441 | + case TOK_GT: |
| 442 | + if (op & 1) { // remove [U]GE,GT |
| 443 | + inv = 1; |
| 444 | + op--; |
| 445 | + } |
| 446 | + if ((op & 7) == 6) { // [U]LE |
| 447 | + int t = a; a = b; b = t; |
| 448 | + inv ^= 1; |
| 449 | + } |
| 450 | + o(0x33 | (d << 7) | (a << 15) | (b << 20) | (((op > TOK_UGT) ? 2 : 3) << 12)); // slt[u] d, a, b |
| 451 | + if (inv) |
| 452 | + EI(0x13, 4, d, d, 1); // xori d, d, 1 |
| 453 | + vset_VT_CMP(TOK_NE); |
| 454 | + vtop->cmp_r = d; |
| 455 | + break; |
| 456 | + case TOK_NE: |
| 457 | + case TOK_EQ: |
| 458 | + o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x20 << 25)); // sub d, a, b |
| 459 | + if (op == TOK_NE) |
| 460 | + o(0x33 | (3 << 12) | (d << 7) | (0 << 15) | (d << 20)); // sltu d, x0, d == snez d,d |
| 461 | + else |
| 462 | + EI(0x13, 3, d, d, 1); // sltiu d, d, 1 == seqz d,d |
| 463 | + vset_VT_CMP(TOK_NE); |
| 464 | + vtop->cmp_r = d; |
| 465 | + break; |
| 466 | + } |
| 328 | 467 | } |
| 329 | 468 | |
| 330 | 469 | ST_FUNC void gen_opi(int op) |
| 331 | 470 | { |
| 332 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 471 | + gen_opil(op, 0); |
| 333 | 472 | } |
| 334 | 473 | |
| 335 | 474 | ST_FUNC void gen_opl(int op) |
| 336 | 475 | { |
| 337 | | − tcc_error("implement me: %s", __FUNCTION__); |
| 476 | + gen_opil(op, 1); |
| 338 | 477 | } |
| 339 | 478 | |
| 340 | 479 | ST_FUNC void gen_opf(int op) |