mirror of
https://github.com/ziglang/zig.git
synced 2026-01-02 11:33:21 +00:00
wasm: Use 'select' instruction for max/min
Rather than using blocks and control flow to check which operand is the maximum or minimum, we use wasm's `select` instruction which returns us the operand based on a result from a comparison. This saves us the need of control flow, as well as reduce the instruction count from 13 to 7.
This commit is contained in:
parent
5fafcc2b62
commit
ac873367b9
@ -3889,27 +3889,26 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro
|
||||
const lhs = try self.resolveInst(bin_op.lhs);
|
||||
const rhs = try self.resolveInst(bin_op.rhs);
|
||||
|
||||
const result = try self.allocLocal(ty);
|
||||
|
||||
try self.startBlock(.block, wasm.block_empty);
|
||||
try self.startBlock(.block, wasm.block_empty);
|
||||
|
||||
// check if LHS is greater/lesser than RHS
|
||||
const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
|
||||
try self.addLabel(.local_get, cmp_result.local);
|
||||
try self.addLabel(.br_if, 0); // break to outer loop if LHS is greater/lesser than RHS
|
||||
|
||||
// set RHS as max/min
|
||||
try self.emitWValue(rhs);
|
||||
try self.addLabel(.local_set, result.local);
|
||||
try self.addLabel(.br, 1); // break out of all blocks
|
||||
try self.endBlock();
|
||||
|
||||
// set LHS as max/min
|
||||
// operands to select from
|
||||
try self.emitWValue(lhs);
|
||||
try self.addLabel(.local_set, result.local);
|
||||
try self.endBlock();
|
||||
try self.emitWValue(rhs);
|
||||
|
||||
// operands to compare
|
||||
try self.emitWValue(lhs);
|
||||
try self.emitWValue(rhs);
|
||||
const opcode = buildOpcode(.{
|
||||
.op = if (op == .max) .gt else .lt,
|
||||
.signedness = if (ty.isSignedInt()) .signed else .unsigned,
|
||||
.valtype1 = typeToValtype(ty, self.target),
|
||||
});
|
||||
try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
|
||||
|
||||
// based on the result from comparison, return operand 0 or 1.
|
||||
try self.addTag(.select);
|
||||
|
||||
// store result in local
|
||||
const result = try self.allocLocal(ty);
|
||||
try self.addLabel(.local_set, result.local);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -96,6 +96,8 @@ pub fn emitMir(emit: *Emit) InnerError!void {
|
||||
.@"return" => try emit.emitTag(tag),
|
||||
.@"unreachable" => try emit.emitTag(tag),
|
||||
|
||||
.select => try emit.emitTag(tag),
|
||||
|
||||
// arithmetic
|
||||
.i32_eqz => try emit.emitTag(tag),
|
||||
.i32_eq => try emit.emitTag(tag),
|
||||
|
||||
@ -77,6 +77,10 @@ pub const Inst = struct {
|
||||
///
|
||||
/// Uses `label`
|
||||
call_indirect = 0x11,
|
||||
/// Pops three values from the stack and pushes
|
||||
/// the first or second value dependent on the third value.
|
||||
/// Uses `tag`
|
||||
select = 0x1B,
|
||||
/// Loads a local at given index onto the stack.
|
||||
///
|
||||
/// Uses `label`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user