This is an archive of the discontinued LLVM Phabricator instance.

[CodeGen] Reuse stack space from unused function results (with more accurate unused result detection)
ClosedPublic

Authored by lenykholodov on May 26 2015, 3:12 PM.

Details

Summary

This patch fixes issues with unused result detection which were found in patch http://reviews.llvm.org/D9743.

For detection of unused result the method CodeGenFunction::EmitCall uses similar approach to Sema::DiagnoseUnusedExprResult. Sema::DiagnoseUnusedExprResult uses underlying method Expr::isUnusedResultAWarning(const Expr *&WarnExpr, SourceLocation &Loc, SourceRange &R1, SourceRange &R2, ASTContext &Ctx) for accurate detection. This method has few drawbacks for using outside of Sema class:

  • it checks warn_unused_result attribute which in general case is not set;
  • it modifies several parameters which are not required for unused result checking.

In general case, we want to see smth similar to this method but without warn_unused_attribute checking and without modifiable parameters. The most expected solution in this case may be to provide Expr::isUnusedResult method which the method isUnusedResultAWarning method should use. However, this can't be easily done because in this case all context information for diagnostic should be detected repeatedly inside isUnusedResultAWarning method. Same for warn_unused_attribute. Another solution might be to duplicate logic of isUnusedResultAWarning inside inUnusedResult, but this duplication is too big (few hundred LOC). Moreover, all changes inside isUnusedResultAWarning should be duplicated inside isUnusedResult too. So this doesn't look acceptable.

This patch provides solution which uses isUnusedResultAWarning as an underlying method for isUnusedResult. It extends the list of parameters of isUnusedResultAWarning with extra parameter alwaysWarnIfUnused (default value is false). Based on the isUnusedResult method patch detects unused result during the code generation.

Diff Detail

Repository
rL LLVM

Event Timeline

lenykholodov retitled this revision from to [CodeGen] Reuse stack space from unused function results (with more accurate unused result detection).
lenykholodov updated this object.
lenykholodov edited the test plan for this revision. (Show Details)
lenykholodov added a reviewer: rnk.
lenykholodov set the repository for this revision to rL LLVM.
lenykholodov added a subscriber: Unknown Object (MLST).
rnk edited edge metadata.May 27 2015, 1:04 PM

I don't think this is the right approach. The code that you're reusing is in theory checking the same thing as codegen, but the implementations are distant, unrelated, and I suspect out of sync. I think this will probably be easier to handle in AggExprEmitter, which has more accurate information about its destinations.

You might also want to use the cleanup mechanism instead of trying to manually insert IR after emitting the function call. We should probably add a helper for pushing a CallLifetimeEnd cleanup that takes the slot address and size.

asl added a subscriber: asl.May 28 2015, 1:37 PM
lenykholodov updated this revision to Diff 26798.EditedMay 29 2015, 11:28 AM
lenykholodov edited the test plan for this revision. (Show Details)
lenykholodov edited edge metadata.
lenykholodov added subscribers: rengolin, chapuni.

Reid, first of all thank you very much for your comments. I've updated the implementation. Now I make decision about result usage inside CodeGenFunction::EmitAggExpr method. For an unused result I have incoming expression with type CallExpr. But for the used result I have two calls of EmitAggExpr method second of which has incoming expression with type MaterializeTemporaryExpr. So I decided to mark result as used in case of incoming MaterializeTemporaryExpr expression and to mark result as unused in other cases.

In the current implementation I don't use automatically cleanup mechanism for CallLifetimeEnd. I want to prepare it in separate patch.

rnk added a comment.May 29 2015, 1:33 PM

Can you add some negative lifetime tests? These would be corner case situations like the original Twine bug where we thought the call result was unused but it's actually consumed by someone.

lib/CodeGen/CGExprAgg.cpp
1398 ↗(On Diff #26798)

This condition doesn't seem right. You can Slot.isIgnored(), which should do the trick, though. :)

Changes:

  • Slot.isIgnored() is used for detection of unused result;
  • test case 'large_combiner_test()' has been added; it doesn't work with previous patch (D9743) and works now; after codegen this test has no lifetime scope, and clang detects results of internal calls as used.
rnk added inline comments.Jun 4 2015, 5:18 PM
lib/CodeGen/CGCall.h
158–159 ↗(On Diff #26977)

There's another low alignment bit here, you should really fold it in here to keep this thing pointer-sized. You can either nest PointerIntPair<> twice or use PointerIntPair<llvm::Value *, 2, unsigned> Value and then do bitwise arithmetic in the helpers.

lib/CodeGen/CGExprAgg.cpp
65 ↗(On Diff #26977)

You can follow the convention for Dest and name the parameter after the member with the same case. It's correct.

  • ReturnValueSlot class size optimization using packed to PointerIntPair<> flags;
  • minor changes.
rnk accepted this revision.Jun 5 2015, 6:26 PM
rnk edited edge metadata.

lgtm, let's give it a shot

This revision is now accepted and ready to land.Jun 5 2015, 6:26 PM
This revision was automatically updated to reflect the committed changes.