Skip to content

Cranelift: simplify opcode set by removing "flags" values and producers/consumers #3249

Open
@cfallin

Description

@cfallin

In #3233 we discussed various simplifications we could perform to reduce the number of CLIF opcodes that exist. In general, we should strive for simplicity -- fewer opcodes mean less cost for every consumer of the IR -- as long as simplifications don't impose other overheads, such as unnecessary expansion and pattern-matching.

The "flags"-related opcodes, such as ifcmp / ffcmp, brif / brff, trapif / trapff, and those that communicate carry/borrow flags via the full flags value, seem to be good candidates for removal. This is for at least a few reasons:

  • A flag value behaves differently than most others in the IR, and as such, imposes complexity cost. For example, only one flag value may be live at a time. This constraint, enforced by the validator, is meant to allow the flags value to be directly lowered onto a machine's CPU flags register, but our backends no longer work this way. For another example, a flag value cannot be stored/loaded to/from memory.
  • The flags do not have a well-defined value but rather serve as a sort of opaque connection between producer (e.g., a compare) and consumer (e.g., a branch). For example, a bitcast/raw-bitcast from a flag value to an integer is undefined (and disallowed by the validator).
  • There is redundancy in the instruction set, as some conditions can also be materialized as bools. For example, we have both iadd_carry, which produces the carry flag as a bool, and iadd_ifcout, which produces a flags value with the carry embedded in it.

With better pattern-matching in the backends (both as they stand today and potentially with a DSL to help as proposed in bytecodealliance/rfcs#15), it is less important for the CLIF to directly correspond to machine code; we can pattern-match a producer and consumer (e.g. a compare and a branch) that communicate via a b1 (bool) just as well as we can those that communicate via opaque flags values.

Thus, we should look into removing all uses of "flags" values, instead consuming the flags where they are produced to generate a bool condition as appropriate.

One downside of this approach is that we cannot directly express reuse of flags for more than one condition (e.g. ifcmp then multiple trueifs with multiple flag conditions). Potentially we could instead pattern-match on multiple compare instructions with the same arguments and merge them instead, so e.g. icmp ge v0, v1 and icmp eq v0, v1 become a comopare-setcc-setcc three-instruction sequence.

cc @abrown @afonso360 @bjorn3 from earlier discussion

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status

      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions