[cfe-dev] [PATCH] For loop migration tool (round 1) - patch 2

Sam Panzer panzer at google.com
Mon Aug 13 18:21:54 PDT 2012


Here's my next attempt!

On Mon, Aug 13, 2012 at 6:45 AM, Manuel Klimek <klimek at google.com> wrote:

>
> High-level comment about "using std::string" and similar: this is not
> done anywhere else in clang/llvm, so I'd suggest not to start doing
> it...
> I again have the feeling that not everything I'd like to be tested is
> tested, but this time it's harder for me to put my finger on it :)
>

That's partly because I hadn't included all the tests that could be added
at this point. They're in now.gg


>
> +struct LoopFixerArgs {
> +  tooling::Replacements *Replace;
> +  DeclMap *GeneratedDecls;
> +  ReplacedVarsMap *ReplacedVarRanges;
> +};
>
> What's the reason to not make those fields in LoopFixer?
>

The only reason apparent in this patch is to keep doConversion static
within LoopActions.cpp, though in another few patches I reuse this struct
across three LoopFixers (one per kind of convertible loop). Is there a
better way to arrange this? (LoopFixerArgs ends up with 10 parameters by
the end.)


>
> +  for (const Stmt *Prev = Curr; Curr != NULL;
> +       Prev = Curr, Curr = StmtParents->lookup(Prev))
>
> It would seem simpler to me to write that as:
> while(Curr != NULL) {
>   ...
>   Curr = StmtParents->lookup(Curr);
> }
>

Agreed. Switched to a while loop.


>
> or, if you really prefer for loops (llvm isn't consistent here)
> for (; Curr != NULL; Curr = StmtParent->lookup(Curr))
>
> +  /// Run the analysis on Body, and return true iff the expression
> depends on
> +  /// some variable declared within ContainingLoop.
> +  bool isExternallyDependent(const Stmt *Body) {
>
> I'm not sure I get the name: why is it "externally dependent" if it
> depends on a variable within the loop? What does "externally" mean in
> that context?
>

It's external to ContainingLoop. A full description would be "expression
has a free variable in the lexical context of the specified loop," which
would mean that hoisting Body outside of ContainingLoop would result in a
syntactic (variable not defined) or semantic (identifier refers to a
different variable) error. I'm going with dependsOnOutsideVariable for now.
Is hasFreeVariableInStmt a better name?

While I was at it, I also renamed ContainingLoop to ContainingStmt.


> +  /// Attempts to find any usages of variables name Name in Body,
> returning
> +  /// true when it is only used as an array index. A list of usages and
> +  /// the arrays TargetVar indexes are also tracked.
>
> Is that comment correct? From the implementation it looks like we
> abort traversal when we find the first match.
>

The comment was way off after the first line. Fixed.


>
> +  DeclFinderASTVisitor(const std::string &Name,
> +                       const DeclMap *GeneratedDecls) :
>
> Please document what GeneratedDecls is here...
>

It was somewhat opaque; comments added. That's what I use to track the
loop-to-generated-variable-name mapping.


>
> +  friend class RecursiveASTVisitor<DependencyFinderASTVisitor>;
>
> Why's that necessary?
>

CRTP + private overrides. This way, the VisitXXX functions don't have to be
public.


>
> +class DeclFinderASTVisitor : public
> RecursiveASTVisitor<DeclFinderASTVisitor> {
> + private:
> +  const std::string &Name;
>
> I'd strongly vote for making this a copy, as otherwise it's really
> easy to introduce errors by handing in temps.
>

Done.


>
> +// Generates the name to be used for an inserted iterator. It reliles on
> +// declarationExists() to determine that there are no naming conflicts,
> and
> +// tries to use some hints from the container name and the old index name.
> +
> +string VariableNamer::createIndexName() {
>
> s/reliles/relies/
>

Done.


>
> Also, put the comment to the method.
>

Do you mean move the comment to the .h file? Done.


>
> +bool VariableNamer::declarationExists(const string& Symbol) {
> +  IdentifierInfo& Identifier = Context->Idents.get(Symbol);
> +  DeclarationName Name =
> +      Context->DeclarationNames.getIdentifier(&Identifier);
> +
> +  // First, let's check the parent context.
> +  // FIXME: lookup() always returns the pair (NULL, NULL) because its
> +  // StoredDeclsMap is not initialized (i.e. LookupPtr.getInt() is false
> inside
> +  // of DeclContext::lookup()). Why is this?
> +  // NOTE: We work around this by checking when a shadowed declaration is
> +  // referenced, rather than now.
> +  for (const DeclContext *CurrContext = LoopContext; CurrContext != NULL;
> +       CurrContext = CurrContext->getLookupParent()) {
> +    DeclContext::lookup_const_result Result = CurrContext->lookup(Name);
> +    if (Result.first != Result.second)
> +        return true;
> +  }
> +
> +  // Next, iterate through child contexts.
>

The above comment was incorrect. Fixed.


> +  for (const Stmt *S = SourceStmt; S != NULL; S = ReverseAST->lookup(S)) {
> +    DeclMap::const_iterator I = GeneratedDecls->find(S);
> +    if (I != GeneratedDecls->end() && I->second == Symbol)
> +      return true;
> +  }
> +  DeclFinderASTVisitor DeclFinder(Symbol, GeneratedDecls);
> +  return DeclFinder.findUsages(SourceStmt);
>
> Are all those return paths tested?
>
>
>
The first one doesn't fire on my tests due to the problem documented at the
top of this function. The others have tests in loop-convert-nesting.cpp and
loop-convert-naming.cpp (I didn't attach loop-convert-naming.cpp to the
original patch.), though they needed fixing due to a FileCheck quirk.


>
>
> On Sat, Aug 4, 2012 at 1:14 AM, Sam Panzer <panzer at google.com> wrote:
> > Here are three patches which constitute most of the work needed for the
> > for-loop migration tool. The first contains the contents of the tutorial
> > from earlier this week, with extra comments and rebased into
> > clang/tools/extra/. The second patch fixes most of the correctness
> > assumptions that the naive tool makes (e.g. conflicting edits, name
> > conflicts), and the third adds some command-line flags along with a trick
> > for eliding a variable declared as a reference to the array access.
> >
> > Together, they provide a nearly complete converter for array-based loops
> -
> > the three optional features I didn't rebase into the patches involve
> using
> > an explicit type rather than auto, adding const when possible, and making
> > the loop variable a non-reference type for non-aggregate types if
> possible.
> >
> > There is one potentially problematic assumption that I haven't fixed yet:
> > the array expression is assumed not to change, as this becomes difficult
> to
> > verify when the code iterates over a compound expression such as
> > graph.nodes->getInputs(). In most cases, the loop will probably be
> > convertible if it passes all other checks, so I intend to offer a flag
> that
> > tells the loop converter whether or not to make these usually-okay
> changes.
> >
> > I also have two more patches in the works for next week, which add
> support
> > for iterator-based loops and loops over array-like containers.
> >
> > Thoughts?
> >
> > -Sam
> >
> >
> > _______________________________________________
> > cfe-dev mailing list
> > cfe-dev at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20120813/334a4bc1/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: loop-converter-2.patch
Type: application/octet-stream
Size: 33637 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20120813/334a4bc1/attachment.obj>


More information about the cfe-dev mailing list