Skip to content

Zijf (Far jumps and calls)#3269

Draft
Andrew Waterman (aswaterman) wants to merge 3 commits into
mainfrom
zijfal
Draft

Zijf (Far jumps and calls)#3269
Andrew Waterman (aswaterman) wants to merge 3 commits into
mainfrom
zijfal

Conversation

@aswaterman

Copy link
Copy Markdown
Member

This proposed extension adds two new instructions, JF (Jump Far) and JFAL (Jump Far and Link), which improve code density and performance for large programs by replacing a 64-bit AUIPC+JALR sequence with a single 32-bit instruction.

Signed-off-by: Andrew Waterman <andrew@sifive.com>
Signed-off-by: Andrew Waterman <andrew@sifive.com>
@github-actions

Copy link
Copy Markdown
:warning: DCO CHECK FAILED :warning:

The Developer's Certificate of Origin (DCO) check has failed for this pull request.
To fix this, you need to sign off on your commits.

For instructions on how to set up signed commits, please see:
https://github.com/riscv/docs-spec-template/blob/main/CONTRIBUTING.md

Once you have signed your commits, you will need to force-push your changes.

@wangpc-pp

Copy link
Copy Markdown

Some questions here:

  1. We had some discussions in https://lists.riscv.org/g/tech-unprivileged/topic/119028439 and the conclusion is:

Note that fusion of an AUIPC/JALR (or LUI/JALR) instruction pair provides a much larger jump range. Even without fusion, this code idiom is the standard way to encode a larger jump range. But without recognizing this idiom as a "far" JAL that doesn't need to use an indirect branch predictor, then one gets the extra pressure on your indirect branch predictor.

Redefining the existing JAL is not on the table for compatibility reasons. There are proposals to add 48-bit instructions that have greater displacement than JAL (32-ish bits), and proposals to add 32-bit instructions that have slightly greater displacement than JAL (24-ish bits). But even if these proposals eventually go through, they are not of use for implementations being developed now, so I'd follow Greg's advice and optimize AUIPC/JALR.

  1. According to our profiling of ByteDance's applications, we need at least a 28 bits displacement to cover 90% scenarios. The JAL/JALR have already covered about 62%, and 23 bits/24 bits only covers about 70%/72%.
  2. Do we have a prototype to show the gains of code size and performance?

@aswaterman

Andrew Waterman (aswaterman) commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

Thanks for chiming in Pengcheng Wang (@wangpc-pp).

An additional 10% coverage is material, even if not earth-shattering.

To do any better we will need longer instructions. Doing as much as we can within the 32-bit encoding space is useful even if we eventually have 48-bit jump instructions, since these instructions are denser.

Also note that even implementations that optimize the AUIPC+JALR fusion pair will benefit from this extension, because of reduced code size and because a physical register allocation is skipped in the JF case.

Comment thread src/unpriv/zijf.adoc
insn:jfal[] writes the address of the instruction following the
jump (`pc` + 4) into register `x1`.
Then, insn:jfal[] sets the `pc` to `pc` + `offset`.
insn:jfal[] can target a range of qty:±16[MiB].

@Wren6991 Luke Wren (Wren6991) Jul 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The range +- 1 MiB is redundant with the existing jal. This range is easily decoded: bits 31, 19, 14, 13, 11 are either all-zeroes or all-ones.

Should these encodings be marked as reserved or are they allocated for jfal?

Similar point applies to jf with bits 31, 19, 13, 11.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see it being simpler for the tools to not have to patch the opcode during relaxation.

To put some numbers to it: there are 2^21 redundant opcodes in total, which costs the sames as 64 new R-type instructions, or 1/2 of a new I-type.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Luke Wren (@Wren6991) It's a valid point. We had been approaching this from a different angle--we were looking at the possibility of expanding the ranges of the two instructions to ±9 MiB and ±17 MiB--but found that choice to be awkward.

I agree we should at least consider reserving the redundant cases, but if we do so, we might want to change the immediate encoding so that the high-order immediate bits are in a less inconvenient place. (Right now they overlap the rs1 and rd register specifiers.)

Anyway, we'll think about it.

@Wren6991 Luke Wren (Wren6991) Jul 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now they overlap the rs1 and rd register specifiers

It varies a bit. When 31, 14 (jfal only) and 13 are not all alike, you have completely free choice over rs1, rs2 and rd. That's half of the jf and three quarters of the jfal encoding space, so 40 clean R-types. Sorry, I had this backwards. The redundant opcodes have those bits all alike.

You're right though, I missed that, and maybe it could be avoided altogether with some shuffling.

@brucehoult

Copy link
Copy Markdown
Contributor

Why not make the target of these instructions address be a multiple of 16 or 64 bytes? That would increase the range from 16MB to 128MB or 512MB.

If someone is worried about the performance overhead of (LUI/AUIPC)+JALR then they are probably also prepared to align those important target addresses at least a little.

You'd need to discard the low bits of the PC before/after adding the offset.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants