Skip to content

const evaluator: enums #21869

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 2 commits into from
Jan 22, 2019
Merged

const evaluator: enums #21869

merged 2 commits into from
Jan 22, 2019

Conversation

marcrasi
Copy link

Implements enums in the const evaluator.

#assert(weighPet(pet: .cat(2)) == 2)
// expected-error @+1 {{assertion failed}}
#assert(weighPet(pet: .cat(2)) == 3)
#assert(weighPet(pet: .dog(9, 10)) == 19)
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder whether this patch handles indirect, recursive enums, or if it needs something more? I think it would be great to add a test for indirect, recursive enums. It may help to document the behavior on them.

Copy link
Author

Choose a reason for hiding this comment

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

Indeed! Indirect enums seem not to work -- the thing that is immediately blocking them is that the const evaluator does not do alloc_box. I have added some test code but commented out the #assert statements that actually trigger the test. I'd prefer not to implement indirect enum support myself, and there's nothing left in the tensorflow branch to copy over, so if you want it, would you or someone else take that on after this gets merged?

Also your question reminded me to add a test for address-only enums. So I did that and that seems to work.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure. Thanks for adding a test. We can add the support for indirect enum when it is needed. It is enough that we document that using test cases here.

ASTContext &astContext) {
assert(decl && payload.isConstant());
auto rawMem = astContext.Allocate(sizeof(EnumWithPayloadSymbolicValue),
alignof(EnumWithPayloadSymbolicValue));
Copy link
Contributor

Choose a reason for hiding this comment

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

@marcrasi I have a more general question. It would be helpful if you can throw some light on why we have to allocate the symbolic values in the allocator of the astContext, and not bind its lifetime to the interpreter instance i.e, ConstExprEvaluator instance. (I think you clarified this in the earlier PRs, but it slipped my mind.) This essentially means these objects are never cleaned up (or at least retained for a long time). On the upside, I see that this enables querying the symbolic state of a SILValue long after interpreter has died. I wonder whether there is an inherent reason why this is needed or is this a design choice motivated by other use cases (possibly Swift for Tensorflow usecases).

Copy link
Author

Choose a reason for hiding this comment

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

One of our passes does store SymbolicValues into a SILInstruction that lives longer than the ConstExprEvaluator. (see GraphOperationInst in SILInstruction.h in the tensorflow branch if you're intersted, and look at the call to constantEvaluator.computeConstantValues in TFDeabstraction.cpp).

It should be pretty easy to clone all the memory into a longer-lived allocator before we do that though. It would be good to write APIs such that it's hard to forget to do this. Maybe all the public ConstExprEvaluator functions could clone all the memory for the returned SymbolicValues into the astcontext by default. There could be an argument allowing callers who don't actually need long-lived SymbolicValues to opt out of the cloning.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for explaining this.

Maybe all the public ConstExprEvaluator functions could clone all the memory for the returned SymbolicValues into the astcontext by default.

It seems to me that even cloning symbolic values returned by public functions may not necessary in many cases. I think it would be better if they are cloned only when they have to be stored in an instruction. If you are fine with this, I can later make a separate PR that introduces bump allocator in ConstExprEvaluator and stores the symbolic values in there.

Also, from my quick search through the code base it appears that SILInstructions are generally allocated using M.allocateInst, which seems to have a shorter lifetime compared to astcontext. It gets freed when the containing function is destroyed etc. That may something to consider for GraphOperationInst, if you have not already.

Copy link
Contributor

Choose a reason for hiding this comment

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

An alternative is that we can also provide a suitable allocator as a parameter to the constructor of ConstExprEvaluator (e.g. as Lambda or something else). But, this is something we can discuss in a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

@marcrasi I am thinking of moving some design discussions such as the above to Swift forum (compiler development section), so that we can discuss these things is more public visibility
and hopefully involve more people. :-)

@ravikandhadai
Copy link
Contributor

@marcrasi I have just added a comment on adding a test case. Otherwise, it LGTM. Thanks a lot for doing this.

case add(_ lhs: IntExpr, _ rhs: IntExpr)
case multiply(_ lhs: IntExpr, _ rhs: IntExpr)
}

Copy link
Contributor

@ravikandhadai ravikandhadai Jan 17, 2019

Choose a reason for hiding this comment

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

Looks like there are some extra spaces here, and also in the code below

Copy link
Author

Choose a reason for hiding this comment

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

Do you mean the empty lines?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh sorry, the red bars were underscores. It looked like GitHub was flagging was extra spaces (diffs)

// #assert(evaluate(intExpr: .int(5)) == 5)
// #assert(evaluate(intExpr: .add(.int(5), .int(6))) == 11)
// #assert(evaluate(intExpr: .add(.multiply(.int(2), .int(2)), .int(3))) == 7)

Copy link
Contributor

Choose a reason for hiding this comment

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

Does the interpreter crash here, or just throws a diagnostics saying assert condition is not constant? If it is the latter case, can we add it here. It doesn't bring a lot of value to the test case, except for ensuring that the interpreter gives up gracefully (and possibly with a good diagnostics eventually).

Copy link
Author

Choose a reason for hiding this comment

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

Oh yeah, it makes a diagnostic. I have uncommented them.

Copy link
Contributor

Choose a reason for hiding this comment

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

@marcrasi Thanks for fixing all of this. LGTM

@marcrasi marcrasi force-pushed the marcrasi-const-evaluator-enums branch from cdd9b77 to fb45802 Compare January 20, 2019 19:21
@ravikandhadai
Copy link
Contributor

@swift-ci Please smoke test

Copy link
Contributor

@devincoughlin devincoughlin left a comment

Choose a reason for hiding this comment

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

LGTM.

@ravikandhadai
Copy link
Contributor

@swift-ci Please test and merge

1 similar comment
@ravikandhadai
Copy link
Contributor

@swift-ci Please test and merge

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.

4 participants