History

riscv64-asm: implement far branches via expansion

For branch targets that are external/static symbols (where the offset cannot be determined at assembly time), expand to: b<inverse> .+8 # skip if condition false auipc t0, %pcrel_hi # load target upper bits jalr x0, %pcrel_lo(t0) # jump This handles the ±4 KiB B-type limitation without requiring linker relaxation (R_RISCV_RELAX). Local immediates within range still use the compact B-type encoding.

Meng Zhuo committed 6 months ago

Commit 419b5271 parent 5c2240a1 file · +23 −5Browse files

Unified · Split

riscv64-asm.c+23−5
@@ -247,11 +247,9 @@ static void parse_branch_offset_operand(TCCState *s1, Operand *op){ · 246 unmodified lines
247 if ((int) op->e.v >= -0x1000 && (int) op->e.v < 0x1000)247 if ((int) op->e.v >= -0x1000 && (int) op->e.v < 0x1000)
248 op->type = OP_IM12S;248 op->type = OP_IM12S;
249 } else if (op->e.sym->type.t & (VT_EXTERN | VT_STATIC)) {249 } else if (op->e.sym->type.t & (VT_EXTERN | VT_STATIC)) {
250 greloca(cur_text_section, op->e.sym, ind, R_RISCV_BRANCH, 0);250 /* For extern/static symbols, always use far-branch expansion
251 251 since linker relaxation (R_RISCV_RELAX) is not implemented. */
252 /* XXX: Implement far branches */252 op->type = OP_IM32;
253
254 op->type = OP_IM12S;
255 op->e.v = 0;253 op->e.v = 0;
256 } else {254 } else {
257 expect("operand");255 expect("operand");
@@ -1384,6 +1382,26 @@ static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Ope · 1126 unmodified lines
1384 if (rs2->type != OP_REG) {1382 if (rs2->type != OP_REG) {
1385 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));1383 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1386 }1384 }
1385 if (imm->type == OP_IM32 && imm->e.sym) {
1386 /* far branch: expand to inverted short branch + auipc + jalr */
1387 int b_ofs = ind;
1388 uint32_t inv_func3 = ((opcode >> 12) & 7) ^ 1;
1389 uint32_t inv_opcode = (opcode & ~(7 << 12)) | (inv_func3 << 12);
1390 /* b<inverse> .+8 */
1391 asm_emit_opcode(inv_opcode | ENCODE_RS1(rs1->reg)
1392 | ENCODE_RS2(rs2->reg) | (1 << 8));
1393 /* auipc t0, 0 */
1394 greloca(cur_text_section, imm->e.sym, ind, R_RISCV_CALL, 0);
1395 asm_emit_opcode(0x17 | ENCODE_RD(5));
1396 /* jalr x0, 0(t0) */
1397 write32le(cur_text_section->data + b_ofs,
1398 read32le(cur_text_section->data + b_ofs)
1399 | (((ind - b_ofs) >> 1) & 0xf) << 8
1400 | (((ind - b_ofs) >> 5) & 0x3f) << 25
1401 | (((ind - b_ofs) >> 11) & 1) << 7
1402 | (((ind - b_ofs) >> 12) & 1) << 31);
1403 return;
1404 }
1387 if (imm->type != OP_IM12S) {1405 if (imm->type != OP_IM12S) {
1388 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));1406 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
1389 }1407 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t