Replace ApplyInst with an IntegerLiteral

I have an ApplyInst that I want to replace with an IntegerLiteral. But, when I call replaceAllUsesWith on the ApplyInst I get an assertion failure in getParentDecl (SILInstruction.h, line 572).

Should I be using replaceAllUsesWith or something else? What is the reason for this failure?

Would you be able to share the patch you're working with?

If you mean this assertion at line 5732:

  NominalTypeDecl *getParentDecl() const {
    auto s = getOperand(0)->getType().getNominalOrBoundGenericNominal();
    assert(s);
    return s;
  }

That suggests that the types of the new instruction and the old don't match up, and it's expecting the type of the operand to be a nominal type (a struct, enum, or class). An ApplyInst for a typical Swift function that returns an Int would return the Int struct defined in the standard library, but an IntegerLiteral instruction by itself creates a Builtin.IntNN value. You might need to also wrap it in an Int by creating a struct instruction, and replacing your apply with the struct.

@Joe_Groff Thanks for the help! I will try wrapping it in an Int type (the ApplyInst returns a Bool but, either should work).

That is the function I am talking about. I think my repository is a bit out of date.

Here is the diff if you don't mind taking a look. Edit: keep in mind, this patch is still very much a work in progress. I will probably pull most of that code into another function and maybe put it in a different file.

A Bool would have the same issue. IntegerLiteral produces a Builtin.Int1 which would need to be wrapped in the Bool struct.

If you can tell us what optimization you're doing, we might be able to help with suggestions for how to fit more cleanly into the stdlib/Builtin divide. For example, most of the existing constant-folding optimizations just operate on Builtin functions, which return Builtin types, and the existing optimizations to peephole struct_extract(struct) take care of the extra abstraction around Bool, Int, etc.

2 Likes

I'm trying to constant fold string comparison instructions. For example, the following:

func test() -> Int {
  let i = "3"
  switch i {
      case "1": return 1
      case "2": return 2
      default: return 3
  }
}

would simply return 3.

3 Likes

Ah. So you're recognizing the call to the stdlib's string-equality function with constant-string arguments and then performing the comparison statically? That seems like a great optimization, and it should be straightforward in at least the ASCII cases; @Michael_Ilseman probably has ideas about how best to recognize those. In non-ASCII cases, I don't think we currently build the Unicode composition tables into the compiler, and I don't know if there's a future-proofing argument against trying to.

It's tempting to say that we could actually just define a builtin function to do string comparison and have that builtin function magically call back into the stdlib if it isn't folded away, but that might make stdlib development unnecessarily difficult. We do have some places in SILGen — and maybe also the SIL optimizer — that know how to wrap a Builtin type back up into a stdlib type; it would be reasonable to just put those routines on something more prominent like SILBuilder.

2 Likes

I'd think it'd be safe, and likely good enough for common case, to just assume that string literals with identical code unit sequences are equal for constant folding purposes.

1 Like

Yes, that is exactly what I am trying to do.

Wrapping the integer literal in a swift int seems reasonable. I'll try that.

Thanks for all the help!

2 Likes

It might also be interesting to add an assertion to replaceAllUsesWith that the new instruction matches the type of the instruction being replaced. It seems like that would highlight the problem more obviously in your use case. (For the places where we might intentionally change the type as part of a more complex transform, we could add a boolean argument to say "yes, I intend to change the type" and suppress the assertion.)

They need to be able to fold equality to false to optimize the test case above.

Ah, I see what you're saying now. Yeah, we'd only be able to definitively fold to "false" for ASCII strings without carrying around Unicode tables in the compiler.

Fantastic! Worked like a charm. Expect a patch soon :)

2 Likes

@Joe_Groff and @John_McCall thanks again for the help. Here is the PR if you are interested: Constant fold string comparisons by zoecarver · Pull Request #27551 · apple/swift · GitHub