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