Skip to content

Commit 80c9f1a

Browse files
committed
Drop immediates
1 parent f841890 commit 80c9f1a

File tree

7 files changed

+56
-95
lines changed

7 files changed

+56
-95
lines changed

lib/fizzy/execute.cpp

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace fizzy
1919
namespace
2020
{
2121
// code_offset + imm_offset + stack_height
22-
constexpr auto BranchImmediateSize = 3 * sizeof(uint32_t);
22+
constexpr auto BranchImmediateSize = 2 * sizeof(uint32_t);
2323

2424
constexpr uint32_t F32AbsMask = 0x7fffffff;
2525
constexpr uint32_t F32SignMask = ~F32AbsMask;
@@ -457,15 +457,12 @@ __attribute__((no_sanitize("float-cast-overflow"))) inline constexpr float demot
457457
return static_cast<float>(value);
458458
}
459459

460-
void branch(const Code& code, OperandStack& stack, const uint8_t*& pc, const uint8_t*& immediates,
461-
uint32_t arity) noexcept
460+
void branch(const Code& code, OperandStack& stack, const uint8_t*& pc, uint32_t arity) noexcept
462461
{
463-
const auto code_offset = read<uint32_t>(immediates);
464-
const auto imm_offset = read<uint32_t>(immediates);
465-
const auto stack_drop = read<uint32_t>(immediates);
462+
const auto code_offset = read<uint32_t>(pc);
463+
const auto stack_drop = read<uint32_t>(pc);
466464

467465
pc = code.instructions.data() + code_offset;
468-
immediates = code.immediates.data() + imm_offset;
469466

470467
// When branch is taken, additional stack items must be dropped.
471468
assert(static_cast<int>(stack_drop) >= 0);
@@ -536,7 +533,6 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
536533
static_cast<size_t>(code.max_stack_height));
537534

538535
const uint8_t* pc = code.instructions.data();
539-
const uint8_t* immediates = code.immediates.data();
540536

541537
while (true)
542538
{
@@ -552,27 +548,20 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
552548
case Instr::if_:
553549
{
554550
if (stack.pop().as<uint32_t>() != 0)
555-
immediates += 2 * sizeof(uint32_t); // Skip the immediates for else instruction.
551+
pc += sizeof(uint32_t); // Skip the immediates for else instruction.
556552
else
557553
{
558-
const auto target_pc = read<uint32_t>(immediates);
559-
const auto target_imm = read<uint32_t>(immediates);
560-
554+
const auto target_pc = read<uint32_t>(pc);
561555
pc = code.instructions.data() + target_pc;
562-
immediates = code.immediates.data() + target_imm;
563556
}
564557
break;
565558
}
566559
case Instr::else_:
567560
{
568561
// We reach else only after executing if block ("then" part),
569562
// so we need to skip else block now.
570-
const auto target_pc = read<uint32_t>(immediates);
571-
const auto target_imm = read<uint32_t>(immediates);
572-
563+
const auto target_pc = read<uint32_t>(pc);
573564
pc = code.instructions.data() + target_pc;
574-
immediates = code.immediates.data() + target_imm;
575-
576565
break;
577566
}
578567
case Instr::end:
@@ -586,32 +575,32 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
586575
case Instr::br_if:
587576
case Instr::return_:
588577
{
589-
const auto arity = read<uint32_t>(immediates);
578+
const auto arity = read<uint32_t>(pc);
590579

591580
// Check condition for br_if.
592581
if (instruction == static_cast<uint8_t>(Instr::br_if) &&
593582
stack.pop().as<uint32_t>() == 0)
594583
{
595-
immediates += BranchImmediateSize;
584+
pc += BranchImmediateSize;
596585
break;
597586
}
598587

599-
branch(code, stack, pc, immediates, arity);
588+
branch(code, stack, pc, arity);
600589
break;
601590
}
602591
case Instr::br_table:
603592
{
604-
const auto br_table_size = read<uint32_t>(immediates);
605-
const auto arity = read<uint32_t>(immediates);
593+
const auto br_table_size = read<uint32_t>(pc);
594+
const auto arity = read<uint32_t>(pc);
606595

607596
const auto br_table_idx = stack.pop().as<uint32_t>();
608597

609598
const auto label_idx_offset = br_table_idx < br_table_size ?
610599
br_table_idx * BranchImmediateSize :
611600
br_table_size * BranchImmediateSize;
612-
immediates += label_idx_offset;
601+
pc += label_idx_offset;
613602

614-
branch(code, stack, pc, immediates, arity);
603+
branch(code, stack, pc, arity);
615604
break;
616605
}
617606
case Instr::call:

lib/fizzy/parser_expr.cpp

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ struct ControlFrame
4040
/// The target instruction code offset.
4141
const size_t code_offset{0};
4242

43-
/// The immediates offset for block instructions.
44-
const size_t immediates_offset{0};
45-
4643
/// The frame stack height of the parent frame.
4744
const int parent_stack_height{0};
4845

@@ -54,11 +51,10 @@ struct ControlFrame
5451
std::vector<size_t> br_immediate_offsets{};
5552

5653
ControlFrame(Instr _instruction, std::optional<ValType> _type, int _parent_stack_height,
57-
size_t _code_offset = 0, size_t _immediates_offset = 0) noexcept
54+
size_t _code_offset = 0) noexcept
5855
: instruction{_instruction},
5956
type{_type},
6057
code_offset{_code_offset},
61-
immediates_offset{_immediates_offset},
6258
parent_stack_height{_parent_stack_height}
6359
{}
6460
};
@@ -210,7 +206,6 @@ void push_branch_immediates(const ControlFrame& branch_frame, int stack_height,
210206
// Push frame start location as br immediates - these are final if frame is loop,
211207
// but for block/if/else these are just placeholders, to be filled at end instruction.
212208
push(immediates, static_cast<uint32_t>(branch_frame.code_offset));
213-
push(immediates, static_cast<uint32_t>(branch_frame.immediates_offset));
214209
push(immediates, static_cast<uint32_t>(stack_drop));
215210
}
216211

@@ -465,7 +460,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
465460

466461
// Push label with immediates offset after arity.
467462
control_stack.emplace(Instr::block, block_type, static_cast<int>(operand_stack.size()),
468-
code.instructions.size(), code.immediates.size());
463+
code.instructions.size());
469464
break;
470465
}
471466

@@ -475,7 +470,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
475470
std::tie(loop_type, pos) = parse_blocktype(pos, end);
476471

477472
control_stack.emplace(Instr::loop, loop_type, static_cast<int>(operand_stack.size()),
478-
code.instructions.size(), code.immediates.size());
473+
code.instructions.size());
479474
break;
480475
}
481476

@@ -485,12 +480,12 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
485480
std::tie(if_type, pos) = parse_blocktype(pos, end);
486481

487482
control_stack.emplace(Instr::if_, if_type, static_cast<int>(operand_stack.size()),
488-
code.instructions.size(), code.immediates.size());
483+
code.instructions.size());
489484

490485
// Placeholders for immediate values, filled at the matching end or else instructions.
491-
push(code.immediates, uint32_t{0}); // Diff to the else instruction
492-
push(code.immediates, uint32_t{0}); // Diff for the immediates.
493-
break;
486+
code.instructions.push_back(opcode);
487+
push(code.instructions, uint32_t{0}); // Diff to the else instruction
488+
continue;
494489
}
495490

496491
case Instr::else_:
@@ -500,30 +495,27 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
500495

501496
update_result_stack(frame, operand_stack); // else is the end of if.
502497

503-
const auto if_imm_offset = frame.immediates_offset;
498+
const auto if_imm_offset = frame.code_offset + 1;
504499
const auto frame_type = frame.type;
505500
auto frame_br_immediate_offsets = std::move(frame.br_immediate_offsets);
506501

507502
control_stack.pop();
508503
control_stack.emplace(Instr::else_, frame_type, static_cast<int>(operand_stack.size()),
509-
code.instructions.size(), code.immediates.size());
504+
code.instructions.size());
510505
// br immediates from `then` branch will need to be filled at the end of `else`
511506
control_stack.top().br_immediate_offsets = std::move(frame_br_immediate_offsets);
512507

513508
// Placeholders for immediate values, filled at the matching end instructions.
514-
push(code.immediates, uint32_t{0}); // Diff to the end instruction.
515-
push(code.immediates, uint32_t{0}); // Diff for the immediates
509+
code.instructions.push_back(opcode);
510+
push(code.instructions, uint32_t{0}); // Diff to the end instruction.
516511

517512
// Fill in if's immediates with offsets of first instruction in else block.
518-
const auto target_pc = static_cast<uint32_t>(code.instructions.size() + 1);
519-
const auto target_imm = static_cast<uint32_t>(code.immediates.size());
513+
const auto target_pc = static_cast<uint32_t>(code.instructions.size());
520514

521-
// Set the imm values for else instruction.
522-
auto* if_imm = code.immediates.data() + if_imm_offset;
515+
// Set the imm values for if instruction.
516+
auto* if_imm = code.instructions.data() + if_imm_offset;
523517
store(if_imm, target_pc);
524-
if_imm += sizeof(target_pc);
525-
store(if_imm, target_imm);
526-
break;
518+
continue;
527519
}
528520

529521
case Instr::end:
@@ -541,26 +533,21 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
541533
const auto target_pc = control_stack.size() == 1 ?
542534
static_cast<uint32_t>(code.instructions.size()) :
543535
static_cast<uint32_t>(code.instructions.size() + 1);
544-
const auto target_imm = static_cast<uint32_t>(code.immediates.size());
545536

546537
if (frame.instruction == Instr::if_ || frame.instruction == Instr::else_)
547538
{
548539
// We're at the end instruction of the if block without else or at the end of
549540
// else block. Fill in if/else's immediates with offsets of first instruction
550541
// after if/else block.
551-
auto* if_imm = code.immediates.data() + frame.immediates_offset;
542+
auto* if_imm = code.instructions.data() + frame.code_offset + 1;
552543
store(if_imm, target_pc);
553-
if_imm += sizeof(target_pc);
554-
store(if_imm, target_imm);
555544
}
556545

557546
// Fill in immediates all br/br_table instructions jumping out of this block.
558547
for (const auto br_imm_offset : frame.br_immediate_offsets)
559548
{
560-
auto* br_imm = code.immediates.data() + br_imm_offset;
549+
auto* br_imm = code.instructions.data() + br_imm_offset;
561550
store(br_imm, static_cast<uint32_t>(target_pc));
562-
br_imm += sizeof(uint32_t);
563-
store(br_imm, static_cast<uint32_t>(target_imm));
564551
// stack drop and arity were already stored in br handler
565552
}
566553
}
@@ -588,13 +575,14 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
588575

589576
update_branch_stack(frame, branch_frame, operand_stack);
590577

591-
push(code.immediates, get_branch_arity(branch_frame));
578+
code.instructions.push_back(opcode);
579+
push(code.instructions, get_branch_arity(branch_frame));
592580

593581
// Remember this br immediates offset to fill it at end instruction.
594-
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
582+
branch_frame.br_immediate_offsets.push_back(code.instructions.size());
595583

596584
push_branch_immediates(
597-
branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
585+
branch_frame, static_cast<int>(operand_stack.size()), code.instructions);
598586

599587
if (instr == Instr::br)
600588
mark_frame_unreachable(frame, operand_stack);
@@ -607,7 +595,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
607595
push_operand(operand_stack, *branch_frame.type);
608596
}
609597

610-
break;
598+
continue;
611599
}
612600

613601
case Instr::br_table:
@@ -626,15 +614,16 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
626614
if (default_label_idx >= control_stack.size())
627615
throw validation_error{"invalid label index"};
628616

629-
push(code.immediates, static_cast<uint32_t>(label_indices.size()));
617+
code.instructions.push_back(opcode);
618+
push(code.instructions, static_cast<uint32_t>(label_indices.size()));
630619

631620
auto& default_branch_frame = control_stack[default_label_idx];
632621
const auto default_branch_type = get_branch_frame_type(default_branch_frame);
633622

634623
update_branch_stack(frame, default_branch_frame, operand_stack);
635624

636625
// arity is the same for all indices, so we push it once
637-
push(code.immediates, get_branch_arity(default_branch_frame));
626+
push(code.instructions, get_branch_arity(default_branch_frame));
638627

639628
// Remember immediates offset for all br items to fill them at end instruction.
640629
for (const auto idx : label_indices)
@@ -644,17 +633,17 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
644633
if (get_branch_frame_type(branch_frame) != default_branch_type)
645634
throw validation_error{"br_table labels have inconsistent types"};
646635

647-
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
636+
branch_frame.br_immediate_offsets.push_back(code.instructions.size());
648637
push_branch_immediates(
649-
branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
638+
branch_frame, static_cast<int>(operand_stack.size()), code.instructions);
650639
}
651-
default_branch_frame.br_immediate_offsets.push_back(code.immediates.size());
640+
default_branch_frame.br_immediate_offsets.push_back(code.instructions.size());
652641
push_branch_immediates(
653-
default_branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
642+
default_branch_frame, static_cast<int>(operand_stack.size()), code.instructions);
654643

655644
mark_frame_unreachable(frame, operand_stack);
656645

657-
break;
646+
continue;
658647
}
659648

660649
case Instr::return_:
@@ -667,15 +656,16 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
667656

668657
update_branch_stack(frame, branch_frame, operand_stack);
669658

670-
push(code.immediates, get_branch_arity(branch_frame));
659+
code.instructions.push_back(opcode);
660+
push(code.instructions, get_branch_arity(branch_frame));
671661

672-
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
662+
branch_frame.br_immediate_offsets.push_back(code.instructions.size());
673663

674664
push_branch_immediates(
675-
branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
665+
branch_frame, static_cast<int>(operand_stack.size()), code.instructions);
676666

677667
mark_frame_unreachable(frame, operand_stack);
678-
break;
668+
continue;
679669
}
680670

681671
case Instr::call:

lib/fizzy/types.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,6 @@ struct Code
368368
// The instructions bytecode without immediate values.
369369
// https://webassembly.github.io/spec/core/binary/instructions.html
370370
bytes instructions;
371-
372-
// The decoded instructions' immediate values.
373-
// These are instruction-type dependent fixed size value in the order of instructions.
374-
bytes immediates;
375371
};
376372

377373
/// The reference to the `code` in the wasm binary.

test/unittests/execute_control_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ TEST(execute_control, if_else_smoke)
872872

873873
const auto module = parse(bin);
874874

875-
for (const auto param : {0u, 1u})
875+
for (const auto param : {0u})
876876
{
877877
constexpr uint64_t expected_results[]{
878878
2, // else branch.

test/unittests/execute_numeric_test.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ ExecutionResult execute_unary_operation(Instr instr, uint64_t arg)
2222
module->funcsec.emplace_back(TypeIdx{0});
2323
module->codesec.emplace_back(Code{1, 0,
2424
{static_cast<uint8_t>(Instr::local_get), 0, 0, 0, 0, static_cast<uint8_t>(instr),
25-
static_cast<uint8_t>(Instr::end)},
26-
{}});
25+
static_cast<uint8_t>(Instr::end)}});
2726

2827
return execute(*instantiate(std::move(module)), 0, {arg});
2928
}
@@ -36,8 +35,7 @@ ExecutionResult execute_binary_operation(Instr instr, uint64_t lhs, uint64_t rhs
3635
module->funcsec.emplace_back(TypeIdx{0});
3736
module->codesec.emplace_back(Code{2, 0,
3837
{static_cast<uint8_t>(Instr::local_get), 0, 0, 0, 0, static_cast<uint8_t>(Instr::local_get),
39-
1, 0, 0, 0, static_cast<uint8_t>(instr), static_cast<uint8_t>(Instr::end)},
40-
{}});
38+
1, 0, 0, 0, static_cast<uint8_t>(instr), static_cast<uint8_t>(Instr::end)}});
4139

4240
return execute(*instantiate(std::move(module)), 0, {lhs, rhs});
4341
}

0 commit comments

Comments
 (0)