-
Notifications
You must be signed in to change notification settings - Fork 445
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
Syntax sugar for creating IR::Expressions #196
Conversation
- IR::ERef type encapsulating a `const IR::Expression *` for overloading - overloaded operators and methods for creating new expressions - set types & srcInfo of newly created expressions based on operands
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this looks pretty it has two major shortcomings:
- you are losing sourceInfo for many constructs. This will cause problems with giving good error messages and implementing debuggers
- you are mixing some type checking logic with the IR classes. I think that typeChecking should be a visitor.
| '!' expression %prec PREFIX { $$ = new IR::LNot(@1, $2); } | ||
| '~' expression %prec PREFIX { $$ = new IR::Cmpl(@1, $2); } | ||
| '-' expression %prec PREFIX { $$ = new IR::Neg(@1, $2); } | ||
| NOT expression %prec PREFIX { $$ = !$2; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The grammar was partly serving as documentation of the IR; now developers will have to read the ERef class too.
You are losing the sourceInfo. Error messages will not be able to point to the source code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
source info is pulled from the operands by default -- it should be unchanged from what it was before (all tests indicate that it is unchanged)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, then I withdraw this objection.
Should have read more carefully ERef.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, sourceInfo was pointing at the operation sign only, but maybe that's a minor issue.
The error looks like this:
a+b
^
and not like this:
a+b
^^^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an odd difference between the P4_14 and _16 frontends that I hadn't noticed before -- the P4_14 frontend always set the source info to the full expression (not just the operator token). I'm not sure which is better aesthetically for error messages. We could change it back to explicity setting the source info to just the operator char if desired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P4-16 was the same originally, but this causes problems with long expressions that span multiple lines; the error output does not look as sharp - so I moved to pointing just the operator instead of also pointing the operands.
new IR::Constant(aval)); | ||
result->type = IR::Type_Bits::get(bval); | ||
IR::ERef lookahead = method(typeargs); | ||
IR::ERef result = lookahead.Slice(aval + bval - 1, aval); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are losing the source info in the slice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
source info is unchanged here as far as I can see...
new IR::Vector<IR::Expression>()); | ||
IR::ERef base = primitive->operands.at(0); | ||
IR::ERef method = base.Member(primitive->srcInfo, IR::Type_Header::isValid); | ||
IR::ERef result = method(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are losing the sourceInfo in the method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unchanged here as well
structure->emptyTypeArguments, | ||
new IR::Vector<IR::Expression>()); | ||
IR::ERef tbl = new IR::PathExpression(newname); | ||
IR::ERef method = tbl.Member(IR::IApply::applyMethodName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these are losing the sourceInfo.
@@ -452,8 +452,8 @@ simpleExpressionList | |||
|
|||
simpleKeysetExpression | |||
: expression { $$ = $1; } | |||
| expression MASK expression { $$ = new IR::Mask(@1 + @3, $1, $3); } | |||
| expression RANGE expression { $$ = new IR::Range(@1 + @3, $1, $3); } | |||
| expression MASK expression { $$ = $1.Mask($3); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are losing the sourceInfo.
: lvalue '(' argumentList ')' ';' { auto mc = new IR::MethodCallExpression(@1 + @4, $1, | ||
new IR::Vector<IR::Type>(), $3); | ||
$$ = new IR::MethodCallStatement(@1 + @4, mc); } | ||
: lvalue '(' argumentList ')' ';' { $$ = new IR::MethodCallStatement(@1 + @4, $1($3)); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here for the methodCallExpression.
@@ -66,10 +66,12 @@ class Sub : Operation_Binary { | |||
class Shl : Operation_Binary { | |||
stringOp = "<<"; | |||
precedence = DBPrint::Prec_Shl; | |||
Shl { if (type->is<Type::Unknown>() && left) type = left->type; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that this logic belongs to the IR class; it is maybe part of a typeChecker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want the types set for expressions in all cases, so it should be part of the constructor. Making it a separate pass just leads to holes where the type info is incorrect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The P4-16 front-end and all mid-end passes I wrote never use the type in the expression; they always uses the typeMap. The only use for that type is when converting from p4-14 - the type is set by the p4-14 front-end and read by the p4-16 front-end.
I would dearly love to get rid of the typeMap and refMap and just use the
types in the IR everywhere, as they are a huge source of excess complexity
and bugs in the code. They are needed at first to do type resolution in
the frontend, but they should no longer be necessary in the midend. Fixing
this would require adding all declarations to the global scope (once
they've been changed to be globally unique), after which any code that
needs to get the definition for a name can just look in the global scope.
This would interfere with dumping the code as legal P4, however (perhaps
just mark these added symbols and have the toP4 code ignore them in the
global scope?)
-chris
…On Tue, Dec 20, 2016 at 9:23 AM, Mihai Budiu ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In ir/expression.def <#196>:
> @@ -66,10 +66,12 @@ class Sub : Operation_Binary {
class Shl : Operation_Binary {
stringOp = "<<";
precedence = DBPrint::Prec_Shl;
+ Shl { if (type->is<Type::Unknown>() && left) type = left->type; }
The P4-16 front-end and all mid-end passes I wrote never use the type in
the expression; they always uses the typeMap. The only use for that type is
when converting from p4-14 - the type is set by the p4-14 front-end and
read by the p4-16 front-end.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#196>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AD4c8WSW7iaeD0ILi_GADlODP5tTHDS0ks5rKA8vgaJpZM4LSC78>
.
|
Changing all existing passes will be a major endeavor. The simplest solution is to write a pass before the back-end which does the conversion you want and consume this lower-level IR in the back-end. Also, in the back-end you don't worry about generating P4 again. Note that types do change while compiling, for example when enums are converted to ints, or when parameters are removed (then function signatures change). So the typechecker is not a no-op in the mid-end. |
|
||
public: | ||
ERef(const Expression *e) : expr(e) {} // NOLINT(runtime/explicit) | ||
ERef(const Expression &e) : expr(&e) {} // NOLINT(runtime/explicit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are Expression objects always allocated via new? If you pass a temporary here you'll be storing a pointer to the stack. That's a pretty big footgun. Presumably if they are always allocated via new, the constructor that takes a pointer is sufficient, so I'd suggest only providing that one or else performing an actual copy here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, they should always be allocated by new. This was an attempt to get around the need for explicit IR::ERef
constructor calls all over the place, but it doesn't really work.
|
||
namespace IR { | ||
|
||
class ERef { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd mark this class final.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that I wanted ERef_specific
to be a subclass of ERef
to avoid erasing the Expression subclass type, but that doesn't really work either.
I think I'm going to withdraw this pull request as being only half-baked. Experimenting with using ERef in the backend, it seems far too cumbersome, as all the Expression references in the IR are |
const IR::Expression *
for overloading