Skip to content

Add support for conditional jump in action bodies #379

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 24, 2017

Conversation

antoninbas
Copy link
Member

@antoninbas antoninbas commented May 23, 2017

We tentatively add support for 2 "core" action primitives for absolute
jumps: _jump and _jump_if_zero. _jump takes one parameter which
must resolve to an integral value offset. When it is executed, we jump
to the primitive call at index offset in the enclosing
action. _jump_if_zero is a conditional jump and takes two parameters
which must both resolve to integral values, which we call respectively
cond and offset. If cond is 0, the primitive behaves exactly like
_jump and we jump to the primitive call at index offset; otherwise
the primitive is a no-op.

This was implemented at no additional cost compared to the existing
implementation. In other words, if an input does not use these 2
primitives, performance will not be affected.

This can be used by a P4_16 compiler to support conditions in actions.

The JSON documentation was updated to reflect this change, and the
version number was bumped up to 2.13

@antoninbas
Copy link
Member Author

@jafingerhut this means that your PR #355 will need to be updated but I think the code will look nicer. I created the ActionPrimitiveCall class, which can include source information.
Once the p4c bmv2 backend is updated to leverage the jump primitives, I think you can attach source information to these primitive calls which will be valuable for debugging.

@jafingerhut
Copy link
Contributor

@antoninbas If we get a little generalization in bmv2 for the P4-16 programs that can be compiled, I am more than happy to update that PR to adjust. Thanks. I did have a question on that PR regarding log levels that may address your concern about log file growth there.

@codecov-io
Copy link

codecov-io commented May 23, 2017

Codecov Report

Merging #379 into master will increase coverage by 0.06%.
The diff coverage is 91.89%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #379      +/-   ##
==========================================
+ Coverage   76.28%   76.35%   +0.06%     
==========================================
  Files         112      112              
  Lines        8802     8833      +31     
==========================================
+ Hits         6715     6744      +29     
- Misses       2087     2089       +2
Impacted Files Coverage Δ
src/bm_sim/actions.cpp 93.71% <100%> (+1.03%) ⬆️
include/bm/bm_sim/actions.h 30.88% <40%> (+1.19%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a0aaa72...cd1595b. Read the comment docs.

Copy link
Contributor

@jafingerhut jafingerhut left a comment

Choose a reason for hiding this comment

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

I haven't read through this with enough care to detect subtle bugs, but I got the basic idea enough to see that it looks reasonable. I'm probably not the reviewer you need approval from before committing, though.

@mihaibudiu
Copy link

Wouldn't it be simple to introduce a label primitive whose semantics is a no-op, and to have jumps use labels? It will certainly make code generation and debugging easier; I expect understanding the execution of a nested if conditional will be hairy with the jumps as proposed.

@antoninbas
Copy link
Member Author

The label primitive would be a pain to support; it would require some special handling wrt other primitives for backward-jumps (which I agree are not needed for if/else support), which I don't think is a good idea. Supporting string labels would also not be ideal.

One thing I could do is try to replace relative jumps with absolute jumps to a primitive operation. In a way this is the same as supporting labels, instead the label would be the index of the primitive operation in the sequence and there would be no need for a special label primitive as each primitive operation would be implicitly labelled with its index. @mbudiu-vmw would you like this better?

@mihaibudiu
Copy link

That would work; so the label is just a number denoting the position within the action.
We could even emit that as part of json to make it easy to read, but it would not be interpreted by the runtime.

@antoninbas
Copy link
Member Author

antoninbas commented May 24, 2017

To make sure we are on the same page, I'll give some more details.
Let's look at the following code:

if (hdr1.f8)
    hdr1.f32 = 0xaa;
else
    hdr1.f32 = 0xbb;

Right now this pull request would require some json that looks like this for the primitive list in the action:

[op0(_jump_if_zero, [hdr1.f8, 2]), op1(assign, [hdr1.f32, 0xaa]), op2(_jump, [1]), op3(assign, [hdr1.f32, 0xbb])]

Notice how the jumps use relative offsets. When op0 is executed, if hdr1.f8 is 0, we skip the next 2 operations and execute op3.

What I'm proposing is to make the jumps absolute. The new json would look like this:

[op0(_jump_if_zero, [hdr1.f8, 3]), op1(assign, [hdr1.f32, 0xaa]), op2(_jump, [4]), op3(assign, [hdr1.f32, 0xbb])]

The offsets are now absolute. When op0 is executed, if hdr1.f8 is 0, we jump to the operation at index 3, which is op3.

The change I'm offering is a very small one. But using absolute offsets make things a little more readable and maybe a little easier to generate in p4c.

As you correctly mention, the offsets can be explicitly added in the JSON for the sake for readability, the bmv2 json parser will ignore them. For example:

{
    "op": "assign",
    "parameters": [...],
    offset: 0
},
{
    "op": "assign",
    "parameters": [...],
    offset: 1
}

offset can also be called label. In the future we can consider using this attribute and supporting arbitrary labels.

@mbudiu-vmw let me know if we are on the same page and I'll make the change this afternoon.

@mihaibudiu
Copy link

Yes, that looks good. Thank you.

@antoninbas antoninbas force-pushed the action-conditional-jump branch from 9fe4739 to 15cc42c Compare May 24, 2017 20:35
We tentatively add support for 2 "core" action primitives for absolute
jumps: `_jump` and `_jump_if_zero`. `_jump` takes one parameter which
must resolve to an integral value `offset`. When it is executed, we jump
to the primitive call at index `offset` in the enclosing
action. `_jump_if_zero` is a conditional jump and takes two parameters
which must both resolve to integral values, which we call respectively
`cond` and `offset`. If `cond` is 0, the primitive behaves exactly like
`_jump` and we jump to the primitive call at index `offset`; otherwise
the primitive is a no-op.

This was implemented at no additional cost compared to the existing
implementation. In other words, if an input does not use these 2
primitives, performance will not be affected.

This can be used by a P4_16 compiler to support conditions in actions.

The JSON documentation was updated to reflect this change, and the
version number was bumped up to 2.13
@antoninbas antoninbas force-pushed the action-conditional-jump branch from 15cc42c to cd1595b Compare May 24, 2017 20:37
@antoninbas
Copy link
Member Author

I updated the PR to support absolute jumps.

const auto &primitive = primitives[idx];
param_offset = primitive.get_param_offset();
primitive.execute(&state, &(action_fn->params[param_offset]));
idx = primitive.get_jump_offset(idx);

Choose a reason for hiding this comment

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

Would you like to check here that idx is greater than the previous value?

Copy link
Member Author

Choose a reason for hiding this comment

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

it does not have to be, we could imagine supporting backward jumps (for loops)
what would make sense is to check the jump indices in the bmv2 json parser but that would require some special handling for the jump primitives, which I am trying to avoid

@hesingh
Copy link
Contributor

hesingh commented May 15, 2020

@antoninbas I like what you did for code for this issue.

However, I wonder, if one could use keywords in JSON such as if_cond, else_cond, else_if_cond to support if-statements? This way, the format is also consistent with the if_cond used in checksum. Further, whether the if-statement exists in the apply block of a control or inside an action, we could generate the same JSON, couldn't we?

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.

None yet

5 participants