Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
mlir/include/mlir/Dialect/SparseTensor/IR/Enums.h | ||
---|---|---|
114–132 | It makes me squeamish to have so much code duplication between these macros and the basic ones. There isn't a great way to handle this due to (intentional) limitations in CPP. But the best option is to rephrase the original x-macros to be variadic: i.e., something like MLIR_SPARSETENSOR_FOREVERY_V(DO,...) DO(F64, double, __VA_ARGS__) etc. Which will at least save you from needing to duplicate the innermost x-macro. However, IIRC Peiming had some issues getting this to work on Windows last time I raised this concern, so you should check with him about what problems he ran into. If you cannot get the variadic macros to work, then at the very least you should file a bug (assigned to me) and add a FIXME comment with the bug number. | |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
397 | Please rename to dimRank to match the terminology used elsewhere (and as per D143800 and https://github.com/openxla/stablehlo/pull/1143). | |
402 | Just use !IsSymmetric | |
406–407 | Why use new temp variables rather than just reusing the function parameter variables? | |
409–413 | I like how this helps save code duplication, but I feel it's at the wrong level of abstraction. E.g., if you use the indices and values variables directly rather than using the pIndices and pValues variables, then you could have this function advance the two pointers after writing to them —thus maintaining the invariant that the pointers are always pointing to the next free entry (or one-past-the-end). Doing so keeps both halves of the pointer logic (writing to them and advancing them) together; whereas the current code mixes some of the pointer logic with the isSorted logic. Having this function advance the pointers after writing to them would also help in clarifying things in the if constexpr (IsSymmetric) conditional, since it would be doing indices[0,1] = indices[-2,-1]; values[0] = values[-1] which (to my mind) helps clarify that it's writing the *next* entry based on the *previous* entry. | |
438–439 | Since IsSymmetric can only be true when dimRank == 2, the pIndices[2] and pIndices[3] memory addresses look like they should be invalid. Yes, I know why the code actually works, but it would be prudent to add a comment explaining why it's okay so that other readers won't get confused. | |
mlir/lib/ExecutionEngine/SparseTensorRuntime.cpp | ||
646 | please rename to dimRank |
Address review comments.
mlir/include/mlir/Dialect/SparseTensor/IR/Enums.h | ||
---|---|---|
114–132 | Thanks. Done. |
mlir/include/mlir/Dialect/SparseTensor/IR/Enums.h | ||
---|---|---|
38 | does it really say, "function-liked"? | |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
252 | Can we make the NNZ -> NSE or NOE change (number of stored entries, rather than nonzeros, since we may store a few zeros ;-) | |
437 | I feels like the way we handle symmetry (with the expand option) is starting to convolute our implantation quite a bit. Here we have the whole complication of knowing the number of entries in advance, but still have to compute how many are on the diagonal and thus not counted twice. perhaps we should abandon the "expand symmetry" option altogether, and simply read in symmetric matrices as lower/upper triangular and start working on adding the proper "property" to our dim/level types |
Update after removing expand_symmetry property. Rename nnz to nse.
mlir/include/mlir/Dialect/SparseTensor/IR/Enums.h | ||
---|---|---|
38 | see here | |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
437 | Remove symmetry in https://reviews.llvm.org/D144059 |
mlir/include/mlir/Dialect/SparseTensor/IR/Enums.h | ||
---|---|---|
114–132 | Thanks for doing that :) | |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
252 | Fwiw I've been using "NSE" in my renaming patch. (I like that that specifically has "stored" in it.) | |
255 | I find it confusing that this method has the same name as readCOO<I> but very different arguments. You should rename this method to readIntoBuffers (or readInto if you're feeling succinct). Also, you should have this method take the lvlRank argument in addition to dim2lvl so that it matches the API of readCOO<I>. Also, I follow the style of (a) providing buffer lengths before the buffers themselves, and (b) placing out-parameters last. Thus, the arguments should be in the order (lvlRank, dim2lvl, maxNse, indices, values) | |
302 | Ditto my comments at readCOO<I,V>, this method should:
In addition, you should change the type of dim2lvl to be detail::PermutationRef, so that it matches the API of readCOOLoop<I>. When you move the construction of the PermutationRef to readIntoBuffers<I,V> be sure to also add the assert(lvlRank == dimRank && "Rank mismatch"); as well. Ideally both readCOO<I> and readIntoBuffers<I,V> should take PermutationRef rather than a pointer: because we want to push construction of PermutationRef as far up the callstack as possible, since doing so helps make more of the code typesafe and improves the C++ API. (Honestly I'm not entirely sure why I didn't do that in the first place; but I can make that change in a separate CL.) | |
390 | You should add an assertion here that nnz <= maxNse, to ensure we catch errors as early as possible. You should also rename the local variable to nse so that it matches the function parameter. Don't worry about the mismatch between the local variable and the method name; I'll be fixing that in my big renaming CL | |
398 | Why split this out as a separate function? It would be cleaner to combine it with getOneElement so that it maintains the invariant that indices/values are always pointing to free memory. I'm guessing you're worried about the sortedness check. If so, then the cleanest thing would be to move that sortedness check into getOneElement so that the function maintains that invariant as well! To make that work all you have to do is set isSorted=false before getting the first element (so that the conditional fails and all we do is read and advance pointers), and then set isSorted=true before entering the loop. Rewriting getOneElement to include both advanceOneElement and the sortedness check will greatly help readability and reasoning. It'll help not just because it's maintaining invariants (which always helps), but because it's using the proper inductive hypothesis. It's precisely because that's the correct IH that (a) the function maintains a bunch of invariants, and (b) the rest of the code is just a simple loop calling the function plus a basis case outside of the loop. | |
411 | Once you add the assert(nse <= maxNse) above, then you don't need this assertion anymore |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
255 | Rename to readToBuffers. | |
302 | Rename to readToBuffersLoop. | |
390 | Rename nnz to nse. |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
299 | we don't template over isSymmetric? | |
405 | this is only safe when we already have one element. You do have the unrolled for loop below, but I don't see how that helps? | |
408 | it feels like if (prevIndices[d] != indices[d]) { if (prevIndices[d] >= indices[d]) isSorted = false; break; } avoids writing true to the isSorted field for every element. | |
417 | is this one reading outside the buffer? |
I think you missed some of my comments?
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
256 | Technically this should be a *Level, since it maps dims (as index now) to levels in the array. @wrengr do we want a typedef for dim2lvl and lvl2dim too just to be complete? | |
299 | did you see my comment. The comment on L297 still mentions IsSymmetric, which is gone now |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
252 | please use "coordinates" to match the new naming convention | |
255 | Since readToBuffers does still construct a PermutationRef, it should have the same assert(lvlRank == dimRank && "Rank mismatch") assertion that readCOO does. While the PermutationRef ctor checks that dim2lvl is in fact a permutation, having this assertion before calling the ctor does two things: First, it ensures consistent error messages between the runtime/codegen passes, which is important for UX. Second, it helps catch errors —dim2lvl can be a permutation of dimRank even if dimRank != lvlRank, so we need to be sure to catch the rank mismatch in order to ensure correctness. Also, as I mention in other comments below, the readToBuffersLoop does in fact want the lvlRank argument | |
255 | Please rename the I template parameter to C to match the new naming convention. | |
256 | We can, though that'd best be done as a separate CL, just to keep things clean. Fwiw, I'm not too worried about it at the moment. Once I wrap up my current CL, I'll be getting back to updating the compiler to support non-permutations; and once the compiler is in a position to generate the dim2lvl/lvl2dim functions, that's when I was going to go through and update everything in the RT to take function-pointers in lieu of the current vectors/memrefs/pointers. Thus, so long as the new methods follow the same coding conventions as the pre-existing methods, then it should be easy enough to change at that point. | |
256 | Please rename to lvlCoordinates to match the new naming convention. (N.B., we do not use the shorter lvlCoords here because this is a shared pool of coords, rather than just the coords for a single element) | |
301 | Please rename the I template parameter to C to match the new naming convention. | |
302 | Please rename to lvlCoordinates to match the new naming convention. (N.B., we do not use the shorter lvlCoords here because this is a shared pool of coords, rather than just the coords for a single element) | |
369 | Please rename the I template parameter to C to match the new naming convention. | |
370 | Please rename to lvlCoordinates to match the new naming convention. (N.B., we do not use the shorter lvlCoords here because this is a shared pool of coords, rather than just the coords for a single element) | |
388 | Please rename the I template parameter to C to match the new naming convention. | |
390 | Please rename to lvlCoordinates to match the new naming convention. (N.B., we do not use the shorter lvlCoords here because this is a shared pool of coords, rather than just the coords for a single element) | |
394 | Please rename to dimCoords to match the new naming convention. | |
405–406 | This comment should be moved up to where you first declare/define the isSorted variable, rather than here | |
407 | This should be lvlRank. Once we change dim2lvl to be an arbitrary mapping rather than a permutation, then each element will have lvlRank-many coordinates, therefore we need to make sure to advance the lvlCoordinates pointer by lvlRank for each element. | |
407 | Please rename to prevLvlCoords to match the new naming convention | |
408 | This should be lvlRank. | |
408 | This should be l | |
416 | This should be lvlRank. | |
423 | These braces aren't needed for so simple a loop body | |
mlir/include/mlir/ExecutionEngine/SparseTensorRuntime.h | ||
286 | please say "coordinates" to match the new naming convention | |
mlir/lib/ExecutionEngine/SparseTensorRuntime.cpp | ||
634 | use CNAME and C to match the new naming convention |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
256 |
Yeah, I was not suggesting to add that here, but this was really more a note to you on perhaps adding two more types for the two mappings. void foo(Dim2Lvl dim2lvl) would be nice ;-=) |
Rename I to C, indices to coordinates.
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
256 | Will use the new typedef here when we have it. | |
256 | Ok. Leaving this as it is. | |
299 | We remove the expansion for isSymmetric in https://reviews.llvm.org/D144059 and now only record the property. | |
299 | Sorry for missing this. | |
405 | I add a comment to the code to explain this. | |
408 | Agree. changed to isSorted = false; | |
411 | we don't have maxNse anymore. | |
417 | This reads the first element with isSorted = false, to prepare for the reading of the rest, with isSorted initialized to true. Add a comment to the code. |
Just a few more nits re naming. Once these and the couple remaining ones from before (dimInd->dimCoords; d->l) are finished, then this should be good to go! :)
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
252 | Shouldn't that say "reads from the file" or something similar? (Since this isn't using SparseTensorCOO) | |
397 | You already asserted this in readToBuffers, so don't need to do it again here (since readToBuffersLoop is private). | |
414 | This should be just prevLvlCoords since it's intended to refer to the coordinates of a single element (despite the fact that those "coords" live inside the larger "coordinates" buffer). Yeah, I know it looks idiosyncratic here, since the function parameter is being used both for the entire collection of "coordinates" (when viewed from outside the function) as well as being reused to mean just the "coords" of the most-recent element (when viewed from inside the loop). If you want to avoid the idiosyncrasy, then feel free to (re)introduce a local variable lvlCoords for the pointer that we advance by lvlRank each time this lambda is called. (Yeah, you used to have such a local variable in earlier versions of this CL; but when I suggested removing it, that was before I started on the Big Renaming CL to try and clean all this stuff up ;) |
Rename d->l, dimInd->dimCoords, prevlvlCoordinates->prevLvlCoords.
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
252 | add "from the file". |
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
379–381 | personally I'd rather this be phrased as const bool isSorted = IsPattern ? ... : ...; (or const bool isSorted = isPattern() ? ... : ...;) since that's a lot more succinct and keeps things const | |
405 | should be dimCoords here too | |
410–421 | To avoid the code repetition, it'd be nice to replace this whole conditional and loopnest with isSorted &&= elemLT(Element<_>(prevLvlCoords,_), Element<_>(lvlCoordinates,_)) where const ElementLT<_> elemLT(lvlRank); is defined above the lambda. Though I'm hesitant to suggest that wholeheartedly, because there's the issue of filling in those underscores. The natural thing to do would be to use V and *values/*(values-1), but that incurs the cost of copying V and hence would slow things down. (The unnatural thing to do would be to define struct Empty {}; or similar and then use that instead of V; but that cure is worse than the disease imo.) So, rather than making that change per se, could you add a TODO comment saying that we should define a new CoordsLT which is like ElementLT but doesn't have the V parameter? That way I can remember to fix that in the future since it'd be trivial enough to define the new comparator. Alternatively, could you file a ticket with that same comment and assign it to me? | |
412 | should be prevLvlCoords here too | |
mlir/lib/ExecutionEngine/SparseTensorRuntime.cpp | ||
637 | rename to cref (or more ideally lvlCoordinatesRef) to match the new naming scheme | |
638 | You don't need to assert these, since that's already handled by the ASSERT_NO_STRIDE macro. | |
643–644 | These variables should use the full "size" rather than just "s" | |
646 | Does this really need to be ==? The more liberal thing would be to assert(lvlCoordinatesSize >= reader.getNNZ() * lvlRank); which also matches the liberalness of assert(valuesSize >= reader.getNNZ()). If you really do want equality, then you should use the ASSERT_USIZE_EQ macro instead. (And if you really want >= then you should define a new ASSERT_USIZE_GE/ASSERT_USIZE_LE macro that mirrors ASSERT_USIZE_EQ except for the comparison operator used.) | |
646 | This check should be using lvlRank instead, since that's what the buffer actually needs to store. Of course, there's no way to get the lvlRank from the reader itself, so you'll need to pass it in as an additional argument to this function. | |
647 | "enough" | |
648–649 | Since you don't need the ps variable anywhere other than this assertion, you should use the ASSERT_USIZE_EQ macro instead. | |
654 | should be lvlCoordinates to match the name in the readToBuffers method |
Address review comments: use ASSERT_USIZE_EQ, rename dimRank to lvlRank, fix comments.
mlir/include/mlir/ExecutionEngine/SparseTensor/File.h | ||
---|---|---|
408 | The comment "We set isSorted to false to read the first element" feels like you are actively setting it here instead of above (where you also comment on that). I think here it should read "// Note that isSorted was set to false while reading the first element to...." |
does it really say, "function-liked"?