* register indirect loads and stores * load of local addresses * indirect calls (uses ra as temporary reg if necessary) * operations *, -, << * gen_cvt_sxtw: is not needed in most cases, let's see tests2 runs until (incl) 09_do_while.
Unified · Split
| @@ -33,6 +33,8 @@ · 32 unmodified lines | |||
| 33 | 33 | ||
| 34 | #define XLEN 8 | 34 | #define XLEN 8 |
| 35 | 35 | ||
| 36 | #define TREG_RA 17 | ||
| 37 | |||
| 36 | ST_DATA const int reg_classes[NB_REGS] = { | 38 | ST_DATA const int reg_classes[NB_REGS] = { |
| 37 | RC_INT | RC_R(0), | 39 | RC_INT | RC_R(0), |
| 38 | RC_INT | RC_R(1), | 40 | RC_INT | RC_R(1), |
| @@ -54,13 +56,15 @@ ST_DATA const int reg_classes[NB_REGS] = { · 15 unmodified lines | |||
| 54 | 56 | ||
| 55 | static int ireg(int r) | 57 | static int ireg(int r) |
| 56 | { | 58 | { |
| 59 | if (r == TREG_RA) | ||
| 60 | return 1; // ra | ||
| 57 | assert(r >= 0 && r < 8); | 61 | assert(r >= 0 && r < 8); |
| 58 | return r + 10; // tccrX --> aX == x(10+X) | 62 | return r + 10; // tccrX --> aX == x(10+X) |
| 59 | } | 63 | } |
| 60 | 64 | ||
| 61 | static int is_ireg(int r) | 65 | static int is_ireg(int r) |
| 62 | { | 66 | { |
| 63 | return r < 8; | 67 | return r < 8 || r == TREG_RA; |
| 64 | } | 68 | } |
| 65 | 69 | ||
| 66 | static int is_freg(int r) | 70 | static int is_freg(int r) |
| @@ -121,20 +125,22 @@ ST_FUNC void load(int r, SValue *sv) · 54 unmodified lines | |||
| 121 | int rr = ireg(r); | 125 | int rr = ireg(r); |
| 122 | int fc = sv->c.i; | 126 | int fc = sv->c.i; |
| 123 | if (fr & VT_LVAL) { | 127 | if (fr & VT_LVAL) { |
| 128 | int bt = sv->type.t & VT_BTYPE; | ||
| 129 | int align, size = type_size(&sv->type, &align); | ||
| 130 | int func3; | ||
| 131 | if (is_float(bt)) | ||
| 132 | tcc_error("unimp: load-local(float)"); | ||
| 133 | else if (bt == VT_FUNC) | ||
| 134 | size = PTR_SIZE; | ||
| 135 | func3 = size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3; | ||
| 136 | if (size < 8 && (sv->type.t & VT_UNSIGNED)) | ||
| 137 | func3 |= 4; | ||
| 124 | if (v == VT_LOCAL) { | 138 | if (v == VT_LOCAL) { |
| 125 | int bt = sv->type.t & VT_BTYPE; | ||
| 126 | int align, size = type_size(&sv->type, &align); | ||
| 127 | int func3; | ||
| 128 | if (((unsigned)fc + (1 << 11)) >> 12) | 139 | if (((unsigned)fc + (1 << 11)) >> 12) |
| 129 | tcc_error("unimp: load(large local ofs) (0x%x)", fc); | 140 | tcc_error("unimp: load(large local ofs) (0x%x)", fc); |
| 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) | 141 | EI(0x03, func3, rr, 8, fc); // l[bhwd][u] RR, fc(s0) |
| 142 | } else if (v < VT_CONST) { | ||
| 143 | EI(0x03, func3, rr, ireg(v), 0); // l[bhwd][u] RR, 0(V) | ||
| 138 | } else { | 144 | } else { |
| 139 | tcc_error("unimp: load(non-local lval)"); | 145 | tcc_error("unimp: load(non-local lval)"); |
| 140 | } | 146 | } |
| @@ -162,6 +168,10 @@ ST_FUNC void load(int r, SValue *sv) · 21 unmodified lines | |||
| 162 | if (is_float(sv->type.t)) | 168 | if (is_float(sv->type.t)) |
| 163 | tcc_error("unimp: load(float)"); | 169 | tcc_error("unimp: load(float)"); |
| 164 | EI(0x13, 0, rr, rb, fc); // addi R, x0|R, FC | 170 | EI(0x13, 0, rr, rb, fc); // addi R, x0|R, FC |
| 171 | } else if (v == VT_LOCAL) { | ||
| 172 | if (((unsigned)fc + (1 << 11)) >> 12) | ||
| 173 | tcc_error("unimp: load(addr large local ofs) (0x%x)", fc); | ||
| 174 | EI(0x13, 0, rr, 8, fc); // addi R, s0, FC | ||
| 165 | } else if (v < VT_CONST) { | 175 | } else if (v < VT_CONST) { |
| 166 | /* reg-reg */ | 176 | /* reg-reg */ |
| 167 | if (is_freg(r) && is_freg(v)) | 177 | if (is_freg(r) && is_freg(v)) |
| @@ -195,6 +205,10 @@ ST_FUNC void store(int r, SValue *sv) · 27 unmodified lines | |||
| 195 | tcc_error("unimp: large sized store"); | 205 | tcc_error("unimp: large sized store"); |
| 196 | ES(0x23, size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3, | 206 | ES(0x23, size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3, |
| 197 | 8, rr, fc); // s[bhwd] RR, fc(s0) | 207 | 8, rr, fc); // s[bhwd] RR, fc(s0) |
| 208 | } else if (fr < VT_CONST) { | ||
| 209 | int ptrreg = ireg(fr); | ||
| 210 | ES(0x23, size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3, | ||
| 211 | ptrreg, rr, 0); // s[bhwd] RR, 0(PTRREG) | ||
| 198 | } else | 212 | } else |
| 199 | tcc_error("implement me: %s(!local)", __FUNCTION__); | 213 | tcc_error("implement me: %s(!local)", __FUNCTION__); |
| 200 | } | 214 | } |
| @@ -208,8 +222,14 @@ static void gcall(void) · 7 unmodified lines | |||
| 208 | R_RISCV_CALL_PLT, (int)vtop->c.i); | 222 | R_RISCV_CALL_PLT, (int)vtop->c.i); |
| 209 | o(0x17 | (1 << 7)); // auipc ra, 0 %call(func) | 223 | o(0x17 | (1 << 7)); // auipc ra, 0 %call(func) |
| 210 | o(0x80e7); // jalr ra, 0 %call(func) | 224 | o(0x80e7); // jalr ra, 0 %call(func) |
| 225 | } else if ((vtop->r & VT_VALMASK) < VT_CONST) { | ||
| 226 | int r = ireg(vtop->r & VT_VALMASK); | ||
| 227 | EI(0x67, 0, 1, r, 0); // jalr ra, 0(R) | ||
| 211 | } else { | 228 | } else { |
| 212 | tcc_error("unimp: indirect call"); | 229 | int r = TREG_RA; |
| 230 | load(r, vtop); | ||
| 231 | r = ireg(r); | ||
| 232 | EI(0x67, 0, 1, r, 0); // jalr ra, 0(R) | ||
| 213 | } | 233 | } |
| 214 | } | 234 | } |
| 215 | 235 | ||
| @@ -401,6 +421,7 @@ static void gen_opil(int op, int ll) · 185 unmodified lines | |||
| 401 | { | 421 | { |
| 402 | int a, b, d; | 422 | int a, b, d; |
| 403 | int inv = 0; | 423 | int inv = 0; |
| 424 | int func3 = 0, func7 = 0; | ||
| 404 | /* XXX We could special-case some constant args. */ | 425 | /* XXX We could special-case some constant args. */ |
| 405 | gv2(RC_INT, RC_INT); | 426 | gv2(RC_INT, RC_INT); |
| 406 | a = ireg(vtop[-1].r); | 427 | a = ireg(vtop[-1].r); |
| @@ -413,13 +434,10 @@ static void gen_opil(int op, int ll) · 6 unmodified lines | |||
| 413 | switch (op) { | 434 | switch (op) { |
| 414 | case '%': | 435 | case '%': |
| 415 | case '&': | 436 | case '&': |
| 416 | case '*': | ||
| 417 | case '-': | ||
| 418 | case '/': | 437 | case '/': |
| 419 | case '^': | 438 | case '^': |
| 420 | case '|': | 439 | case '|': |
| 421 | case TOK_SAR: | 440 | case TOK_SAR: |
| 422 | case TOK_SHL: | ||
| 423 | case TOK_SHR: | 441 | case TOK_SHR: |
| 424 | case TOK_UDIV: | 442 | case TOK_UDIV: |
| 425 | case TOK_PDIV: | 443 | case TOK_PDIV: |
| @@ -430,6 +448,15 @@ static void gen_opil(int op, int ll) · 4 unmodified lines | |||
| 430 | case '+': | 448 | case '+': |
| 431 | o(0x33 | (d << 7) | (a << 15) | (b << 20)); // add d, a, b | 449 | o(0x33 | (d << 7) | (a << 15) | (b << 20)); // add d, a, b |
| 432 | break; | 450 | break; |
| 451 | case '-': | ||
| 452 | o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x20 << 25)); //sub d, a, b | ||
| 453 | break; | ||
| 454 | case TOK_SHL: | ||
| 455 | o(0x33 | (d << 7) | (a << 15) | (b << 20) | (1 << 12)); //sll d, a, b | ||
| 456 | break; | ||
| 457 | case '*': | ||
| 458 | o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x01 << 25)); //mul d, a, b | ||
| 459 | break; | ||
| 433 | 460 | ||
| 434 | case TOK_ULT: | 461 | case TOK_ULT: |
| 435 | case TOK_UGE: | 462 | case TOK_UGE: |
| @@ -483,7 +510,8 @@ ST_FUNC void gen_opf(int op) · 47 unmodified lines | |||
| 483 | 510 | ||
| 484 | ST_FUNC void gen_cvt_sxtw(void) | 511 | ST_FUNC void gen_cvt_sxtw(void) |
| 485 | { | 512 | { |
| 486 | tcc_error("implement me: %s", __FUNCTION__); | 513 | /* XXX on risc-v the registers are usually sign-extended already. |
| 514 | Let's try to not do anything here. */ | ||
| 487 | } | 515 | } |
| 488 | 516 | ||
| 489 | ST_FUNC void gen_cvt_itof(int t) | 517 | ST_FUNC void gen_cvt_itof(int t) |