| ... | @@ -163,11 +163,8 @@ pub const Context = struct { | ... | @@ -163,11 +163,8 @@ pub const Context = struct { |
| 163 | try self.genFunctype(); | 163 | try self.genFunctype(); |
| 164 | const writer = self.code.writer(); | 164 | const writer = self.code.writer(); |
| 165 | | 165 | |
| 166 | // Reserve space to write the size after generating the code | 166 | // Reserve space to write the size after generating the code as well as space for locals count |
| 167 | try self.code.resize(5); | 167 | try self.code.resize(10); |
| 168 | | | |
| 169 | // offset into 'code' section where we will put our locals count | | |
| 170 | var local_offset = self.code.items.len; | | |
| 171 | | 168 | |
| 172 | // Write instructions | 169 | // Write instructions |
| 173 | // TODO: check for and handle death of instructions | 170 | // TODO: check for and handle death of instructions |
| ... | @@ -177,10 +174,10 @@ pub const Context = struct { | ... | @@ -177,10 +174,10 @@ pub const Context = struct { |
| 177 | | 174 | |
| 178 | // finally, write our local types at the 'offset' position | 175 | // finally, write our local types at the 'offset' position |
| 179 | { | 176 | { |
| 180 | var totals_buffer: [5]u8 = undefined; | 177 | leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len)); |
| 181 | leb.writeUnsignedFixed(5, totals_buffer[0..5], @intCast(u32, self.locals.items.len)); | 178 | |
| 182 | try self.code.insertSlice(local_offset, &totals_buffer); | 179 | // offset into 'code' section where we will put our locals types |
| 183 | local_offset += 5; | 180 | var local_offset: usize = 10; |
| 184 | | 181 | |
| 185 | // emit the actual locals amount | 182 | // emit the actual locals amount |
| 186 | for (self.locals.items) |local| { | 183 | for (self.locals.items) |local| { |
| ... | @@ -285,8 +282,7 @@ pub const Context = struct { | ... | @@ -285,8 +282,7 @@ pub const Context = struct { |
| 285 | } | 282 | } |
| 286 | | 283 | |
| 287 | fn genLoad(self: *Context, inst: *Inst.UnOp) InnerError!WValue { | 284 | fn genLoad(self: *Context, inst: *Inst.UnOp) InnerError!WValue { |
| 288 | const operand = self.resolveInst(inst.operand); | 285 | return self.resolveInst(inst.operand); |
| 289 | return operand; | | |
| 290 | } | 286 | } |
| 291 | | 287 | |
| 292 | fn genArg(self: *Context, inst: *Inst.Arg) InnerError!WValue { | 288 | fn genArg(self: *Context, inst: *Inst.Arg) InnerError!WValue { |
| ... | @@ -351,35 +347,49 @@ pub const Context = struct { | ... | @@ -351,35 +347,49 @@ pub const Context = struct { |
| 351 | fn genBlock(self: *Context, block: *Inst.Block) InnerError!WValue { | 347 | fn genBlock(self: *Context, block: *Inst.Block) InnerError!WValue { |
| 352 | const block_ty = try self.genBlockType(block.base.src, block.base.ty); | 348 | const block_ty = try self.genBlockType(block.base.src, block.base.ty); |
| 353 | | 349 | |
| | 350 | try self.startBlock(.block, block_ty, null); |
| 354 | block.codegen = .{ | 351 | block.codegen = .{ |
| 355 | // we don't use relocs, so using `relocs` is illegal behaviour. | 352 | // we don't use relocs, so using `relocs` is illegal behaviour. |
| 356 | .relocs = undefined, | 353 | .relocs = undefined, |
| 357 | // Here we set the current block idx, so conditions know the depth to jump | 354 | // Here we set the current block idx, so breaks know the depth to jump |
| 358 | // to when breaking out. This will be set to .none when it is found again within | 355 | // to when breaking out. |
| 359 | // the same block | | |
| 360 | .mcv = @bitCast(AnyMCValue, WValue{ .block_idx = self.block_depth }), | 356 | .mcv = @bitCast(AnyMCValue, WValue{ .block_idx = self.block_depth }), |
| 361 | }; | 357 | }; |
| | 358 | try self.genBody(block.body); |
| | 359 | try self.endBlock(); |
| | 360 | |
| | 361 | return .none; |
| | 362 | } |
| | 363 | |
| | 364 | /// appends a new wasm block to the code section and increases the `block_depth` by 1 |
| | 365 | fn startBlock(self: *Context, block_type: wasm.Opcode, valtype: u8, with_offset: ?usize) !void { |
| 362 | self.block_depth += 1; | 366 | self.block_depth += 1; |
| | 367 | if (with_offset) |offset| { |
| | 368 | try self.code.insert(offset, wasm.opcode(block_type)); |
| | 369 | try self.code.insert(offset + 1, valtype); |
| | 370 | } else { |
| | 371 | try self.code.append(wasm.opcode(block_type)); |
| | 372 | try self.code.append(valtype); |
| | 373 | } |
| | 374 | } |
| 363 | | 375 | |
| 364 | try self.code.append(wasm.opcode(.block)); | 376 | /// Ends the current wasm block and decreases the `block_depth` by 1 |
| 365 | try self.code.append(block_ty); | 377 | fn endBlock(self: *Context) !void { |
| 366 | try self.genBody(block.body); | | |
| 367 | try self.code.append(wasm.opcode(.end)); | 378 | try self.code.append(wasm.opcode(.end)); |
| 368 | | | |
| 369 | self.block_depth -= 1; | 379 | self.block_depth -= 1; |
| 370 | return .none; | | |
| 371 | } | 380 | } |
| 372 | | 381 | |
| 373 | fn genLoop(self: *Context, loop: *Inst.Loop) InnerError!WValue { | 382 | fn genLoop(self: *Context, loop: *Inst.Loop) InnerError!WValue { |
| 374 | const loop_ty = try self.genBlockType(loop.base.src, loop.base.ty); | 383 | const loop_ty = try self.genBlockType(loop.base.src, loop.base.ty); |
| 375 | | 384 | |
| 376 | try self.code.append(wasm.opcode(.loop)); | 385 | try self.startBlock(.loop, loop_ty, null); |
| 377 | try self.code.append(loop_ty); | | |
| 378 | self.block_depth += 1; | | |
| 379 | try self.genBody(loop.body); | 386 | try self.genBody(loop.body); |
| 380 | self.block_depth -= 1; | | |
| 381 | | 387 | |
| 382 | try self.code.append(wasm.opcode(.end)); | 388 | // breaking to the index of a loop block will continue the loop instead |
| | 389 | try self.code.append(wasm.opcode(.br)); |
| | 390 | try leb.writeULEB128(self.code.writer(), @as(u32, 0)); |
| | 391 | |
| | 392 | try self.endBlock(); |
| 383 | | 393 | |
| 384 | return .none; | 394 | return .none; |
| 385 | } | 395 | } |
| ... | @@ -388,23 +398,22 @@ pub const Context = struct { | ... | @@ -388,23 +398,22 @@ pub const Context = struct { |
| 388 | const condition = self.resolveInst(condbr.condition); | 398 | const condition = self.resolveInst(condbr.condition); |
| 389 | const writer = self.code.writer(); | 399 | const writer = self.code.writer(); |
| 390 | | 400 | |
| | 401 | // TODO: Handle death instructions for then and else body |
| | 402 | |
| 391 | // insert blocks at the position of `offset` so | 403 | // insert blocks at the position of `offset` so |
| 392 | // the condition can jump to it | 404 | // the condition can jump to it |
| 393 | const offset = condition.code_offset; | 405 | const offset = condition.code_offset; |
| 394 | try self.code.insert(offset, wasm.opcode(.block)); | 406 | const block_ty = try self.genBlockType(condbr.base.src, condbr.base.ty); |
| 395 | try self.code.insert(offset, try self.genBlockType(condbr.base.src, condbr.base.ty)); | 407 | try self.startBlock(.block, block_ty, offset); |
| 396 | | 408 | |
| 397 | // we inserted the block in front of the condition | 409 | // we inserted the block in front of the condition |
| 398 | // so now check if condition matches. If not, break outside this block | 410 | // so now check if condition matches. If not, break outside this block |
| 399 | // and continue with the regular codepath | 411 | // and continue with the then codepath |
| 400 | try writer.writeByte(wasm.opcode(.br_if)); | 412 | try writer.writeByte(wasm.opcode(.br_if)); |
| 401 | try leb.writeULEB128(writer, @as(u32, 0)); | 413 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 402 | | 414 | |
| 403 | // else body in case condition does not match | | |
| 404 | try self.genBody(condbr.else_body); | 415 | try self.genBody(condbr.else_body); |
| 405 | | 416 | try self.endBlock(); |
| 406 | // finally, tell wasm we have reached the end of the block we inserted above | | |
| 407 | try writer.writeByte(wasm.opcode(.end)); | | |
| 408 | | 417 | |
| 409 | // Outer block that matches the condition | 418 | // Outer block that matches the condition |
| 410 | try self.genBody(condbr.then_body); | 419 | try self.genBody(condbr.then_body); |
| ... | @@ -417,7 +426,7 @@ pub const Context = struct { | ... | @@ -417,7 +426,7 @@ pub const Context = struct { |
| 417 | | 426 | |
| 418 | // save offset, so potential conditions can insert blocks in front of | 427 | // save offset, so potential conditions can insert blocks in front of |
| 419 | // the comparison that we can later jump back to | 428 | // the comparison that we can later jump back to |
| 420 | const offset = self.code.items.len - 1; | 429 | const offset = self.code.items.len; |
| 421 | | 430 | |
| 422 | const lhs = self.resolveInst(inst.lhs); | 431 | const lhs = self.resolveInst(inst.lhs); |
| 423 | const rhs = self.resolveInst(inst.rhs); | 432 | const rhs = self.resolveInst(inst.rhs); |
| ... | @@ -492,17 +501,14 @@ pub const Context = struct { | ... | @@ -492,17 +501,14 @@ pub const Context = struct { |
| 492 | try self.emitWValue(operand); | 501 | try self.emitWValue(operand); |
| 493 | } | 502 | } |
| 494 | | 503 | |
| 495 | // if the block contains a block_idx, do a relative jump to it | 504 | // every block contains a `WValue` with its block index. |
| 496 | // if `wvalue` was already 'consumed', simply break out of current block | 505 | // We then determine how far we have to jump to it by substracting it from current block depth |
| 497 | const wvalue = @bitCast(WValue, br.block.codegen.mcv); | 506 | const wvalue = @bitCast(WValue, br.block.codegen.mcv); |
| 498 | const idx: u32 = if (wvalue == .block_idx) blk: { | 507 | const idx: u32 = self.block_depth - wvalue.block_idx; |
| 499 | br.block.codegen.mcv = @bitCast(AnyMCValue, WValue{ .none = {} }); | | |
| 500 | break :blk self.block_depth - wvalue.block_idx; | | |
| 501 | } else 0; | | |
| 502 | | | |
| 503 | const writer = self.code.writer(); | 508 | const writer = self.code.writer(); |
| 504 | try writer.writeByte(wasm.opcode(.br)); | 509 | try writer.writeByte(wasm.opcode(.br)); |
| 505 | try leb.writeULEB128(writer, idx); | 510 | try leb.writeULEB128(writer, idx); |
| 506 | return WValue.none; | 511 | |
| | 512 | return .none; |
| 507 | } | 513 | } |
| 508 | }; | 514 | }; |