0

For a project I am currently using the swift compiler front end to generate LLVM IR. I need to analyze the IR to find run time dependencies between variable read/writes with the end goal of finding parallelism.

For this it is important that I am able to generate LLVM IR that is unoptimized and all the load and store instructions are present. It works well with clang with the -O0 flag which prevents optimization.

However with swiftc I have the following issue on this simple example:

func returnInputSum(test: Int) -> Int {
    var a = 5
    var b = 10
    var c = a + b
    return c
}

with swiftc -Onone this becomes(removed debug etc.):


entry:
  %a = alloca i64, align 8
  %b = alloca i64, align 8
  %c = alloca i64, align 8
  store i64 5, i64* %a, align 8
  store i64 10, i64* %b align 8

  store i64 15, i64* %c, align 8
  

  ret i64 15

so instead of loading a and b, inserting an "add" instruction and storing the result in c, the compiler seems to evaluate 5 + 10 directory to store the 15 in c. Then the return does not even return c but an immediate value this is a problem for me because I want to see all load/store instructions.

when I use clang with c/c++ code it works just fine and I get what I expect there:

  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 5, i32* %a, align 
  store i32 10, i32* %b, align 4

  %0 = load i32, i32* %b, align 4
  %1 = load i32, i32* %a, align 4
  %add = add nsw i32 %0, %1
  store i32 %add, i32* %c, align 4

  
  %2 = load i32, i32* %c, align 4
  ret i32 %2



is there any way to actually make the compiler do no optimization at all on the LLVM IR code? or am I not understanding something important here? I know that before generating LLVM IR there is SIL pass with some optimization but I am under the assumption that with the -Onone flag this should also be turned "off"?

thank you!

Peter
  • 37
  • 3
  • The thing you are missing is that there is no general obligation to store variables in main memory. The compiler does not have to start with variables in ram that are then optimised into something more sensible. Rather, the compiler has to follow the language's rules. – arnt Jun 13 '22 at 20:46
  • Why do you want to defeat constant-propagation in the first place? Not doing work at all is even better than having the CPU do it in parallel every run. If you want interesting asm or LLVM-IR to look at, write functions that take args and return a value dependent on them, like `long foo(long a, long b){ return a+b; }` or the Swift equivalent. That will necessarily have a run-time add operation. [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116) has some examples – Peter Cordes Jun 13 '22 at 20:46
  • "For this it is important that I am able to generate LLVM IR that is unoptimized" Why? Are you trying to find parallelism opportunities in the source language? Or are you trying to find them as part of compiler optimisation to exploit them? – Nick Lewycky Jun 14 '22 at 04:38
  • @NickLewycky I am trying to find them in the source language, yes – Peter Jun 14 '22 at 06:37
  • @PeterCordes it is not the constant propagation is not wanted, just for the analysis it would be suitable to have an IR that is compatible with the unoptimized clang version of it as the tool I am working with was originally developed as a pass on unoptimized llvm ir generated by clang. no I have to carefully analyze whether content prop and other optimization that might take place may have an effect on the result – Peter Jun 14 '22 at 06:43
  • Ok, well good luck then; I don't know Swift or its front-end for LLVM. It doesn't seem useful to me to find parallelism in the source for things that won't even exist in the final asm, instead of just looking for parallelism in whatever LLVM-IR you run it on. – Peter Cordes Jun 14 '22 at 06:50
  • 1
    @PeterCordes thats what I was thinking now too. in the case of clang it would be odd to require no optimization on an instruction level just so you can have much more expensive thread level parallelism. so the end result after the optimization should be enough. of course some optimization like instruction reordering and scheduling or loop unrolling would make it really hard to make guarantees and defeat the purpose of parallelizing a loop with something like openmp but as far as I understand these are not happening at this stage of the compilation process and can be disabled – Peter Jun 14 '22 at 07:36
  • Yeah, I'd expect most real transformations are in the LLVM back-end, not per-language front-ends. And yeah, unrolling in the source can sometimes defeat back-end optimizations that do the same thing (like auto-vectorization), so yeah I could see that you'd want LLVM-IR that hasn't been over-complicated yet. – Peter Cordes Jun 14 '22 at 08:00
  • 1
    Something else to be aware of is that Swift isn’t directly compiled into IR. It first goes through SIL (Swift Intermediate Language) and as I recall there are required optimizations that are done regardless of the command line switch before lowering the SIL to IR. That may further complicate things. – Chip Jarred Jun 14 '22 at 08:18
  • I think there is a command line switch to dump the SIL. I don’t recall exactly what it is, so you might need to employ some google-fu to find it. – Chip Jarred Jun 14 '22 at 08:20
  • 1
    @ChipJarred yes, I emitted and dumped the SIL and the canonical SIL after the pass and I can see that the constant propagation is happening in this step. someone from the swift forum also confirmed this to me. – Peter Jun 14 '22 at 09:25
  • @Peter annoying isn’t it? My opinion is there should always be a way to say “when I say no optimizations I really mean NO optimizations,” for exactly the kind of thing you’re trying to do. – Chip Jarred Jun 14 '22 at 09:39
  • @ChipJarred I agree. someone on the swift forum has said that "The compiler does basic data-flow analysis on local variables at the SIL level. There is no way to disable this because some of the results of that analysis are required in order to make certain code patterns legal." but I do not understand how for example not having constant propagation does make the code illegal – Peter Jun 14 '22 at 09:57
  • The heart of LLVM is a gradient for program simplicity and algorithms for sliding down that slope while preserving equivalent program behaviour. If you don't want your program rewritten into a simpler equivalent program, you probably shouldn't use LLVM. LLVM's power in analyzing program semantics is based on allowing you to pattern match the simplest form you're interested in, and letting LLVM simplify your program into that if it's equivalent. In my opinion, if you want to analyze a property of the source code, then you need to analyze the source code, not the LLVM IR. – Nick Lewycky Jun 14 '22 at 18:29

0 Answers0