call, tail, jump, jr, mv, not, neg, negw, seqz, snez, sltz, sgtz, bnez, beqz, blez, bgez, bltz, bgtz, li
Unified · Split
| @@ -152,6 +152,12 @@ static void asm_nullary_opcode(TCCState *s1, int token) · 151 unmodified lines | ||
| 152 | 152 | asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20)); |
| 153 | 153 | return; |
| 154 | 154 | |
| 155 | + /* Pseudoinstructions */ | |
| 156 | + case TOK_ASM_ret: | |
| 157 | + /* jalr zero, x1, 0 */ | |
| 158 | + asm_emit_opcode( 0x67 | (0 << 12) | ENCODE_RS1(1) ); | |
| 159 | + return; | |
| 160 | + | |
| 155 | 161 | /* C extension */ |
| 156 | 162 | case TOK_ASM_c_ebreak: |
| 157 | 163 | asm_emit_cr(token, 2 | (9 << 12), &nil, &nil); |
| @@ -265,7 +271,8 @@ static void asm_unary_opcode(TCCState *s1, int token) · 107 unmodified lines | ||
| 265 | 271 | { |
| 266 | 272 | uint32_t opcode = (0x1C << 2) | 3 | (2 << 12); |
| 267 | 273 | Operand op; |
| 268 | − static const Operand nil = {.type = OP_REG}; | |
| 274 | + static const Operand zero = {.type = OP_REG}; | |
| 275 | + static const Operand zimm = {.type = OP_IM12S}; | |
| 269 | 276 | |
| 270 | 277 | parse_operands(s1, &op, 1); |
| 271 | 278 | /* Note: Those all map to CSR--so they are pseudo-instructions. */ |
| @@ -291,6 +298,26 @@ static void asm_unary_opcode(TCCState *s1, int token) · 19 unmodified lines | ||
| 291 | 298 | case TOK_ASM_rdinstreth: |
| 292 | 299 | asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg)); |
| 293 | 300 | return; |
| 301 | + | |
| 302 | + case TOK_ASM_jr: | |
| 303 | + /* jalr zero, 0(rs)*/ | |
| 304 | + asm_emit_i(token, 0x67 | (0 << 12), &zero, &op, &zimm); | |
| 305 | + return; | |
| 306 | + case TOK_ASM_call: | |
| 307 | + /* auipc ra, 0 */ | |
| 308 | + greloca(cur_text_section, op.e.sym, ind, R_RISCV_CALL, 0); | |
| 309 | + asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(1)); | |
| 310 | + /* jalr zero, 0(ra) */ | |
| 311 | + asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(1)); | |
| 312 | + return; | |
| 313 | + case TOK_ASM_tail: | |
| 314 | + /* auipc x6, 0 */ | |
| 315 | + greloca(cur_text_section, op.e.sym, ind, R_RISCV_CALL, 0); | |
| 316 | + asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(6)); | |
| 317 | + /* jalr zero, 0(x6) */ | |
| 318 | + asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(6)); | |
| 319 | + return; | |
| 320 | + | |
| 294 | 321 | /* C extension */ |
| 295 | 322 | case TOK_ASM_c_j: |
| 296 | 323 | asm_emit_cj(token, 1 | (5 << 13), &op); |
| @@ -299,10 +326,10 @@ static void asm_unary_opcode(TCCState *s1, int token) · 2 unmodified lines | ||
| 299 | 326 | asm_emit_cj(token, 1 | (1 << 13), &op); |
| 300 | 327 | return; |
| 301 | 328 | case TOK_ASM_c_jalr: |
| 302 | − asm_emit_cr(token, 2 | (9 << 12), &op, &nil); | |
| 329 | + asm_emit_cr(token, 2 | (9 << 12), &op, &zero); | |
| 303 | 330 | return; |
| 304 | 331 | case TOK_ASM_c_jr: |
| 305 | − asm_emit_cr(token, 2 | (8 << 12), &op, &nil); | |
| 332 | + asm_emit_cr(token, 2 | (8 << 12), &op, &zero); | |
| 306 | 333 | return; |
| 307 | 334 | default: |
| 308 | 335 | expect("unary instruction"); |
| @@ -331,6 +358,8 @@ static void asm_emit_u(int token, uint32_t opcode, const Operand* rd, const Oper · 22 unmodified lines | ||
| 331 | 358 | |
| 332 | 359 | static void asm_binary_opcode(TCCState* s1, int token) |
| 333 | 360 | { |
| 361 | + static const Operand zero = {.type = OP_REG, .reg = 0}; | |
| 362 | + Operand imm = {.type = OP_IM12S, .e = {.v = 0}}; | |
| 334 | 363 | Operand ops[2]; |
| 335 | 364 | parse_operands(s1, &ops[0], 2); |
| 336 | 365 | |
| @@ -452,6 +481,110 @@ static void asm_binary_opcode(TCCState* s1, int token) · 115 unmodified lines | ||
| 452 | 481 | /* addi rd, rd, 0 */ |
| 453 | 482 | asm_emit_i(token, 3 | (4 << 2), ops, ops, ops + 1); |
| 454 | 483 | return; |
| 484 | + case TOK_ASM_li: | |
| 485 | + if(ops[1].type != OP_IM32 && ops[1].type != OP_IM12S){ | |
| 486 | + tcc_error("'%s': Expected first source operand that is an immediate value between 0 and 0xFFFFFFFFFFFFFFFF", get_tok_str(token, NULL)); | |
| 487 | + } | |
| 488 | + int32_t lo = ops[1].e.v; | |
| 489 | + uint32_t hi = (int64_t)ops[1].e.v >> 32; | |
| 490 | + if(lo < 0){ | |
| 491 | + hi += 1; | |
| 492 | + } | |
| 493 | + imm.e.v = ((hi + 0x800) & 0xfffff000) >> 12; | |
| 494 | + /* lui rd, HI_20(HI_32(imm)) */ | |
| 495 | + asm_emit_u(token, (0xD << 2) | 3, &ops[0], &imm); | |
| 496 | + /* addi rd, rd, LO_12(HI_32(imm)) */ | |
| 497 | + imm.e.v = (int32_t)hi<<20>>20; | |
| 498 | + asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm); | |
| 499 | + /* slli rd, rd, 12 */ | |
| 500 | + imm.e.v = 12; | |
| 501 | + asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[0], &imm); | |
| 502 | + /* addi rd, rd, HI_12(LO_32(imm)) */ | |
| 503 | + imm.e.v = (lo + (1<<19)) >> 20; | |
| 504 | + asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm); | |
| 505 | + /* slli rd, rd, 12 */ | |
| 506 | + imm.e.v = 12; | |
| 507 | + asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[0], &imm); | |
| 508 | + /* addi rd, rd, HI_12(LO_20(LO_32imm)) */ | |
| 509 | + lo = lo << 12 >> 12; | |
| 510 | + imm.e.v = lo >> 8; | |
| 511 | + asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm); | |
| 512 | + /* slli rd, rd, 8 */ | |
| 513 | + imm.e.v = 8; | |
| 514 | + asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[0], &imm); | |
| 515 | + /* addi rd, rd, LO_8(LO_20(LO_32imm)) */ | |
| 516 | + lo &= 0xff; | |
| 517 | + imm.e.v = lo << 20 >> 20; | |
| 518 | + asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm); | |
| 519 | + return; | |
| 520 | + case TOK_ASM_mv: | |
| 521 | + /* addi rd, rs, 0 */ | |
| 522 | + asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[1], &imm); | |
| 523 | + return; | |
| 524 | + case TOK_ASM_not: | |
| 525 | + /* xori rd, rs, -1 */ | |
| 526 | + imm.e.v = -1; | |
| 527 | + asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &imm); | |
| 528 | + return; | |
| 529 | + case TOK_ASM_neg: | |
| 530 | + /* sub rd, x0, rs */ | |
| 531 | + imm.e.v = 1; | |
| 532 | + asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm); | |
| 533 | + return; | |
| 534 | + case TOK_ASM_negw: | |
| 535 | + /* sub rd, x0, rs */ | |
| 536 | + imm.e.v = 1; | |
| 537 | + asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm); | |
| 538 | + return; | |
| 539 | + case TOK_ASM_jump: | |
| 540 | + /* auipc x5, 0 */ | |
| 541 | + asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(5)); | |
| 542 | + greloca(cur_text_section, ops->e.sym, ind, R_RISCV_CALL, 0); | |
| 543 | + /* jalr zero, 0(x5) */ | |
| 544 | + asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(5)); | |
| 545 | + return; | |
| 546 | + case TOK_ASM_seqz: | |
| 547 | + /* sltiu rd, rs, 1 */ | |
| 548 | + imm.e.v = 1; | |
| 549 | + asm_emit_i(token, (0x4 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &imm); | |
| 550 | + return; | |
| 551 | + case TOK_ASM_snez: | |
| 552 | + /* sltu rd, zero, rs */ | |
| 553 | + imm.e.v = 1; | |
| 554 | + asm_emit_r(token, (0xC << 2) | 3 | (3 << 12), &ops[0], &zero, &ops[1]); | |
| 555 | + return; | |
| 556 | + case TOK_ASM_sltz: | |
| 557 | + /* slt rd, rs, zero */ | |
| 558 | + asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &ops[1], &zero); | |
| 559 | + return; | |
| 560 | + case TOK_ASM_sgtz: | |
| 561 | + /* slt rd, zero, rs */ | |
| 562 | + asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]); | |
| 563 | + return; | |
| 564 | + case TOK_ASM_bnez: | |
| 565 | + /* bne rs, zero, offset */ | |
| 566 | + asm_emit_b(token, 0x63 | (1 << 12), &ops[0], &zero, &ops[1]); | |
| 567 | + return; | |
| 568 | + case TOK_ASM_beqz: | |
| 569 | + /* bne rs, zero, offset */ | |
| 570 | + asm_emit_b(token, 0x63 | (0 << 12), &ops[0], &zero, &ops[1]); | |
| 571 | + return; | |
| 572 | + case TOK_ASM_blez: | |
| 573 | + /* bge rs, zero, offset */ | |
| 574 | + asm_emit_b(token, 0x63 | (5 << 12), &ops[0], &zero, &ops[1]); | |
| 575 | + return; | |
| 576 | + case TOK_ASM_bgez: | |
| 577 | + /* bge zero, rs, offset */ | |
| 578 | + asm_emit_b(token, 0x63 | (5 << 12), &zero, &ops[0], &ops[1]); | |
| 579 | + return; | |
| 580 | + case TOK_ASM_bltz: | |
| 581 | + /* blt rs, zero, offset */ | |
| 582 | + asm_emit_b(token, 0x63 | (4 << 12), &ops[0], &zero, &ops[1]); | |
| 583 | + return; | |
| 584 | + case TOK_ASM_bgtz: | |
| 585 | + /* blt zero, rs, offset */ | |
| 586 | + asm_emit_b(token, 0x63 | (4 << 12), &zero, &ops[0], &ops[1]); | |
| 587 | + return; | |
| 455 | 588 | |
| 456 | 589 | default: |
| 457 | 590 | expect("binary instruction"); |
| @@ -549,8 +682,23 @@ static void asm_mem_access_opcode(TCCState *s1, int token) · 91 unmodified lines | ||
| 549 | 682 | Operand ops[3]; |
| 550 | 683 | parse_mem_access_operands(s1, &ops[0]); |
| 551 | 684 | |
| 552 | − // l{b|h|w|d}[u] rd, imm(rs1); I-format | |
| 685 | + /* Pseudoinstruction: inst reg, label | |
| 686 | + * expand to: | |
| 687 | + * auipc reg, 0 | |
| 688 | + * inst reg, 0(reg) | |
| 689 | + * And with the proper relocation to label | |
| 690 | + */ | |
| 691 | + if (ops[1].type == OP_IM32 && ops[1].e.sym && ops[1].e.sym->type.t & VT_STATIC){ | |
| 692 | + ops[1] = ops[0]; | |
| 693 | + /* set the offset to zero */ | |
| 694 | + ops[2].type = OP_IM12S; | |
| 695 | + ops[2].e.v = 0; | |
| 696 | + /* auipc reg, 0 */ | |
| 697 | + asm_emit_u(token, (0x05 << 2) | 3, &ops[0], &ops[2]); | |
| 698 | + } | |
| 699 | + | |
| 553 | 700 | switch (token) { |
| 701 | + // l{b|h|w|d}[u] rd, imm(rs1); I-format | |
| 554 | 702 | case TOK_ASM_lb: |
| 555 | 703 | asm_emit_i(token, (0x0 << 2) | 3, &ops[0], &ops[1], &ops[2]); |
| 556 | 704 | return; |
| @@ -713,6 +861,19 @@ static void asm_ternary_opcode(TCCState *s1, int token) · 156 unmodified lines | ||
| 713 | 861 | case TOK_ASM_bgeu: |
| 714 | 862 | asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2); |
| 715 | 863 | return; |
| 864 | + /* related pseudoinstructions */ | |
| 865 | + case TOK_ASM_bgt: | |
| 866 | + asm_emit_b(token, 0x63 | (4 << 12), ops + 1, ops, ops + 2); | |
| 867 | + return; | |
| 868 | + case TOK_ASM_ble: | |
| 869 | + asm_emit_b(token, 0x63 | (5 << 12), ops + 1, ops, ops + 2); | |
| 870 | + return; | |
| 871 | + case TOK_ASM_bgtu: | |
| 872 | + asm_emit_b(token, 0x63 | (6 << 12), ops + 1, ops, ops + 2); | |
| 873 | + return; | |
| 874 | + case TOK_ASM_bleu: | |
| 875 | + asm_emit_b(token, 0x63 | (7 << 12), ops + 1, ops, ops + 2); | |
| 876 | + return; | |
| 716 | 877 | |
| 717 | 878 | /* M extension */ |
| 718 | 879 | case TOK_ASM_div: |
| @@ -1030,14 +1191,44 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 311 unmodified lines | ||
| 1030 | 1191 | |
| 1031 | 1192 | /* pseudoinstructions */ |
| 1032 | 1193 | case TOK_ASM_nop: |
| 1194 | + case TOK_ASM_ret: | |
| 1033 | 1195 | asm_nullary_opcode(s1, token); |
| 1034 | 1196 | return; |
| 1035 | 1197 | |
| 1198 | + case TOK_ASM_jr: | |
| 1199 | + case TOK_ASM_call: | |
| 1200 | + case TOK_ASM_tail: | |
| 1201 | + asm_unary_opcode(s1, token); | |
| 1202 | + return; | |
| 1203 | + | |
| 1036 | 1204 | case TOK_ASM_la: |
| 1037 | 1205 | case TOK_ASM_lla: |
| 1206 | + case TOK_ASM_li: | |
| 1207 | + case TOK_ASM_jump: | |
| 1208 | + case TOK_ASM_seqz: | |
| 1209 | + case TOK_ASM_snez: | |
| 1210 | + case TOK_ASM_sltz: | |
| 1211 | + case TOK_ASM_sgtz: | |
| 1212 | + case TOK_ASM_bnez: | |
| 1213 | + case TOK_ASM_beqz: | |
| 1214 | + case TOK_ASM_blez: | |
| 1215 | + case TOK_ASM_bgez: | |
| 1216 | + case TOK_ASM_bltz: | |
| 1217 | + case TOK_ASM_bgtz: | |
| 1218 | + case TOK_ASM_mv: | |
| 1219 | + case TOK_ASM_not: | |
| 1220 | + case TOK_ASM_neg: | |
| 1221 | + case TOK_ASM_negw: | |
| 1038 | 1222 | asm_binary_opcode(s1, token); |
| 1039 | 1223 | return; |
| 1040 | 1224 | |
| 1225 | + case TOK_ASM_bgt: | |
| 1226 | + case TOK_ASM_bgtu: | |
| 1227 | + case TOK_ASM_ble: | |
| 1228 | + case TOK_ASM_bleu: | |
| 1229 | + asm_ternary_opcode(s1, token); | |
| 1230 | + return; | |
| 1231 | + | |
| 1041 | 1232 | default: |
| 1042 | 1233 | expect("known instruction"); |
| 1043 | 1234 | } |
| @@ -393,6 +393,8 @@ · 392 unmodified lines | ||
| 393 | 393 | DEF_ASM(fsd) |
| 394 | 394 | DEF_ASM(fsw) |
| 395 | 395 | DEF_ASM(j) |
| 396 | + DEF_ASM(jump) | |
| 397 | + DEF_ASM(jr) | |
| 396 | 398 | DEF_ASM(la) |
| 397 | 399 | DEF_ASM(li) |
| 398 | 400 | DEF_ASM(lla) |