authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-10 21:54:23+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-11 19:38:00+02:00
logf05e09a0cf7870fda463d9a0ceb42be4c3100825
tree858b5107d90a97392b5765a318672b276531feb7
parent18afcc34c61a18ada7bda0fc50f48e929866ab82

wasm: optimize & simplify sign extension

Rather than storing all the shifts in temporaries, we perform the correct shifting without temporaries. This makes the runtime code more performant and also the backend code is simplified as we have a singular abstraction.

1 files changed, 12 insertions(+), 39 deletions(-)

src/arch/wasm/CodeGen.zig+12-39
...@@ -4162,22 +4162,14 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W...@@ -4162,22 +4162,14 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
4162 64 => WValue{ .imm64 = 0 },4162 64 => WValue{ .imm64 = 0 },
4163 else => unreachable,4163 else => unreachable,
4164 };4164 };
4165 const shift_amt = wasm_bits - int_info.bits;
4166 const shift_val = switch (wasm_bits) {
4167 32 => WValue{ .imm32 = shift_amt },
4168 64 => WValue{ .imm64 = shift_amt },
4169 else => unreachable,
4170 };
41714165
4172 // for signed integers, we first apply signed shifts by the difference in bits4166 // for signed integers, we first apply signed shifts by the difference in bits
4173 // to get the signed value, as we store it internally as 2's complement.4167 // to get the signed value, as we store it internally as 2's complement.
4174 const lhs = if (wasm_bits != int_info.bits and is_signed) blk: {4168 const lhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4175 const shl = try self.binOp(lhs_op, shift_val, lhs_ty, .shl);4169 break :blk try self.signAbsValue(lhs_op, lhs_ty);
4176 break :blk try self.binOp(shl, shift_val, lhs_ty, .shr);
4177 } else lhs_op;4170 } else lhs_op;
4178 const rhs = if (wasm_bits != int_info.bits and is_signed) blk: {4171 const rhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4179 const shl = try self.binOp(rhs_op, shift_val, lhs_ty, .shl);4172 break :blk try self.signAbsValue(rhs_op, lhs_ty);
4180 break :blk try self.binOp(shl, shift_val, lhs_ty, .shr);
4181 } else rhs_op;4173 } else rhs_op;
41824174
4183 const bin_op = try self.binOp(lhs, rhs, lhs_ty, op);4175 const bin_op = try self.binOp(lhs, rhs, lhs_ty, op);
...@@ -4192,9 +4184,8 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W...@@ -4192,9 +4184,8 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
4192 const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt);4184 const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt);
4193 break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor); // result of cmp_zero and lt is always 32bit4185 break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor); // result of cmp_zero and lt is always 32bit
4194 }4186 }
4195 const shl = try self.binOp(bin_op, shift_val, lhs_ty, .shl);4187 const abs = try self.signAbsValue(bin_op, lhs_ty);
4196 const shr = try self.binOp(shl, shift_val, lhs_ty, .shr);4188 break :blk try self.cmp(abs, bin_op, lhs_ty, .neq);
4197 break :blk try self.cmp(shr, bin_op, lhs_ty, .neq);
4198 } else if (wasm_bits == int_info.bits)4189 } else if (wasm_bits == int_info.bits)
4199 try self.cmp(bin_op, lhs, lhs_ty, cmp_op)4190 try self.cmp(bin_op, lhs, lhs_ty, cmp_op)
4200 else4191 else
...@@ -4289,17 +4280,9 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4289,17 +4280,9 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4289 } else shl;4280 } else shl;
42904281
4291 const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: {4282 const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: {
4292 const shift_amt = wasm_bits - int_info.bits;4283 const abs = try self.signAbsValue(shl, lhs_ty);
4293 const shift_val = switch (wasm_bits) {4284 const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr);
4294 32 => WValue{ .imm32 = shift_amt },4285 break :blk try self.cmp(lhs, wrapped, lhs_ty, .neq);
4295 64 => WValue{ .imm64 = shift_amt },
4296 else => unreachable,
4297 };
4298
4299 const secondary_shl = try self.binOp(shl, shift_val, lhs_ty, .shl);
4300 const initial_shr = try self.binOp(secondary_shl, shift_val, lhs_ty, .shr);
4301 const shr = try self.wrapBinOp(initial_shr, rhs, lhs_ty, .shr);
4302 break :blk try self.cmp(lhs, shr, lhs_ty, .neq);
4303 } else blk: {4286 } else blk: {
4304 const shr = try self.binOp(result, rhs, lhs_ty, .shr);4287 const shr = try self.binOp(result, rhs, lhs_ty, .shr);
4305 break :blk try self.cmp(lhs, shr, lhs_ty, .neq);4288 break :blk try self.cmp(lhs, shr, lhs_ty, .neq);
...@@ -4367,21 +4350,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4367,21 +4350,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4367 break :blk down_cast;4350 break :blk down_cast;
4368 }4351 }
4369 } else if (int_info.signedness == .signed) blk: {4352 } else if (int_info.signedness == .signed) blk: {
4370 const shift_imm = if (wasm_bits == 32)4353 const lhs_abs = try self.signAbsValue(lhs, lhs_ty);
4371 WValue{ .imm32 = wasm_bits - int_info.bits }4354 const rhs_abs = try self.signAbsValue(rhs, lhs_ty);
4372 else4355 const bin_op = try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul);
4373 WValue{ .imm64 = wasm_bits - int_info.bits };4356 const mul_abs = try self.signAbsValue(bin_op, lhs_ty);
43744357 const cmp_op = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);
4375 const lhs_shl = try self.binOp(lhs, shift_imm, lhs_ty, .shl);
4376 const lhs_shr = try self.binOp(lhs_shl, shift_imm, lhs_ty, .shr);
4377 const rhs_shl = try self.binOp(rhs, shift_imm, lhs_ty, .shl);
4378 const rhs_shr = try self.binOp(rhs_shl, shift_imm, lhs_ty, .shr);
4379
4380 const bin_op = try self.binOp(lhs_shr, rhs_shr, lhs_ty, .mul);
4381 const shl = try self.binOp(bin_op, shift_imm, lhs_ty, .shl);
4382 const shr = try self.binOp(shl, shift_imm, lhs_ty, .shr);
4383
4384 const cmp_op = try self.cmp(shr, bin_op, lhs_ty, .neq);
4385 try self.emitWValue(cmp_op);4358 try self.emitWValue(cmp_op);
4386 try self.addLabel(.local_set, overflow_bit.local);4359 try self.addLabel(.local_set, overflow_bit.local);
4387 break :blk try self.wrapOperand(bin_op, lhs_ty);4360 break :blk try self.wrapOperand(bin_op, lhs_ty);