Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions runtime/src/ops/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,34 @@ impl Context {
from
}

pub fn jp(&mut self, from: Cont, x: Cont) -> Cont {
if self.cpu.flags.contains(Flags::PF) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

BTW, note that none of the operations that affect parity currently set this flag, so these instructions won't do the right thing 😬

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looking into it!

@evmar evmar Sep 10, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Parity is really annoying because in principle all the arithmetic operations compute it, and then it's almost never actually needed.

Originally what I did in retrowin32 was a hack where if the decoder saw a jp/jnp, it would panic if the previous instruction wasn't some specific thing, so then when it hit the jnp it could retroactively compute parity. (In both links I'm talking about the deleted code)

In my ideal world in theseus we could statically analyze the code enough that we would know when we actually need parity computation or not, similar to this hack but principled and covering all the cases. But I think until we hit that world, just computing parity always (like the added code in the above diff) is probably fine, and I can think of the static analysis thing as an optimization. (Lately I've been working on the static analysis bit of things, which is why I haven't committed to Theseus in a bit!)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think that Theseus is currently setting this flag at least in some cases? But I might be missing something. My game is using these instructions and seems to be working fully (which is amazing 🤩) so that would point towards that as well, but I'm not to familiar with the code base to say anything for sure yet 😅

https://github.com/search?q=repo%3Aevmar%2Ftheseus+flags.set%28Flags%3A%3APF&type=code

My agent did find another issue when looking into this, which I believe was already fixed later in my branch as well, sending a follow up PR for that now: #21

return x;
}
from
}

pub fn jnp(&mut self, from: Cont, x: Cont) -> Cont {
if !self.cpu.flags.contains(Flags::PF) {
return x;
}
from
}

pub fn jo(&mut self, from: Cont, x: Cont) -> Cont {
if self.cpu.flags.contains(Flags::OF) {
return x;
}
from
}

pub fn jno(&mut self, from: Cont, x: Cont) -> Cont {
if !self.cpu.flags.contains(Flags::OF) {
return x;
}
from
}

pub fn js(&mut self, from: Cont, x: Cont) -> Cont {
if self.cpu.flags.contains(Flags::SF) {
return x;
Expand Down
3 changes: 2 additions & 1 deletion tc/src/codegen/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ impl<'a> CodeGen<'a> {
bitness = self.module.bitness()
));
}
Je | Jne | Jb | Js | Jns | Ja | Jae | Jl | Jg | Jge | Jecxz | Jle | Jbe | Jcxz
Je | Jne | Jb | Js | Jns | Ja | Jae | Jl | Jg | Jge | Jecxz | Jle | Jbe | Jcxz | Jp
| Jnp | Jo | Jno
| Loop | Loopne => {
let next = self.resolve_jmp(instr.next_ip());
let (None, None, cont) = self.jmp_target(instr) else {
Expand Down