<div dir="ltr"><div>I like the idea of piggybacking some analysis in the LLVM IR. However, I have some concerns as well. I am not well versed in the LLVM optimizer, but I do see potential side effects. E.g. what if a static function is inlined to ALL call sites, thus the original function can be removed. We will no longer be able to get all the useful info for that function? It would be unfortunate if the analysis result would depend on inlining heuristics. It would make the analyzer even harder to debug or understand.<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 6 Aug 2020 at 19:20, Artem Dergachev via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
  
    
  
  <div>
    Umm, ok!~<br>
    <br>
    Static analysis is commonly run in debug builds and those are
    typically unoptimized. It is not common for a project to have a
    release+asserts build but we are relying on asserts for analysis, so
    debug builds are commonly used for analysis. If your project
    completely ignores debug builds its usefulness drops a lot.<br>
    <br>
    Sounds like we want to disconnect this new fake codegen from
    compiler flags entirely. Like, the AST will depend on compiler
    flags, but we should not be taking -O flags into account at all, but
    pick some default -O2 regardless of flags; and ideally all flags
    should be ignored by default, to ensure experience as consistent as
    possible.<br>
    <br>
    You'd also have to make sure that running CodeGen doesn't have
    unwanted side effects such as emitting a .o file.<br>
    <br>
    Would something like that actually work?<br>
    <br>
    And if it would, would this also address the usual concerns about
    making warnings depend on optimizations? Because, like,
    optimizations now remain consistent and no longer depend on
    optimization flags used for actual code generation or interact with
    code generation; they're now simply another analysis performed on
    the AST that depends solely on the AST.<br>
    <br>
    <div>On 8/6/20 2:06 AM, Gábor Márton wrote:<br>
    </div>
    <blockquote type="cite">
      
      <div dir="ltr">
        <div dir="ltr">> you're "just" generating llvm::Function for
          a given AST FunctionDecl "real quick" and looking at the
          attributes. This is happening on-demand and cached, right?</div>
        <div>This works differently. We generate the llvm code for the
          whole translation unit during parsing. It is the Parser and
          the Sema that calls into the callbacks of the CodeGenerator
          via the ASTConsumer interface. This is the exact same
          mechanism that is used for the Backend (see the
          BackendConsumer). We register both the CodeGenerator ast
          consumer and the AnalysisAstConsumer with the AnalysisAction
          (we use a MultiplexConsumer). By the time we start the
          symbolic execution in AnalysisConsumer::HandleTranslationUnit,
          the CodeGen is already done (since CodeGen is added first to
          the MultiplexConsumer so its HandleTranslationUnit and other
          callbacks are called back earlier). About caching, the llvm
          code is cached, we generate that only once, then during the
          function call evaluation we search it in the llvm::Module
          using the mangled name as the key (we don't cache the mangled
          names now, but we could).</div>
        <div>It would be possible to directly call the callbacks of the
          CodeGenerator on-demand, without registering that to the
          FrontendAction. Actually, my first attempt was to call
          HandleTopLevelDecl for a given FunctionDecl on demand when we
          needed the llvm code. However, this is a false attempt for the
          following reasons: (1) Could not support ObjC/C++ because I
          could not get all the information that the Sema has when it
          calls to HandleTopLevelDeclInObjCContainer. In fact, I think
          it is not supported to call these callbacks directly, just
          indirectly through a registered ASTConsumer because we may not
          know how the Parser and the Sema calls to these. (2) It is not
          enough to get the llvm code for a function in isolation.
          E.g., for the "readonly" attribute we must enable alias
          analysis on global variables (see GlobalsAAResult), so we must
          emit llvm code for global variables.</div>
        <div><br>
        </div>
        <div>> 1.1. But it sounds like for the CTU users it may
          amplify the imperfections of ASTImporter.</div>
        <div>> 2.1. Again, it's worse with CTU because imported ASTs
          have so far never been tested for compatibility with CodeGen.</div>
        <div>We should not call the CodeGen on a merged AST. ASTImporter
          does not support the ASTConsumer interface. In the case of
          CTU, I think we should generate the IR for each TU in
          isolation. And we should probably want to extend the
          CrossTranslationUnit interface to give back the llvm::Function
          for a given FunctionDecl. Or we could make this more
          transparent and the IRContext in this prototype could be CTU
          aware.</div>
        <div><br>
        </div>
        <div>> Just to be clear, we should definitely avoid having
          our analysis results depend on optimization levels. It should
          be possible to avoid that, right? </div>
        <div>There is a dependency we will never be able to get rid of:
          CodeGen generates<a href="https://llvm.org/docs/LangRef.html#memory-use-markers" target="_blank"> lifetime markers</a> only when the
          optimization level is greater or eq to 2 (-O2, -O3) .These
          lifetime markers are needed to get the precise pureness info
          out of GlobalsAA.</div>
        <div><br>
        </div>
        <div>> The way i imagined this, we're only interested in
          picking up LLVM analyses, which can be run over unoptimized IR
          just fine(?)</div>
        <div>Yes, but we need to set the optimization level so CodeGen
          generates lifetime markers. Indeed, there are many llvm
          analyses that simply do not change the IR and just populate
          their results. And we could simply use the results in CSA.<br>
        </div>
        <div>> We should probably not be optimizing the IR at all in
          the process(?)<br>
        </div>
        <div>Some llvm passes may invalidate the results of previous
          analyses and then we need to rerun those. I am not an expert,
          but I think if we run an analysis again after another analysis
          that optimizes the IR (i.e truncates it) then our results
          could be more precise. And that is the reason why we see
          multiple passes for the same analyses when we do
          optimizations. And perhaps this is the exact job of the
          PassManager to orchestrate this (?). </div>
        <div>There are passes that extend the IR
          (e.g InferFunctionAttrsPass), we may not need these strictly
          speaking, but I really don't know how the different analyses
          use the function attributes.<br>
        </div>
        <div>Maybe we need the IR both in unoptimized form and in
          optimized form. Also, we may want to have our own CSA specific
          pipeline, but having the default O2 pipeline seems to simplify
          things.</div>
        <br>
        <div class="gmail_quote">
          <div dir="ltr" class="gmail_attr">On Wed, Aug 5, 2020 at 11:22
            PM Artem Dergachev <<a href="mailto:noqnoqneo@gmail.com" target="_blank">noqnoqneo@gmail.com</a>>
            wrote:<br>
          </div>
          <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
            <div> Just to be clear, we should definitely avoid having
              our analysis results depend on optimization levels. It
              should be possible to avoid that, right? The way i
              imagined this, we're only interested in picking up LLVM
              analyses, which can be run over unoptimized IR just
              fine(?) We should probably not be optimizing the IR at all
              in the process(?)<br>
              <br>
              <div>On 05.08.2020 12:17, Artem Dergachev wrote:<br>
              </div>
              <blockquote type="cite"> I'm excited that this is actually
                moving somewhere!<br>
                <br>
                Let's see what consequences do we have here. I have some
                thoughts but i don't immediately see any architecturally
                catastrophic consequences; you're "just" generating
                llvm::Function for a given AST FunctionDecl "real quick"
                and looking at the attributes. This is happening
                on-demand and cached, right??? I'd love to hear more
                opinions. Here's what i see:<br>
                <br>
                1. We can no longer mutate the AST for analysis purposes
                without the risk of screwing up subsequent codegen. And
                the risk would be pretty high because hand-crafting ASTs
                is extremely difficult. Good thing we aren't actually
                doing this.<br>
                    1.1. But it sounds like for the CTU users it may
                amplify the imperfections of ASTImporter.<br>
                <br>
                2. Ok, yeah, we now may have crashes in CodeGen during
                analysis. Normally they shouldn't be that bad because
                this would mean that CodeGen would crash during normal
                compilation as well. And that's rare; codegen crashes
                are much more rare than analyzer crashes. Of course a
                difference can be triggered by #ifndef
                __clang_analyzer__ but it still remains a proof of valid
                crashing code, so that should be rare.<br>
                    2.1. Again, it's worse with CTU because imported
                ASTs have so far never been tested for compatibility
                with CodeGen.<br>
                <br>
                Let's also talk about the benefits. First of all, *we
                still need the source code available during analysis*.
                This isn't about peeking into binary dependencies and it
                doesn't immediately aid CTU in any way; this is entirely
                about improving upon conservative evaluation on the
                currently available AST, for functions that are already
                available for inlining but are not being inlined for
                whatever reason. In fact, in some cases we may later
                prefer such LLVM IR-based evaluation to inlining, which
                may improve analysis performance (i.e., less path
                explosion) *and* correctness (eg., avoid unjustified
                state splits).<br>
                <br>
                <div>On 05.08.2020 08:29, Gábor Márton via cfe-dev
                  wrote:<br>
                </div>
                <blockquote type="cite">
                  <div dir="ltr">Hi,<br>
                    <div><br>
                    </div>
                    <div>I have been working on a prototype that makes
                      it possible to access the IR from the components
                      of the Clang Static Analyzer.</div>
                    <div><a href="https://reviews.llvm.org/D85319" target="_blank">https://reviews.llvm.org/D85319</a><br>
                    </div>
                    <div><br>
                    </div>
                    <div>There are many important and useful analyses in
                      the LLVM layer that we can use during the path
                      sensitive analysis. Most notably, the "readnone"
                      and "readonly" function attributes (<a href="https://llvm.org/docs/LangRef.html" target="_blank">https://llvm.org/docs/LangRef.html</a>)
                      which can be used to identify "pure" functions
                      (those without side effects). In the prototype I
                      am using the pureness info from the IR to avoid
                      invalidation of any variables during conservative
                      evaluation (when we evaluate a pure function).
                      There are cases when we get false positives
                      exactly because of the too conservative
                      invalidation.</div>
                    <div><br>
                    </div>
                    <div>Some further ideas to use info from the IR:</div>
                    <div>- We should invalidate only the arg regions for
                      functions with "argmemonly" attribute.</div>
                    <div>- Use the smarter invalidation in cross
                      translation unit analysis too. We can get the IR
                      for the other TUs as well.</div>
                    <div>- Run the <a href="https://llvm.org/doxygen/structllvm_1_1Attributor.html" target="_blank">Attributor</a>
                      passes on the IR. We could get range values for
                      return values or for arguments. These range values
                      then could be fed to StdLibraryFunctionsChecker to
                      make the proper assumptions. And we could do this
                      in CTU mode too, these attributes could form some
                      sort of a summary of these functions. Note that I
                      don't expect a meaningful summary for more than a
                      few percent of all the available functions.</div>
                    <div><br>
                    </div>
                    <div>Please let me know if you have any further
                      ideas about how we could use IR attributes (or
                      anything else) during the symbolic execution.</div>
                    <div><br>
                    </div>
                    <div>There are some concerns as well. There may be
                      some source code that we cannot CodeGen, but we
                      can still analyse with the current CSA. That is
                      why I suppress CodeGen diagnostics in the
                      prototype. But in the worst case we may run into
                      assertions in the CodeGen and this may cause
                      regression in the whole analysis experience. This
                      may be the case especially when we get a
                      compile_commands.json from a project that is
                      compiled only with e.g. GCC.</div>
                    <div><br>
                    </div>
                    <div>Thanks,</div>
                    <div>Gabor</div>
                    <div><br>
                    </div>
                    <div> </div>
                  </div>
                  <br>
                  <fieldset></fieldset>
                  <pre>_______________________________________________
cfe-dev mailing list
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a>
</pre>
                </blockquote>
                <br>
              </blockquote>
              <br>
            </div>
          </blockquote>
        </div>
      </div>
    </blockquote>
    <br>
  </div>

_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
</blockquote></div>