authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-08 13:41:49-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-04-08 13:41:49-07:00
log9f744f19e7036df9a410f780f3394f6669b8079e
tree055ef5f9727b51bde13f86805c67b3a4608b8c68
parentd7a89f98765381b4be2ce7626addad07ecfa7208
parent6dc35efe4958a0569c4d8576bca84d62264b1d1d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

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

stage2 wasm: Add division and bitwise/boolean ops &, |, ^, and, or

6 files changed, 126 insertions(+), 1 deletions(-)

src/Sema.zig+2-1
......@@ -3846,6 +3846,7 @@ fn analyzeArithmetic(
38463846 .subwrap => .subwrap,
38473847 .mul => .mul,
38483848 .mulwrap => .mulwrap,
3849 .div => .div,
38493850 else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}''", .{@tagName(zir_tag)}),
38503851 };
38513852
......@@ -4161,7 +4162,7 @@ fn zirBoolBr(
41614162 _ = try rhs_block.addBr(src, block_inst, rhs_result);
41624163
41634164 const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) };
4164 const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, rhs_block.instructions.items) };
4165 const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, else_block.instructions.items) };
41654166 _ = try child_block.addCondBr(src, lhs, tzir_then_body, tzir_else_body);
41664167
41674168 block_inst.body = .{
src/codegen.zig+10
......@@ -855,6 +855,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
855855 .not => return self.genNot(inst.castTag(.not).?),
856856 .mul => return self.genMul(inst.castTag(.mul).?),
857857 .mulwrap => return self.genMulWrap(inst.castTag(.mulwrap).?),
858 .div => return self.genDiv(inst.castTag(.div).?),
858859 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
859860 .ref => return self.genRef(inst.castTag(.ref).?),
860861 .ret => return self.genRet(inst.castTag(.ret).?),
......@@ -1092,6 +1093,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10921093 }
10931094 }
10941095
1096 fn genDiv(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1097 // No side effects, so if it's unreferenced, do nothing.
1098 if (inst.base.isUnused())
1099 return MCValue.dead;
1100 switch (arch) {
1101 else => return self.fail(inst.base.src, "TODO implement div for {}", .{self.target.cpu.arch}),
1102 }
1103 }
1104
10951105 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
10961106 // No side effects, so if it's unreferenced, do nothing.
10971107 if (inst.base.isUnused())
src/codegen/c.zig+3
......@@ -632,6 +632,9 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
632632 .mul => try genBinOp(o, inst.castTag(.sub).?, " * "),
633633 // TODO make this do wrapping multiplication for signed ints
634634 .mulwrap => try genBinOp(o, inst.castTag(.sub).?, " * "),
635 // TODO use a different strategy for div that communicates to the optimizer
636 // that wrapping is UB.
637 .div => try genBinOp(o, inst.castTag(.div).?, " / "),
635638
636639 .constant => unreachable, // excluded from function bodies
637640 .alloc => try genAlloc(o, inst.castTag(.alloc).?),
src/codegen/wasm.zig+7
......@@ -657,6 +657,10 @@ pub const Context = struct {
657657 .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
658658 .br => self.genBr(inst.castTag(.br).?),
659659 .call => self.genCall(inst.castTag(.call).?),
660 .bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),
661 .bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),
662 .bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),
663 .bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),
660664 .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
661665 .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
662666 .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
......@@ -669,6 +673,8 @@ pub const Context = struct {
669673 .load => self.genLoad(inst.castTag(.load).?),
670674 .loop => self.genLoop(inst.castTag(.loop).?),
671675 .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
676 .div => self.genBinOp(inst.castTag(.div).?, .div),
677 .xor => self.genBinOp(inst.castTag(.xor).?, .xor),
672678 .not => self.genNot(inst.castTag(.not).?),
673679 .ret => self.genRet(inst.castTag(.ret).?),
674680 .retvoid => WValue.none,
......@@ -764,6 +770,7 @@ pub const Context = struct {
764770 const opcode: wasm.Opcode = buildOpcode(.{
765771 .op = op,
766772 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
773 .signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,
767774 });
768775 try self.code.append(wasm.opcode(opcode));
769776 return .none;
src/ir.zig+4
......@@ -115,6 +115,7 @@ pub const Inst = struct {
115115 unreach,
116116 mul,
117117 mulwrap,
118 div,
118119 not,
119120 floatcast,
120121 intcast,
......@@ -181,6 +182,7 @@ pub const Inst = struct {
181182 .subwrap,
182183 .mul,
183184 .mulwrap,
185 .div,
184186 .cmp_lt,
185187 .cmp_lte,
186188 .cmp_eq,
......@@ -752,6 +754,7 @@ const DumpTzir = struct {
752754 .subwrap,
753755 .mul,
754756 .mulwrap,
757 .div,
755758 .cmp_lt,
756759 .cmp_lte,
757760 .cmp_eq,
......@@ -891,6 +894,7 @@ const DumpTzir = struct {
891894 .subwrap,
892895 .mul,
893896 .mulwrap,
897 .div,
894898 .cmp_lt,
895899 .cmp_lte,
896900 .cmp_eq,
test/stage2/wasm.zig+100
......@@ -153,6 +153,106 @@ pub fn addCases(ctx: *TestContext) !void {
153153 \\ return x * y;
154154 \\}
155155 , "350\n");
156
157 case.addCompareOutput(
158 \\export fn _start() u32 {
159 \\ var i: u32 = 352;
160 \\ i /= 7; // i = 50
161 \\ var result: u32 = foo(i, 7);
162 \\ return result;
163 \\}
164 \\fn foo(x: u32, y: u32) u32 {
165 \\ return x / y;
166 \\}
167 , "7\n");
168
169 case.addCompareOutput(
170 \\export fn _start() u32 {
171 \\ var i: u32 = 5;
172 \\ i &= 6;
173 \\ return i;
174 \\}
175 , "4\n");
176
177 case.addCompareOutput(
178 \\export fn _start() u32 {
179 \\ var i: u32 = 5;
180 \\ i |= 6;
181 \\ return i;
182 \\}
183 , "7\n");
184
185 case.addCompareOutput(
186 \\export fn _start() u32 {
187 \\ var i: u32 = 5;
188 \\ i ^= 6;
189 \\ return i;
190 \\}
191 , "3\n");
192
193 case.addCompareOutput(
194 \\export fn _start() bool {
195 \\ var b: bool = false;
196 \\ b = b or false;
197 \\ return b;
198 \\}
199 , "0\n");
200
201 case.addCompareOutput(
202 \\export fn _start() bool {
203 \\ var b: bool = true;
204 \\ b = b or false;
205 \\ return b;
206 \\}
207 , "1\n");
208
209 case.addCompareOutput(
210 \\export fn _start() bool {
211 \\ var b: bool = false;
212 \\ b = b or true;
213 \\ return b;
214 \\}
215 , "1\n");
216
217 case.addCompareOutput(
218 \\export fn _start() bool {
219 \\ var b: bool = true;
220 \\ b = b or true;
221 \\ return b;
222 \\}
223 , "1\n");
224
225 case.addCompareOutput(
226 \\export fn _start() bool {
227 \\ var b: bool = false;
228 \\ b = b and false;
229 \\ return b;
230 \\}
231 , "0\n");
232
233 case.addCompareOutput(
234 \\export fn _start() bool {
235 \\ var b: bool = true;
236 \\ b = b and false;
237 \\ return b;
238 \\}
239 , "0\n");
240
241 case.addCompareOutput(
242 \\export fn _start() bool {
243 \\ var b: bool = false;
244 \\ b = b and true;
245 \\ return b;
246 \\}
247 , "0\n");
248
249 case.addCompareOutput(
250 \\export fn _start() bool {
251 \\ var b: bool = true;
252 \\ b = b and true;
253 \\ return b;
254 \\}
255 , "1\n");
156256 }
157257
158258 {