Skip to content

[SYCL] Changes to visitor model in preparation of array support. #1764

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 6 commits into from
Jun 6, 2020

Conversation

rdeodhar
Copy link
Contributor

Signed-off-by: rdeodhar [email protected]

template <typename RangeTy, typename... Handlers>
static void VisitField(CXXRecordDecl *Owner, RangeTy Item, QualType ItemTy,
Handlers &... handlers) {
if (Util::isSyclAccessorType(ItemTy)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't use curley brackets for single line if-statements

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

} else if (Util::isSyclStreamType(ItemTy))
(void)std::initializer_list<int>{
(handlers.handleSyclStreamType(Item, ItemTy), 0)...};
else {
Copy link
Contributor

Choose a reason for hiding this comment

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

This else body shouldn't be necessary, make the two checks top-level. Additionally, please leave the existing order (where structure/class type happens right after accessor/stream) and put the array at the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

int64_t ElemCount = CAT->getSize().getSExtValue();
std::initializer_list<int>{(handlers.enterArray(), 0)...};
for (int64_t Count = 0; Count < ElemCount; Count++) {
VisitField(nullptr, Item, ET, handlers...);
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems that 'visitField' could instead have its 'owner' be a generic declaration, so that the array type could pass that on instead. This would also allow offset-handling quite a bit more easily I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure about this. Let's wait until the handleArrayType bodies are filled in.

bool copyableToKernel(const FieldDecl *FD, const QualType &FieldTy) {
// C++ lambda capture already flags non-constant array types.
// Here, we check copyability.
if (FieldTy->isConstantArrayType()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (FieldTy->isConstantArrayType()) {
if (const auto *CAT = dyn_cast<ConstantArrayType>(FieldTy)) {

And so fourth, do the same elsewhere if you're going to use the type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

@@ -801,6 +843,43 @@ class SyclKernelFieldChecker
bool IsInvalid = false;
DiagnosticsEngine &Diag;

// Check whether the object is bit-wise copyable
bool copyableToKernel(const FieldDecl *FD, const QualType &FieldTy) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is actually a 'check' type function, and thus should be 'checkCopyableToKernel'. With that, please invert the 'bool' (false is successful). Then, all of the Diagnostics.report, followed by a return changes to "return Diagnostics.Report", since that is implicitly convertable to bool.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

return false;
}
}
if (!FieldTy->isStructureOrClassType()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

no curleys for single liners.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

}

void handleArrayType(const CXXBaseSpecifier &, QualType) final {
// FIXME
Copy link
Contributor

Choose a reason for hiding this comment

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

Add some text here, what do you intend this fixme to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Deleted.

template <typename RangeTy, typename... Handlers>
static void VisitArrayElements(RangeTy Item, QualType FieldTy,
Handlers &... handlers) {
const ConstantArrayType *CAT = cast<ConstantArrayType>(FieldTy);
Copy link
Contributor

Choose a reason for hiding this comment

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

When you do cast to ConstantArrayType you expect that FieldTy is ConstantArrayType, otherwise assertion will be triggered, so, is it safe to do cast here? I'm asking because VisitArrayElements is called after check on isArrayType, not on isConstantArrayType.

Copy link
Contributor

Choose a reason for hiding this comment

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

Later, he leaves this comment, which made me not comment on this. but it is still worth evaluating:
// C++ lambda capture already flags non-constant array types.
// Here, we check copyability.

There are 4 types of arrays:
Constant
This one is obvious.

DependentSized
I dont think we have to worry about this one, all instantiations are done before we get here, right?

Incomplete
You cannot actually capture an incomplete sized array type as far as I can tell. They aren't particularly easy to spell in C, and I think we prevent capturing them: https://godbolt.org/z/-oDsdz

Variable
This is the only one that I think is possible, but only as a reference type: https://godbolt.org/z/hEdiK-
Of course, VLAs in structs aren't supported in clang (with the pretty assertive message: fields must have a constant size: 'variable length array in structure' extension will never be supported)

That said, Do we prevent the reference case from making it here?

Copy link
Contributor

Choose a reason for hiding this comment

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

AFAIK SYCL spec allows only "by value" ([=] this one) capture for kernels, AFAIK we just don't diagnose if someone tried to use "by reference" capture.
This comment didn't satisfy me because kernel object can be defined not only as lambda but as user-defined callable object as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, then the VariableArraytype isn't a concern, though we should probably diagnose that (should we diagnose ALL ReferenceType fields?).

I'd not thought about other object types. From that perspective, only the incomplete type is of concern, we should likely diagnose that.

Copy link
Contributor

Choose a reason for hiding this comment

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

FYI: This is another great use of the 'have visit methods return the boolean value'. We could/should stop descending once we report failure.

Copy link
Contributor

@Fznamznon Fznamznon May 28, 2020

Choose a reason for hiding this comment

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

Oh, I just forgot, but it seems we already diagnose ReferenceType fields, don't we?

IsInvalid = Diag.Report(FD->getLocation(), diag::err_bad_kernel_param_type)

From that perspective, only the incomplete type is of concern, we should likely diagnose that.

Agree.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Non-constant arrays could slip through via function objects. I've added a check.

Copy link
Contributor

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

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

I know you emailed a separate implementation that you're working on, so I'll hold off on further review. That said, see my comment here:

We'd like this return value to propogate and happen everywhere, it doesn't make sense to continue looking into any handlers if the 'base' had failed, even struct descent.

}
template <typename T, typename... Tn>
static bool handleField(FieldDecl *FD, QualType FDTy, T &t, Tn &... tn) {
return (t.first->*t.second)(FD, FDTy) && handleField(FD, FDTy, tn...);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this "&&" logic needs to happen at every level here. All the way to the root fields, base classes, etc. As soon as we discover an error in attempting anything we need to give up. So the 'bool' needs to be propogated quite a bit more.

I would think it should cause us to stop descending as well.

@rdeodhar rdeodhar requested review from erichkeane and Fznamznon June 3, 2020 17:29
Comment on lines 932 to 935
bool bad = Diag.Report(FD->getLocation(), diag::err_bad_kernel_param_type)
<< FieldTy;
IsInvalid |= bad;
return !bad;
Copy link
Contributor

Choose a reason for hiding this comment

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

AFAIK bad here is always true. @erichkeane , should we return true in handler functions to continue?

Copy link
Contributor

Choose a reason for hiding this comment

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

bad is completely unnecessary here, I think 934 should just be: "IsInvalid = true", and return false.

You're right, Diag.Report ALWAYS returns true. I'd also suggest having each of these functions just return isValid().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, done.

@rdeodhar rdeodhar requested a review from Fznamznon June 4, 2020 15:55
Comment on lines 2281 to 2287
std::cerr << "isSyclAccessorType:Ty\n";
Ty->dump();
bool b = isSyclType(Ty, "accessor", true /*Tmpl*/) || isSyclType(Ty, "accessor_common", true /*Tmpl*/);
std::cerr << (b ? "IS"
: "NOT")
<< " an accessor\n\n";
return b;
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, it seems something wrong happened, right?

Fznamznon
Fznamznon previously approved these changes Jun 4, 2020
erichkeane
erichkeane previously approved these changes Jun 5, 2020
Copy link
Contributor

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

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

Looks fine to me too. However, @bader, it seems to fail in the merge step. Whats the best way to do this? SHould he commit a merge commit, or do a rebase/force-push, or what?

@bader
Copy link
Contributor

bader commented Jun 5, 2020

To avoid force-pushes it's re-commended to resolve conflict using git merge.

@rdeodhar rdeodhar dismissed stale reviews from erichkeane and Fznamznon via 2a36ef6 June 5, 2020 17:30
@rdeodhar
Copy link
Contributor Author

rdeodhar commented Jun 5, 2020

I've merged in the latest intel/llvm. It should be mergeable now.

Copy link
Contributor

@bader bader left a comment

Choose a reason for hiding this comment

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

LGTM.
One minor style comment - please, apply in follow-up PR(s).

if (const auto *CAT = dyn_cast<ConstantArrayType>(FieldTy)) {
QualType ET = CAT->getElementType();
return checkNotCopyableToKernel(FD, ET);
} else
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
} else
}

Please, don't use else after return.

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