-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Fully implement ++ and -- #486
Conversation
Despite the title I've only done |
d0a7c2c
to
82f5419
Compare
I'm not very pleased with the output of the AST printer, but I'm not sure a better way to represent it.
It also makes error messages in the semantic analyser a bit uglier, e.g. Maybe something like this, but suggestions are welcome:
|
Second examples look more intuitive. |
@@ -111,9 +111,11 @@ class Binop : public Expression { | |||
|
|||
class Unop : public Expression { | |||
public: | |||
Unop(int op, Expression *expr) : expr(expr), op(op) { } | |||
Unop(int op, Expression *expr, bool is_post_op = false) |
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 like this approach of using the unary operator. I had considered something similar but couldn't quite get it figured out
b_.CreateMapUpdateElem(map, key, newval); | ||
b_.CreateLifetimeEnd(key); | ||
|
||
if (unop.is_post_op) |
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, this is exactly how I was thinking of implementing pre/post 👍
src/ast/codegen_llvm.cpp
Outdated
} | ||
break; | ||
} | ||
case bpftrace::Parser::token::MINUSMINUS: |
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 can probably reuse most of the ++ code, and just change:
b_.CreateStore(b_.CreateAdd(oldval, b_.getInt64(1)), newval);
To CreateSub. Not sure of the cleanest way to DRY this up but it shouldn't be too hard.
I agree the second printing example is more intuitive. This approach looks good! It's a simpler version of what I had in mind, overloading the unop constructor is a good approach. |
Not yet, but it shouldn't take me long to finish off. Are you saying there'll be conflicts? I don't mind fixing them up in this pull request if you're blocked. |
I was mistaken, this wasn't needed to fix #544. Also, at a glance it doesn't seem like this PR will conflict with recent changes. |
I want to fix the two shift/reduce conflicts we have on our parser, but I'll wait until this land since it might involve rearranging some grammar rules. |
@ajor were you able to work on this lately? Would be nice to include this in the next version (0.9.1). |
Finished off my other two pull requests last weekend, so will get back to this one next |
I've implemented it fully now. The ntop codegen tests had to be changed because they used |
Read through #448 and now I'm thinking we should maybe keep |
Or we can change #448 to not allow compound assignment of uninitialized variables and maps. |
tl;dr: changing how compound assignments work for uninitialized variables doesn't make sense, so we should change this to make it coherent with compound assignments. diff --git a/src/ast/semantic_analyser.cpp b/src/ast/semantic_analyser.cpp
index aa58df0..ddbfe40 100644
--- a/src/ast/semantic_analyser.cpp
+++ b/src/ast/semantic_analyser.cpp
@@ -855,7 +855,6 @@ void SemanticAnalyser::visit(ExprStatement &expr)
void SemanticAnalyser::visit(AssignMapStatement &assignment)
{
- assignment.map->accept(*this);
assignment.expr->accept(*this);
std::string map_ident = assignment.map->ident;
@@ -877,15 +876,19 @@ void SemanticAnalyser::visit(AssignMapStatement &assignment)
}
}
else {
- // This map hasn't been seen before
- map_val_.insert({map_ident, assignment.expr->type});
- if (map_val_[map_ident].type == Type::integer) {
- // Store all integer values as 64-bit in maps, so that there will
- // be space for any integer to be assigned to the map later
- map_val_[map_ident].size = 8;
+ if (is_final_pass()) {
+ // This map hasn't been seen before
+ map_val_.insert({map_ident, assignment.expr->type});
+ if (map_val_[map_ident].type == Type::integer) {
+ // Store all integer values as 64-bit in maps, so that there will
+ // be space for any integer to be assigned to the map later
+ map_val_[map_ident].size = 8;
+ }
}
}
+ assignment.map->accept(*this);
+
if (assignment.expr->type.type == Type::cast) {
std::string cast_type = assignment.expr->type.cast_type;
std::string curr_cast_type = map_val_[map_ident].cast_type; This seems enough to force initialization of maps on compound assignment. But it changes the behavior of maps. For example, the program below is valid today:
But it would fail with the patch above:
At the same time, the program below kinda makes sense, but would be invalid with the patch above:
But if we change the probe order it works:
Which doesn't make sense since we can't guarantee the execution order of two different probes. Either both programs should fail or be valid. If both programs fail, we won't be able to use maps across different probes, so we should keep the behavior as it is today. As for compound assignments, As for increment, users would expect Variables are a different case, and no changes should be needed in either PR. I also think we might want to better explain maps behavior in our reference guide. Today we only have examples there, which makes it look like both maps and variables behave the same, with the only difference being their scope (https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md#2---basic-variables). |
An alternative implementation would be to turn assignments into expressions, and allow for pre/post assignments. Then we could implement using Assing*Expression insead of unop, and would guarantee the same behavior between normal assignments, compound assignments and increment/decrement. This would also allow for C-style syntax like below:
Not saying that the syntax above is a good idea or that this would be a better implementation, just sharing an alternative that would comply with compound assignment behavior. |
Assignments as expressions might be something we should do, but I'll leave it out of this pull request and just get this one working some other way. EDIT: Changed my mind after thinking about what I'd have to do to implement this :P |
47bf014
to
ee77b3f
Compare
Done - please review again! I'd misunderstood what you meant about assignment expressions when I commented yesterday - I've just done it without them now |
ee77b3f
to
733d59d
Compare
733d59d
to
89981fb
Compare
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.
LGTM. Suggested changes on tests are not critical and we can add it later.
|
||
TEST(codegen, map_increment_decrement) | ||
{ | ||
test("BEGIN { @x = 10; @x++; ++@x; @x--; --@x; }", |
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.
Could also test undefined map here:
test("BEGIN { @x = 10; @x++; ++@x; @x--; --@x; }", | |
test("BEGIN { @x = 10; @x++; ++@x; @x--; --@x; @y++ }", |
@@ -92,3 +92,13 @@ NAME defines work | |||
RUN bpftrace -e "$(echo '#define _UNDERSCORE 314'; echo 'BEGIN { printf("%d\\n", _UNDERSCORE); exit(); }')" | |||
EXPECT 314 | |||
TIMEOUT 1 | |||
|
|||
NAME increment/decrement map | |||
RUN bpftrace -e 'BEGIN { @x = 10; printf("%d", @x++); printf(" %d", ++@x); printf(" %d", @x--); printf(" %d\n", --@x); delete(@x); exit(); }' |
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:
RUN bpftrace -e 'BEGIN { @x = 10; printf("%d", @x++); printf(" %d", ++@x); printf(" %d", @x--); printf(" %d\n", --@x); delete(@x); exit(); }' | |
RUN bpftrace -e 'BEGIN { @x = 10; printf("%d", @x++); printf(" %d", ++@x); printf(" %d", @x--); printf(" %d\n", --@x); printf(" %d", @y++); delete(@x); delete(@y); exit(); }' |
Unrelated tests are failing probably due to me doing a dodgy rebase - I'll fix them too before merging |
This should fix the last failing test: diff --git a/tests/codegen/unroll.cpp b/tests/codegen/unroll.cpp
index 2fcfa87..6b8b27d 100644
--- a/tests/codegen/unroll.cpp
+++ b/tests/codegen/unroll.cpp
@@ -6,7 +6,7 @@ namespace codegen {
TEST(codegen, unroll)
{
- test("BEGIN { @i = 0; unroll(5) { @i++ } }",
+ test("BEGIN { @i = 0; unroll(5) { @i += 1 } }",
R"EXPECTED(; Function Attrs: nounwind
declare i64 @llvm.bpf.pseudo(i64, i64) #0 |
Ahh that makes more sense! Thanks I'll get that updated |
89981fb
to
9b11afc
Compare
Issue #412