Skip to content

Commit 656e46d

Browse files
committed
Move branch immediate values to the instructions array
This also drop the immediates array as no longer needed.
1 parent 35b4c36 commit 656e46d

File tree

7 files changed

+113
-213
lines changed

7 files changed

+113
-213
lines changed

lib/fizzy/execute.cpp

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ namespace fizzy
1818
{
1919
namespace
2020
{
21-
// code_offset + imm_offset + stack_height
22-
constexpr auto BranchImmediateSize = 3 * sizeof(uint32_t);
21+
// code_offset + stack_drop
22+
constexpr auto BranchImmediateSize = 2 * sizeof(uint32_t);
2323

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

456-
void branch(const Code& code, OperandStack& stack, const uint8_t*& pc, const uint8_t*& immediates,
457-
uint32_t arity) noexcept
456+
void branch(const Code& code, OperandStack& stack, const uint8_t*& pc, uint32_t arity) noexcept
458457
{
459-
const auto code_offset = read<uint32_t>(immediates);
460-
const auto imm_offset = read<uint32_t>(immediates);
461-
const auto stack_drop = read<uint32_t>(immediates);
458+
const auto code_offset = read<uint32_t>(pc);
459+
const auto stack_drop = read<uint32_t>(pc);
462460

463461
pc = code.instructions.data() + code_offset;
464-
immediates = code.immediates.data() + imm_offset;
465462

466463
// When branch is taken, additional stack items must be dropped.
467464
assert(static_cast<int>(stack_drop) >= 0);
@@ -532,7 +529,6 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
532529
static_cast<size_t>(code.max_stack_height));
533530

534531
const uint8_t* pc = code.instructions.data();
535-
const uint8_t* immediates = code.immediates.data();
536532

537533
while (true)
538534
{
@@ -548,27 +544,20 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
548544
case Instr::if_:
549545
{
550546
if (stack.pop().as<uint32_t>() != 0)
551-
immediates += 2 * sizeof(uint32_t); // Skip the immediates for else instruction.
547+
pc += sizeof(uint32_t); // Skip the immediates for else instruction.
552548
else
553549
{
554-
const auto target_pc = read<uint32_t>(immediates);
555-
const auto target_imm = read<uint32_t>(immediates);
556-
550+
const auto target_pc = read<uint32_t>(pc);
557551
pc = code.instructions.data() + target_pc;
558-
immediates = code.immediates.data() + target_imm;
559552
}
560553
break;
561554
}
562555
case Instr::else_:
563556
{
564557
// We reach else only after executing if block ("then" part),
565558
// so we need to skip else block now.
566-
const auto target_pc = read<uint32_t>(immediates);
567-
const auto target_imm = read<uint32_t>(immediates);
568-
559+
const auto target_pc = read<uint32_t>(pc);
569560
pc = code.instructions.data() + target_pc;
570-
immediates = code.immediates.data() + target_imm;
571-
572561
break;
573562
}
574563
case Instr::end:
@@ -582,16 +571,16 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
582571
case Instr::br_if:
583572
case Instr::return_:
584573
{
585-
const auto arity = read<uint32_t>(immediates);
574+
const auto arity = read<uint32_t>(pc);
586575

587576
// Check condition for br_if.
588577
if (instruction == Instr::br_if && stack.pop().as<uint32_t>() == 0)
589578
{
590-
immediates += BranchImmediateSize;
579+
pc += BranchImmediateSize;
591580
break;
592581
}
593582

594-
branch(code, stack, pc, immediates, arity);
583+
branch(code, stack, pc, arity);
595584
break;
596585
}
597586
case Instr::br_table:
@@ -604,9 +593,9 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
604593
const auto label_idx_offset = br_table_idx < br_table_size ?
605594
br_table_idx * BranchImmediateSize :
606595
br_table_size * BranchImmediateSize;
607-
immediates += label_idx_offset;
596+
pc += label_idx_offset;
608597

609-
branch(code, stack, pc, immediates, arity);
598+
branch(code, stack, pc, arity);
610599
break;
611600
}
612601
case Instr::call:

lib/fizzy/parser_expr.cpp

Lines changed: 35 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,6 @@ inline void store(uint8_t* dst, T value) noexcept
1919
__builtin_memcpy(dst, &value, sizeof(value));
2020
}
2121

22-
template <typename T>
23-
inline void push(bytes& b, T value)
24-
{
25-
uint8_t storage[sizeof(T)];
26-
store(storage, value);
27-
b.append(storage, sizeof(storage));
28-
}
29-
3022
template <typename T>
3123
inline void push(std::vector<uint8_t>& b, T value)
3224
{
@@ -48,9 +40,6 @@ struct ControlFrame
4840
/// The target instruction code offset.
4941
const size_t code_offset{0};
5042

51-
/// The immediates offset for block instructions.
52-
const size_t immediates_offset{0};
53-
5443
/// The frame stack height of the parent frame.
5544
const int parent_stack_height{0};
5645

@@ -62,11 +51,10 @@ struct ControlFrame
6251
std::vector<size_t> br_immediate_offsets{};
6352

6453
ControlFrame(Instr _instruction, std::optional<ValType> _type, int _parent_stack_height,
65-
size_t _code_offset = 0, size_t _immediates_offset = 0) noexcept
54+
size_t _code_offset = 0) noexcept
6655
: instruction{_instruction},
6756
type{_type},
6857
code_offset{_code_offset},
69-
immediates_offset{_immediates_offset},
7058
parent_stack_height{_parent_stack_height}
7159
{}
7260
};
@@ -210,16 +198,16 @@ inline void update_branch_stack(const ControlFrame& current_frame, const Control
210198
drop_operand(current_frame, operand_stack, from_valtype(*branch_frame_type));
211199
}
212200

213-
void push_branch_immediates(const ControlFrame& branch_frame, int stack_height, bytes& immediates)
201+
void push_branch_immediates(
202+
const ControlFrame& branch_frame, int stack_height, std::vector<uint8_t>& instructions)
214203
{
215204
// How many stack items to drop when taking the branch.
216205
const auto stack_drop = stack_height - branch_frame.parent_stack_height;
217206

218207
// Push frame start location as br immediates - these are final if frame is loop,
219208
// but for block/if/else these are just placeholders, to be filled at end instruction.
220-
push(immediates, static_cast<uint32_t>(branch_frame.code_offset));
221-
push(immediates, static_cast<uint32_t>(branch_frame.immediates_offset));
222-
push(immediates, static_cast<uint32_t>(stack_drop));
209+
push(instructions, static_cast<uint32_t>(branch_frame.code_offset));
210+
push(instructions, static_cast<uint32_t>(stack_drop));
223211
}
224212

225213
inline void mark_frame_unreachable(
@@ -473,7 +461,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
473461

474462
// Push label with immediates offset after arity.
475463
control_stack.emplace(Instr::block, block_type, static_cast<int>(operand_stack.size()),
476-
code.instructions.size(), code.immediates.size());
464+
code.instructions.size());
477465
break;
478466
}
479467

@@ -483,7 +471,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
483471
std::tie(loop_type, pos) = parse_blocktype(pos, end);
484472

485473
control_stack.emplace(Instr::loop, loop_type, static_cast<int>(operand_stack.size()),
486-
code.instructions.size(), code.immediates.size());
474+
code.instructions.size());
487475
break;
488476
}
489477

@@ -493,12 +481,12 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
493481
std::tie(if_type, pos) = parse_blocktype(pos, end);
494482

495483
control_stack.emplace(Instr::if_, if_type, static_cast<int>(operand_stack.size()),
496-
code.instructions.size(), code.immediates.size());
484+
code.instructions.size());
497485

498486
// Placeholders for immediate values, filled at the matching end or else instructions.
499-
push(code.immediates, uint32_t{0}); // Diff to the else instruction
500-
push(code.immediates, uint32_t{0}); // Diff for the immediates.
501-
break;
487+
code.instructions.push_back(opcode);
488+
push(code.instructions, uint32_t{0}); // Diff to the else instruction
489+
continue;
502490
}
503491

504492
case Instr::else_:
@@ -508,30 +496,27 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
508496

509497
update_result_stack(frame, operand_stack); // else is the end of if.
510498

511-
const auto if_imm_offset = frame.immediates_offset;
499+
const auto if_imm_offset = frame.code_offset + 1;
512500
const auto frame_type = frame.type;
513501
auto frame_br_immediate_offsets = std::move(frame.br_immediate_offsets);
514502

515503
control_stack.pop();
516504
control_stack.emplace(Instr::else_, frame_type, static_cast<int>(operand_stack.size()),
517-
code.instructions.size(), code.immediates.size());
505+
code.instructions.size());
518506
// br immediates from `then` branch will need to be filled at the end of `else`
519507
control_stack.top().br_immediate_offsets = std::move(frame_br_immediate_offsets);
520508

521509
// Placeholders for immediate values, filled at the matching end instructions.
522-
push(code.immediates, uint32_t{0}); // Diff to the end instruction.
523-
push(code.immediates, uint32_t{0}); // Diff for the immediates
510+
code.instructions.push_back(opcode);
511+
push(code.instructions, uint32_t{0}); // Diff to the end instruction.
524512

525513
// Fill in if's immediates with offsets of first instruction in else block.
526-
const auto target_pc = static_cast<uint32_t>(code.instructions.size() + 1);
527-
const auto target_imm = static_cast<uint32_t>(code.immediates.size());
514+
const auto target_pc = static_cast<uint32_t>(code.instructions.size());
528515

529-
// Set the imm values for else instruction.
530-
auto* if_imm = code.immediates.data() + if_imm_offset;
516+
// Set the imm values for if instruction.
517+
auto* if_imm = code.instructions.data() + if_imm_offset;
531518
store(if_imm, target_pc);
532-
if_imm += sizeof(target_pc);
533-
store(if_imm, target_imm);
534-
break;
519+
continue;
535520
}
536521

537522
case Instr::end:
@@ -549,26 +534,21 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
549534
const auto target_pc = control_stack.size() == 1 ?
550535
static_cast<uint32_t>(code.instructions.size()) :
551536
static_cast<uint32_t>(code.instructions.size() + 1);
552-
const auto target_imm = static_cast<uint32_t>(code.immediates.size());
553537

554538
if (frame.instruction == Instr::if_ || frame.instruction == Instr::else_)
555539
{
556540
// We're at the end instruction of the if block without else or at the end of
557541
// else block. Fill in if/else's immediates with offsets of first instruction
558542
// after if/else block.
559-
auto* if_imm = code.immediates.data() + frame.immediates_offset;
543+
auto* if_imm = code.instructions.data() + frame.code_offset + 1;
560544
store(if_imm, target_pc);
561-
if_imm += sizeof(target_pc);
562-
store(if_imm, target_imm);
563545
}
564546

565547
// Fill in immediates all br/br_table instructions jumping out of this block.
566548
for (const auto br_imm_offset : frame.br_immediate_offsets)
567549
{
568-
auto* br_imm = code.immediates.data() + br_imm_offset;
550+
auto* br_imm = code.instructions.data() + br_imm_offset;
569551
store(br_imm, static_cast<uint32_t>(target_pc));
570-
br_imm += sizeof(uint32_t);
571-
store(br_imm, static_cast<uint32_t>(target_imm));
572552
// stack drop and arity were already stored in br handler
573553
}
574554
}
@@ -596,13 +576,14 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
596576

597577
update_branch_stack(frame, branch_frame, operand_stack);
598578

599-
push(code.immediates, get_branch_arity(branch_frame));
579+
code.instructions.push_back(opcode);
580+
push(code.instructions, get_branch_arity(branch_frame));
600581

601582
// Remember this br immediates offset to fill it at end instruction.
602-
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
583+
branch_frame.br_immediate_offsets.push_back(code.instructions.size());
603584

604585
push_branch_immediates(
605-
branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
586+
branch_frame, static_cast<int>(operand_stack.size()), code.instructions);
606587

607588
if (instr == Instr::br)
608589
mark_frame_unreachable(frame, operand_stack);
@@ -615,7 +596,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
615596
push_operand(operand_stack, *branch_frame.type);
616597
}
617598

618-
break;
599+
continue;
619600
}
620601

621602
case Instr::br_table:
@@ -653,13 +634,13 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
653634
if (get_branch_frame_type(branch_frame) != default_branch_type)
654635
throw validation_error{"br_table labels have inconsistent types"};
655636

656-
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
637+
branch_frame.br_immediate_offsets.push_back(code.instructions.size());
657638
push_branch_immediates(
658-
branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
639+
branch_frame, static_cast<int>(operand_stack.size()), code.instructions);
659640
}
660-
default_branch_frame.br_immediate_offsets.push_back(code.immediates.size());
641+
default_branch_frame.br_immediate_offsets.push_back(code.instructions.size());
661642
push_branch_immediates(
662-
default_branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
643+
default_branch_frame, static_cast<int>(operand_stack.size()), code.instructions);
663644

664645
mark_frame_unreachable(frame, operand_stack);
665646

@@ -676,15 +657,16 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
676657

677658
update_branch_stack(frame, branch_frame, operand_stack);
678659

679-
push(code.immediates, get_branch_arity(branch_frame));
660+
code.instructions.push_back(opcode);
661+
push(code.instructions, get_branch_arity(branch_frame));
680662

681-
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
663+
branch_frame.br_immediate_offsets.push_back(code.instructions.size());
682664

683665
push_branch_immediates(
684-
branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
666+
branch_frame, static_cast<int>(operand_stack.size()), code.instructions);
685667

686668
mark_frame_unreachable(frame, operand_stack);
687-
break;
669+
continue;
688670
}
689671

690672
case Instr::call:

lib/fizzy/types.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,6 @@ struct Code
363363
// The instructions bytecode without immediate values.
364364
// https://webassembly.github.io/spec/core/binary/instructions.html
365365
std::vector<uint8_t> instructions;
366-
367-
// The decoded instructions' immediate values.
368-
// These are instruction-type dependent fixed size value in the order of instructions.
369-
bytes immediates;
370366
};
371367

372368
/// 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)