Skip to content
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

Fix slice to empty not being converted to FullOp #3882

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

jacobhinkle
Copy link
Collaborator

This fixes an issue noticed by @naoyam, where a simple fusion containing a dynamic slice does not get properly converted to a NoOp in the case when the output size is zero. This was happening because the resized iterdomain was being concretized as Iteration first, after which the extent was replaced by zero. However, the extent that was replaced in that case was the old one, not the extent of the replaced IterDomain. The fix is to first concretize empty extents as zero before doing anything else, then taking care to respect mutated extents when doing other concretizations. In particular, we need to doctor the extents that get resized if their inputs' extents have already been concretized.

@jacobhinkle jacobhinkle requested a review from naoyam February 13, 2025 14:03
@jacobhinkle
Copy link
Collaborator Author

!test

Copy link

github-actions bot commented Feb 13, 2025

Review updated until commit ed89fbe

Description

  • Fix slice to empty not being converted to FullOp

  • Use mutated input in resize concretization

  • Enhance concretization of empty extents

  • Add test case for slice to zero


Changes walkthrough 📝

Relevant files
Enhancement
dynamic_transform.cpp
Enhance concretization of empty extents and resize             

csrc/dynamic_transform.cpp

  • Add concretizeEmptyExtents() call at the beginning of concretize()
  • Use maybeMutated() for inputs in concretizeResize()
  • Update concretizeExpand() to use mutated extent
  • +30/-11 
    Bug fix
    nodes.cpp
    Update resize method for symbolic inputs                                 

    csrc/ir/nodes.cpp

    • Modify IterDomain::resize() to check if in is not symbolic
    +2/-1     
    Tests
    test_resize.cpp
    Add test for slice to zero                                                             

    tests/cpp/test_resize.cpp

    • Add test case SliceToZero for slice to zero conversion
    +32/-0   

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    🧪 PR contains tests
    ⚡ Recommended focus areas for review

    Order of Operations

    The order of operations in the concretize method has been changed. Ensure that this change does not introduce any unintended side effects or dependencies between the concretization steps.

    // Registers replacement of all empty extents with zeroVal()
    concretizeEmptyExtents();
    
    Extent Mutation Handling

    The handling of mutated extents in concretizeResize seems complex. Verify that the logic correctly handles all cases of extent mutation, especially when extents are concretized to zero.

    auto new_id = IterDomain::resize(
        def_in,
        maybeMutated(def->leftExpand()),
        maybeMutated(def->rightExpand()),
        id->isRFactorProduct(),
        iter_type);
    
    if (maybeMutated(def_in->extent()) != def_in->extent()) {
      // Note: if the extent of id is mutated, for example by the
      // concretizeEmptyExtents pass, we should also use the mutated extent to
      // compute the output extent.
      Val* new_extent = SimplifyingIrBuilder::addExpr(
          maybeMutated(def->leftExpand()),
          SimplifyingIrBuilder::addExpr(
              maybeMutated(def_in->extent()),
              maybeMutated(def->rightExpand())));
      IterDomain* replacement =
          IterDomainBuilder(new_id).extent(new_extent).build();
      ir_utils::transferDefinitionToNewOutputs(
          new_id->definition(), {replacement});
      new_id = replacement;
    }
    Symbolic IterDomain Check

    The check if (!in->isSymbolic() && left_expansion->isConstInt() && right_expansion->isConstInt()) might exclude some valid cases. Ensure that the logic is correct and does not unintentionally skip valid resizes.

    if (!in->isSymbolic() && left_expansion->isConstInt() &&
        right_expansion->isConstInt()) {
      auto left = left_expansion->evaluate();

    auto tv0 = makeSymbolicTensor(1);
    fusion.addInput(tv0);

    auto tv1 = slice(tv0, {{fusion.zeroVal(), fusion.zeroVal()}});
    Copy link
    Collaborator Author

    Choose a reason for hiding this comment

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

    Note that we could probably detect patterns like this in the slice op and just translate those to FullOp right away without relying on concretization. I think the attached fix should handle cases where the slice arguments are dynamic.

    csrc/dynamic_transform.cpp Outdated Show resolved Hide resolved
    @jacobhinkle
    Copy link
    Collaborator Author

    !test

    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.

    2 participants