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 | asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20)); | 152 | asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20)); |
| 153 | return; | 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 | /* C extension */ | 161 | /* C extension */ |
| 156 | case TOK_ASM_c_ebreak: | 162 | case TOK_ASM_c_ebreak: |
| 157 | asm_emit_cr(token, 2 | (9 << 12), &nil, &nil); | 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 | uint32_t opcode = (0x1C << 2) | 3 | (2 << 12); | 272 | uint32_t opcode = (0x1C << 2) | 3 | (2 << 12); |
| 267 | Operand op; | 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 | parse_operands(s1, &op, 1); | 277 | parse_operands(s1, &op, 1); |
| 271 | /* Note: Those all map to CSR--so they are pseudo-instructions. */ | 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 | case TOK_ASM_rdinstreth: | 298 | case TOK_ASM_rdinstreth: |
| 292 | asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg)); | 299 | asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg)); |
| 293 | return; | 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 | /* C extension */ | 321 | /* C extension */ |
| 295 | case TOK_ASM_c_j: | 322 | case TOK_ASM_c_j: |
| 296 | asm_emit_cj(token, 1 | (5 << 13), &op); | 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 | asm_emit_cj(token, 1 | (1 << 13), &op); | 326 | asm_emit_cj(token, 1 | (1 << 13), &op); |
| 300 | return; | 327 | return; |
| 301 | case TOK_ASM_c_jalr: | 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 | return; | 330 | return; |
| 304 | case TOK_ASM_c_jr: | 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 | return; | 333 | return; |
| 307 | default: | 334 | default: |
| 308 | expect("unary instruction"); | 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 | static void asm_binary_opcode(TCCState* s1, int token) | 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 | Operand ops[2]; | 363 | Operand ops[2]; |
| 335 | parse_operands(s1, &ops[0], 2); | 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 | /* addi rd, rd, 0 */ | 481 | /* addi rd, rd, 0 */ |
| 453 | asm_emit_i(token, 3 | (4 << 2), ops, ops, ops + 1); | 482 | asm_emit_i(token, 3 | (4 << 2), ops, ops, ops + 1); |
| 454 | return; | 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 | default: | 589 | default: |
| 457 | expect("binary instruction"); | 590 | expect("binary instruction"); |
| @@ -549,8 +682,23 @@ static void asm_mem_access_opcode(TCCState *s1, int token) · 91 unmodified lines | |||
| 549 | Operand ops[3]; | 682 | Operand ops[3]; |
| 550 | parse_mem_access_operands(s1, &ops[0]); | 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 | switch (token) { | 700 | switch (token) { |
| 701 | // l{b|h|w|d}[u] rd, imm(rs1); I-format | ||
| 554 | case TOK_ASM_lb: | 702 | case TOK_ASM_lb: |
| 555 | asm_emit_i(token, (0x0 << 2) | 3, &ops[0], &ops[1], &ops[2]); | 703 | asm_emit_i(token, (0x0 << 2) | 3, &ops[0], &ops[1], &ops[2]); |
| 556 | return; | 704 | return; |
| @@ -713,6 +861,19 @@ static void asm_ternary_opcode(TCCState *s1, int token) · 156 unmodified lines | |||
| 713 | case TOK_ASM_bgeu: | 861 | case TOK_ASM_bgeu: |
| 714 | asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2); | 862 | asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2); |
| 715 | return; | 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 | /* M extension */ | 878 | /* M extension */ |
| 718 | case TOK_ASM_div: | 879 | case TOK_ASM_div: |
| @@ -1030,14 +1191,44 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 311 unmodified lines | |||
| 1030 | 1191 | ||
| 1031 | /* pseudoinstructions */ | 1192 | /* pseudoinstructions */ |
| 1032 | case TOK_ASM_nop: | 1193 | case TOK_ASM_nop: |
| 1194 | case TOK_ASM_ret: | ||
| 1033 | asm_nullary_opcode(s1, token); | 1195 | asm_nullary_opcode(s1, token); |
| 1034 | return; | 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 | case TOK_ASM_la: | 1204 | case TOK_ASM_la: |
| 1037 | case TOK_ASM_lla: | 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 | asm_binary_opcode(s1, token); | 1222 | asm_binary_opcode(s1, token); |
| 1039 | return; | 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 | default: | 1232 | default: |
| 1042 | expect("known instruction"); | 1233 | expect("known instruction"); |
| 1043 | } | 1234 | } |
| @@ -393,6 +393,8 @@ · 392 unmodified lines | |||
| 393 | DEF_ASM(fsd) | 393 | DEF_ASM(fsd) |
| 394 | DEF_ASM(fsw) | 394 | DEF_ASM(fsw) |
| 395 | DEF_ASM(j) | 395 | DEF_ASM(j) |
| 396 | DEF_ASM(jump) | ||
| 397 | DEF_ASM(jr) | ||
| 396 | DEF_ASM(la) | 398 | DEF_ASM(la) |
| 397 | DEF_ASM(li) | 399 | DEF_ASM(li) |
| 398 | DEF_ASM(lla) | 400 | DEF_ASM(lla) |