Skip to content

Conversation

@harkal
Copy link
Collaborator

@harkal harkal commented Sep 10, 2025

What I did

Extent Venom to support multi-output instructions and implemented a multi-output invoke for functions that return multiple values.

How I did it

How to verify it

Commit message

Implements support for instructions with multiple return values, primarily for
the `invoke` instruction using stack-based return convention. Instructions can
now have multiple outputs via `_outputs` field, with `get_outputs()` and other
helpers.

Key changes:
  - Add `_outputs` field to IRInstruction for multi-output support
  - Fix parser, DFG analysis, and optimisation passes to handle multi-output
  - Update venom-to-assembly to properly manage stack for multi-return invoke
  - Add comprehensive tests for multi-output invoke instructions

Description for the changelog

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

@codecov
Copy link

codecov bot commented Sep 18, 2025

Codecov Report

❌ Patch coverage is 89.14956% with 37 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.14%. Comparing base (db8abe8) to head (db400ff).

Files with missing lines Patch % Lines
vyper/venom/check_venom.py 88.31% 8 Missing and 1 partial ⚠️
vyper/venom/basicblock.py 81.57% 7 Missing ⚠️
vyper/venom/ir_node_to_venom.py 87.75% 4 Missing and 2 partials ⚠️
vyper/venom/passes/dft.py 63.63% 2 Missing and 2 partials ⚠️
vyper/venom/function.py 0.00% 3 Missing ⚠️
vyper/venom/venom_to_assembly.py 90.62% 1 Missing and 2 partials ⚠️
vyper/venom/parser.py 90.47% 1 Missing and 1 partial ⚠️
...r/venom/passes/common_subexpression_elimination.py 60.00% 1 Missing and 1 partial ⚠️
vyper/venom/analysis/dfg.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4747      +/-   ##
==========================================
- Coverage   93.23%   93.14%   -0.10%     
==========================================
  Files         137      137              
  Lines       19452    19627     +175     
  Branches     3354     3398      +44     
==========================================
+ Hits        18136    18281     +145     
- Misses        893      914      +21     
- Partials      423      432       +9     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@harkal harkal changed the title feat[venom]: call conv stack return feat[venom]: add multi-output instruction support for stack-based calling convention Oct 29, 2025
@harkal harkal marked this pull request as ready for review October 29, 2025 20:25
if inst.output is not None:
bb_defined.add(inst.output)
outs = inst.get_outputs()
if outs:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary if

outs = inst.get_outputs()
if outs:
for o in outs:
bb_defined.add(o) # type: ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add an assertion instead of type: ignore

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, o should always be an IRVariable, not sure why the type: ignore is necessary


def copy(self) -> IRInstruction:
ret = IRInstruction(self.opcode, self.operands.copy(), self.output)
if self._extra_outputs:
Copy link
Member

@charles-cooper charles-cooper Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use truthy -- this is wrong in case self._extra_outputs has length 0, the pointer to the empty list will be shared with the original instruction.

i think it might be better to just use copy.copy(self._extra_outputs)


inst = IRInstruction("invoke", inst_args, ret)
inst = IRInstruction("invoke", inst_args, single_output)
if extra_outputs:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check is not None

# return buffer
if does_return_data:
if ENABLE_NEW_CALL_CONV and returns_word:
# TODO: remove this once we have proper memory allocator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove these comments?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments fell in battle :)

self.work_list.append(SSAWorkListItem(target_inst))
outputs = inst.get_outputs()
for out in outputs:
if out is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't happen

if inst.output is not None:
stack.push(inst.output)
outs = inst.get_outputs()
if outs:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more truthy

outs = inst.get_outputs()
if outs:
# For multi-output instructions, keep outputs on stack even if
# not immediately live; subsequent instructions may consume them.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't this indicate there is an issue with liveness?

Copy link
Member

@charles-cooper charles-cooper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice work.

couple comments about the approach:

@harkal harkal requested a review from charles-cooper October 30, 2025 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants