Merge pull request #8464 from gracefuu/grace/wasm-ops

stage2 wasm: Add division and bitwise/boolean ops &, |, ^, and, or
This commit is contained in:
Andrew Kelley 2021-04-08 13:41:49 -07:00 committed by GitHub
commit 9f744f19e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 126 additions and 1 deletions

View File

@ -3846,6 +3846,7 @@ fn analyzeArithmetic(
.subwrap => .subwrap,
.mul => .mul,
.mulwrap => .mulwrap,
.div => .div,
else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}''", .{@tagName(zir_tag)}),
};
@ -4161,7 +4162,7 @@ fn zirBoolBr(
_ = try rhs_block.addBr(src, block_inst, rhs_result);
const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) };
const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, rhs_block.instructions.items) };
const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, else_block.instructions.items) };
_ = try child_block.addCondBr(src, lhs, tzir_then_body, tzir_else_body);
block_inst.body = .{

View File

@ -855,6 +855,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.not => return self.genNot(inst.castTag(.not).?),
.mul => return self.genMul(inst.castTag(.mul).?),
.mulwrap => return self.genMulWrap(inst.castTag(.mulwrap).?),
.div => return self.genDiv(inst.castTag(.div).?),
.ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
.ref => return self.genRef(inst.castTag(.ref).?),
.ret => return self.genRet(inst.castTag(.ret).?),
@ -1092,6 +1093,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}
fn genDiv(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())
return MCValue.dead;
switch (arch) {
else => return self.fail(inst.base.src, "TODO implement div for {}", .{self.target.cpu.arch}),
}
}
fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())

View File

@ -632,6 +632,9 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
.mul => try genBinOp(o, inst.castTag(.sub).?, " * "),
// TODO make this do wrapping multiplication for signed ints
.mulwrap => try genBinOp(o, inst.castTag(.sub).?, " * "),
// TODO use a different strategy for div that communicates to the optimizer
// that wrapping is UB.
.div => try genBinOp(o, inst.castTag(.div).?, " / "),
.constant => unreachable, // excluded from function bodies
.alloc => try genAlloc(o, inst.castTag(.alloc).?),

View File

@ -657,6 +657,10 @@ pub const Context = struct {
.breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
.br => self.genBr(inst.castTag(.br).?),
.call => self.genCall(inst.castTag(.call).?),
.bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),
.bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),
.bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),
.bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),
.cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
.cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
.cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
@ -669,6 +673,8 @@ pub const Context = struct {
.load => self.genLoad(inst.castTag(.load).?),
.loop => self.genLoop(inst.castTag(.loop).?),
.mul => self.genBinOp(inst.castTag(.mul).?, .mul),
.div => self.genBinOp(inst.castTag(.div).?, .div),
.xor => self.genBinOp(inst.castTag(.xor).?, .xor),
.not => self.genNot(inst.castTag(.not).?),
.ret => self.genRet(inst.castTag(.ret).?),
.retvoid => WValue.none,
@ -764,6 +770,7 @@ pub const Context = struct {
const opcode: wasm.Opcode = buildOpcode(.{
.op = op,
.valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
.signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,
});
try self.code.append(wasm.opcode(opcode));
return .none;

View File

@ -115,6 +115,7 @@ pub const Inst = struct {
unreach,
mul,
mulwrap,
div,
not,
floatcast,
intcast,
@ -181,6 +182,7 @@ pub const Inst = struct {
.subwrap,
.mul,
.mulwrap,
.div,
.cmp_lt,
.cmp_lte,
.cmp_eq,
@ -752,6 +754,7 @@ const DumpTzir = struct {
.subwrap,
.mul,
.mulwrap,
.div,
.cmp_lt,
.cmp_lte,
.cmp_eq,
@ -891,6 +894,7 @@ const DumpTzir = struct {
.subwrap,
.mul,
.mulwrap,
.div,
.cmp_lt,
.cmp_lte,
.cmp_eq,

View File

@ -153,6 +153,106 @@ pub fn addCases(ctx: *TestContext) !void {
\\ return x * y;
\\}
, "350\n");
case.addCompareOutput(
\\export fn _start() u32 {
\\ var i: u32 = 352;
\\ i /= 7; // i = 50
\\ var result: u32 = foo(i, 7);
\\ return result;
\\}
\\fn foo(x: u32, y: u32) u32 {
\\ return x / y;
\\}
, "7\n");
case.addCompareOutput(
\\export fn _start() u32 {
\\ var i: u32 = 5;
\\ i &= 6;
\\ return i;
\\}
, "4\n");
case.addCompareOutput(
\\export fn _start() u32 {
\\ var i: u32 = 5;
\\ i |= 6;
\\ return i;
\\}
, "7\n");
case.addCompareOutput(
\\export fn _start() u32 {
\\ var i: u32 = 5;
\\ i ^= 6;
\\ return i;
\\}
, "3\n");
case.addCompareOutput(
\\export fn _start() bool {
\\ var b: bool = false;
\\ b = b or false;
\\ return b;
\\}
, "0\n");
case.addCompareOutput(
\\export fn _start() bool {
\\ var b: bool = true;
\\ b = b or false;
\\ return b;
\\}
, "1\n");
case.addCompareOutput(
\\export fn _start() bool {
\\ var b: bool = false;
\\ b = b or true;
\\ return b;
\\}
, "1\n");
case.addCompareOutput(
\\export fn _start() bool {
\\ var b: bool = true;
\\ b = b or true;
\\ return b;
\\}
, "1\n");
case.addCompareOutput(
\\export fn _start() bool {
\\ var b: bool = false;
\\ b = b and false;
\\ return b;
\\}
, "0\n");
case.addCompareOutput(
\\export fn _start() bool {
\\ var b: bool = true;
\\ b = b and false;
\\ return b;
\\}
, "0\n");
case.addCompareOutput(
\\export fn _start() bool {
\\ var b: bool = false;
\\ b = b and true;
\\ return b;
\\}
, "0\n");
case.addCompareOutput(
\\export fn _start() bool {
\\ var b: bool = true;
\\ b = b and true;
\\ return b;
\\}
, "1\n");
}
{