This is an archive of the discontinued LLVM Phabricator instance.

Fix for crash during SjLj preparation step
ClosedPublic

Authored by vhbit on Jun 23 2014, 7:52 AM.

Details

Summary

This crash was pretty common while compiling Rust for iOS (armv7). Reason - SjLj preparation step was lowering aggregate arguments as ExtractValue + InsertValue. ExtractValue has assertion which checks that there is some data in value, which is not true in case of empty (no fields) structures. Rust uses them quite extensively so this patch skips ExtractValue + InsertValue in case of empty struct or empty array.

Diff Detail

Event Timeline

vhbit updated this revision to Diff 10755.Jun 23 2014, 7:52 AM
vhbit retitled this revision from to Fix for crash during SjLj preparation step.
vhbit updated this object.
vhbit edited the test plan for this revision. (Show Details)
vhbit set the repository for this revision to rL LLVM.
vhbit added a subscriber: Unknown Object (MLST).Jun 23 2014, 11:30 PM
void added a subscriber: void.Jul 2 2014, 12:21 PM

This is crying out for a testcase. Can you supply one?

lib/CodeGen/SjLjEHPrepare.cpp
255

This comment should go inside of the 'if (ST || AT) {' block. Also, no need to mention specific languages. Something like this:

An aggregate type with no fields (e.g., an empty struct) cannot have
extract/insert instructions applied to it. In this case, there is no need to
// transfer anything.

258

I'm worried about doing this. The purpose of this function is to lower the arguments so that we don't have to handle them with special code. If we do this, we are now allowing the empty aggregate to be live outside of the entry block. Actually, this whole code seems suspect to me. One way around both the original problem and your problem would be to use another instruction that would satisfy both. This one is off the top of my head:

define @foo([i8, i32] %a) {

%new_a = select i1 true, [i8, i32] %a, [i8, i32] null
...

}

Could you convert this block of code to do that and see if it still works?

vhbit updated this revision to Diff 11076.Jul 4 2014, 1:07 AM

Added a test case and used 'select' as Bill proposed.

Still need advice if it is possible to unify both aggregate type branches into one, as I'm not sure if there is a combination of codegen/optimization flags which might not eliminate loading from null.

void added a comment.Jul 9 2014, 12:51 AM
In D4256#10, @vhbit wrote:

Still need advice if it is possible to unify both aggregate type branches into one, as I'm not sure if there is a combination of codegen/optimization flags which might not eliminate loading from null.

If there is a combination of flags that will result in a load from 'null', then it's a bug and will need to be fixed. The best way to guard against something like this is to create tests to make sure that the expected ASM is emitted.

I would modify the test you added here so that it checks for the expected ARM ASM once it runs through llc. Also, expand the testcase a bit, adding optimizations, etc. You won't be able to check all combinations of flags, nor should you need to. But at least check at every llc '-O' level.

test/CodeGen/Thumb/sjljehprepare-lower-empty-struct.ll
1 ↗(On Diff #11076)

Please put this in test/CodeGen/ARM. It's not thumb-specific.

5 ↗(On Diff #11076)

I don't think you need the 'target *' lines here.

7 ↗(On Diff #11076)

The arguments aren't used in the code. Could you modify the testcase so that they are used outside of the entry basic block?

vhbit updated this revision to Diff 11209.Jul 9 2014, 10:32 AM

Cleaned up test file, moved to ARM, added checks for all optimization levels.

void added inline comments.Jul 9 2014, 3:44 PM
lib/CodeGen/SjLjEHPrepare.cpp
277

You don't need to do this. Just use the 'null' value directly. :-)

void added a comment.Jul 9 2014, 3:52 PM

I think there's some misunderstanding of what I'd like to see here. (I confused things by using 'null' for the example.) This is the type of code I was thinking of:

def void @foo({} %c) {
    %fake_c = select i1 true, {} %c, {} undef
    ; subsequent uses of %fake_c in the code.

This should be valid for all types, whether they are aggregates or not. So you can replace the whole of that code with just this.

vhbit updated this revision to Diff 11242.Jul 9 2014, 9:17 PM

Switched to using undef => code simplification and unification of 2 branches

void added inline comments.Jul 9 2014, 10:43 PM
lib/CodeGen/SjLjEHPrepare.cpp
255

Nit: You don't need the line break before this sentence. :-)

258

Watch out for 80-column violations here.

267

Now that we have the above code, I think we can use it for this situation as well. However, you can do that as a separate commit.

vhbit updated this revision to Diff 11243.Jul 9 2014, 11:12 PM

Fixed too wide line.
Yep, I think that a complete unification should be done in a separate commit

void accepted this revision.Jul 10 2014, 12:31 AM
void added a reviewer: void.
This revision is now accepted and ready to land.Jul 10 2014, 12:31 AM
Eugene.Zelenko added a subscriber: Eugene.Zelenko.

Committed in rL212922.