This is an archive of the discontinued LLVM Phabricator instance.

Fix failure to invoke exception handler on Win64.
ClosedPublic

Authored by vadimcn on Aug 1 2014, 1:39 AM.

Details

Summary

Fixes an obscure Win64 unwinding failure which I've stumbled upon. Please see comments for details.
MSVC does the same, btw.

Diff Detail

Event Timeline

vadimcn updated this revision to Diff 12096.Aug 1 2014, 1:39 AM
vadimcn retitled this revision from to Fix failure to invoke exception handler on Win64..
vadimcn updated this object.
vadimcn edited the test plan for this revision. (Show Details)
vadimcn added a reviewer: rnk.
vadimcn added a subscriber: Unknown Object (MLST).
vadimcn updated this revision to Diff 12098.Aug 1 2014, 2:48 AM
rnk added inline comments.Aug 1 2014, 11:16 AM
lib/Target/X86/X86FrameLowering.cpp
838

This seems like a do { } while (...) loop.

844

Does this not return one-past-the-end?

That aside, I don't think this will work in general, because basic block placement runs *after* prologue-epilogue insertion.

For now I think we should always insert a nop if the epilogue is at the beginning of a basic block, just to be safe. The actual solution is probably to insert some kind of target-specific pseudo that we lower out after block placement to either a nop or nothing.

test/CodeGen/X86/win64_call_epi.ll
1

Does this fail without -O0? Just curious.

3

Can you come up with a test case that fails when block placement runs? Something like this maybe:

define void @bar(i1 zeroext %cond ) {
  br i1 %cond, label %a, label %b  ; <- Add metadata to indicate that %a is *highly* likely over %b.
a:
  call void @foo()
  br label %done
b:
  call void @baz()
  store i32 0, i32* @something
  br label %done
done:
  ret void
}
vadimcn added inline comments.Aug 1 2014, 11:39 AM
lib/Target/X86/X86FrameLowering.cpp
844

Does this not return one-past-the-end?

Hmm, yes it probably does.

That aside, I don't think this will work in general, because basic block placement runs *after* prologue-epilogue insertion.

I can make it do what you suggest, though I think that 'ret' starts out in a MBB of its' own quite often.

The actual solution is probably to insert some kind of target-specific pseudo that we lower out after block placement to either a nop or nothing.

I was considering creating 'SEH_Epilogue' pseudo, then checking for preceding CALLs when lowering it in X86AsmPrinter. Unfortunately, some pseudos, like EH_LABEL, are not lowered till the last moment, so it'd still have to have logic to skip those.
How does that sound?

test/CodeGen/X86/win64_call_epi.ll
1

No, it still works. Just something I copied from another test...

3

Yeah, this breaks it. :(
Okay, that probably means I am gonna have to go with the SEH_Epilogue approach...

rnk added inline comments.Aug 1 2014, 11:54 AM
lib/Target/X86/X86FrameLowering.cpp
844

The SEH_Epilogue pseudo sounds good, even with exciting logic to skip non-instruction pseudos.

vadimcn updated this revision to Diff 12127.Aug 1 2014, 5:11 PM

Implemented 'SEH_Epilogue' approach.

rnk accepted this revision.Aug 4 2014, 1:15 PM
rnk edited edge metadata.

lgtm

I guess I'll apply this with the suggested tweaks, to save a round trip. Thanks for the patch!

lib/Target/X86/X86MCInstLower.cpp
982–983 ↗(On Diff #12127)

Usually when you declare locals in a case label like this you need to wrap it in braces. There are no subsequent cases today, but you should go ahead and wrap it now.

986 ↗(On Diff #12127)

I think some pseudos emit real code, so I would soften this to say that by assuming they aren't real, we will conservatively emit a nop in more cases than is absolutely necessary.

This revision is now accepted and ready to land.Aug 4 2014, 1:15 PM
rnk closed this revision.Aug 4 2014, 7:27 PM

Grumble grumble auto close why doesn't this work.