This is an archive of the discontinued LLVM Phabricator instance.

[WebAssembly] Do not emit tail calls with return type mismatch
ClosedPublic

Authored by tlively on Jul 24 2019, 3:16 PM.

Details

Summary

return_call and return_call_indirect are only valid if the return
types of the callee and caller match. We were previously not enforcing
that, which was producing invalid modules.

Diff Detail

Repository
rL LLVM

Event Timeline

tlively created this revision.Jul 24 2019, 3:16 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 24 2019, 3:16 PM
aheejin added inline comments.Jul 24 2019, 7:14 PM
llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
649 ↗(On Diff #211610)

It's preexisting, but GuaranteedTailCallOpt's description says:

When the flag is on, participating targets will perform tail call optimization on all calls which use the fastcc calling convention and which satisfy certain target-independent criteria (being at the end of a function, having the same return type as their parent function, etc.), using an alternate ABI if necessary.

Does this mean, should we at least try to do tail calls even if CLI.IsTailCall is not true, i.e., there is no tailcall property in the instruction of .ll file? If so, it seems the check for this condition should be outside of if (CLI.IsTailCall). Let me know if I'm mistaken.

664 ↗(On Diff #211610)

We don't call fail in this case?

672 ↗(On Diff #211610)

I'm unsure how the user interface should work. When should we error out and when should we silently switch to non-tail calls? I might be mistaken, but it looks to me that unless CLI.CS.isMustTailCall() is true we don't need to error out, no? But currently MustTail contains much broader conditions, so I'm wondering what the UI should look like.

tlively updated this revision to Diff 212019.Jul 26 2019, 4:14 PM
  • Record proper return types for indirect tail calls as well
tlively marked 3 inline comments as done.Jul 26 2019, 5:01 PM
tlively added inline comments.
llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
649 ↗(On Diff #211610)

I don't believe this is necessary. I checked and neither RISCV nor AArch64 try to do tail calls unless CLI.IsTailCall is true. There is some pass that runs that marks all possible tail calls as tail, so I guess in the common case at least it would be duplicating effort to check again so late in the backend.

664 ↗(On Diff #211610)

It should be an LLVM IR-level validation error if the prototypes of callers and their musttail callees do no match, so we should never observe this condition. I will add a comment.

672 ↗(On Diff #211610)

RISCV and AArch only error out when CLI.CS.isMustTailCall() is true, as you say. I will update this code to match that behavior.

tlively updated this revision to Diff 212034.Jul 26 2019, 6:24 PM
tlively marked 2 inline comments as done.
  • Address comments, add a few more tests
tlively updated this revision to Diff 212043.Jul 26 2019, 8:11 PM
  • Do not allow varargs tail calls
aheejin added inline comments.Jul 29 2019, 3:11 PM
llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
649 ↗(On Diff #212043)

Would we need a test case for vararg too?

677 ↗(On Diff #212043)

Should we document about these restrictions (such as no vararg) here too, like other platforms?

llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
238 ↗(On Diff #212043)

Why should we do this? Is the return type of the tail-called function different from that of the caller? If so, wouldn't we have already disabled tail calling in ISelLowering as you did above?

llvm/test/CodeGen/WebAssembly/tailcall.ll
215 ↗(On Diff #212043)

I'm not sure what this test is trying to test..?

tlively marked 5 inline comments as done.Jul 29 2019, 5:55 PM
tlively added inline comments.
llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
649 ↗(On Diff #212043)

There already is one that was updated for this change.

677 ↗(On Diff #212043)

Yes, I'll add documentation.

llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
238 ↗(On Diff #212043)

Up above the return types for the current machine instruction (Returns) are determined from the instruction's defs. But return_calls do not have defs, so we need this extra code to record their return types by examining the caller's return type.

llvm/test/CodeGen/WebAssembly/tailcall.ll
215 ↗(On Diff #212043)

This tests that we get the ReturnType: I32 correctly. Without the change you asked about above we incorrectly determine that the return type is none.

tlively updated this revision to Diff 212260.Jul 29 2019, 6:00 PM
  • Update documentation
aheejin accepted this revision.Jul 29 2019, 6:17 PM

LGTM!

llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
649 ↗(On Diff #212043)

Oh I didn't see it, sorry.

This revision is now accepted and ready to land.Jul 29 2019, 6:17 PM
This revision was automatically updated to reflect the committed changes.