When I use the command clang -emit-llvm -S test.c -o test.ll, there is no any "phi" instruction in the IR file. How can I get it?
I know that I can use the pass "-mem2reg" or "-gvn" to get "phi" instruction. But they would do some optimization. I just want to get "phi" without any optimization.
I'm not sure what you mean by "do some optimization" but it seems to me that mem2reg is exactly what you need. Here is how it's described in the documentation:
This file promotes memory references to be register references. It
promotes alloca instructions which only have loads and stores as uses.
An alloca is transformed by using dominator frontiers to place phi
nodes, then traversing the function in depth-first order to rewrite
loads and stores as appropriate. This is just the standard SSA
construction algorithm to construct “pruned” SSA form.
Clang itself does not produce optimized LLVM IR. It produces fairly straightforward IR wherein locals are kept in memory (using allocas). The optimizations are done by opt on LLVM IR level, and one of the most important optimizations is indeed mem2reg which makes sure that locals are represented in LLVM's SSA values instead of memory.
Related
I've got some code that employs __sync_val_compare_and_swap with my cross-platform shared_mutex-implementation. The Windows-version (#ifdef'd) uses the _InterlockedCompareExchange-intrinsic which has full physical (to the ordering of loads and stores by the cpu) and logical (to the compiler) acquire- and release-behaviour. I don' find any documentation that the __sync_val_compare_and_swap-intrinsic also has some logical effects on the ordering of loads and stores to the compiler. So is there any "intrinsic" that forces the compiler to have logical a acquire- or release barrier? I know there's asm volatile("" ::: "memory"); with gcc, but this has acquire- and release-behaviour as well.
I am inserting some instructions into llvm IR to do some Integer Overflow(IO) checking. However, I am annoyed to find some of my instructions inserted get optimized by the optimizer.
For example, when there is
int result = data + 1;
My pass would see this operation as a potential overflow site and add(IR of course, I wrote C here to make my life easier):
int64_t result_64bit = (int64_t)data + 1
if (result_64bit > 2147483647) { report(); }
However, this instruction gets optimized out.
Here's what I tried:
add -O0 flag. It won't work. I have dumped IR after every pass and that happened on pass Remove redundant operation. (Not Redundant from my perspective...)
Move the pass to the end of optimization by setting EP_OptimizerLast flag.
Well, this is not optimal as some information gets lost. For example, I heavily rely on nsw/nuw flag to decide signs, some of these flags gets removed after optimizations.
So what I am asking is if there is some kind of instruction guard in LLVM that guards an instruction against been optimized or removed?
In LLVM is it necessary that if we insert some instruction in LLVM IR through LLVM Pass ,than also we have to insert an instruction which will use the result of our previous inserted instruction or we have to store result of our inserted instruction into some variable already present in LLVM IR that is not useless.
for example cant i insert instruction
%result = add i32 4 3
and %result is not used in subsequent instructions.
You should be able to insert it but if an optimization pass runs after your pass it might be eliminated because it's unused and doesn't have side effects.
No, it's absolutely not necessary. If you insert the instruction properly (i.e. use the API correctly), it can be left unused.
As a matter of fact, unused values can be left around by various optimization passes as well. LLVM has other passes like DCE (dead code elimination) that will remove unused instructions.
I have tried the LLVM demo from Try out LLVM and Clang in your browser!.
What kind of IR is this? HIR, MIR, or LIR? The SSA representation is usually used in MIR, I think. So, is it an MIR? But it can store the information for dependence analysis. Hence can it be an HIR?
What filename extension actually represents the LLVM IR, .ll or .bc?
How can I get the symbol table used in LLVM?
I'm not familiar with a single, strict definition of what differentiates one level of IR from another, but from what I know it would fall under the MIR category.
It has SSA form and doesn't have explicit registers, so I would definitely not categorize it as low-level.
It doesn't have named subelement reference or advanced flow-control constructs, so it wouldn't really fit into HIR, either.
In any case, LLVM IR is typically stored on disk in either text files with .ll extension or in binary files with .bc extension. Conversion between the two is trivial, and you can just use llvm-dis for bc -> ll and llvm-as for ll -> bc. The binary format is more memory-efficient, while the textual format is human-readable.
I've been looking into IR code which is specified using SSA- especially, generating LLVM IR in this form. However, I'm confused about whether or not this can be effective when presented with a type which has non-trivial copy semantics. For example,
void f() {
std::string s = "Too long for you, short string optimization!";
std::string s1 = s + " Also, goodbye SSA.";
some_other_function(s1);
}
In this SSA form, at least at the most obvious level, this results in a nasty mess of copies (even for C++). Can optimizers such as LLVM's actually optimize this case accurately? Is SSA viable for use even for types with non-trivial copy/assignment/etc semantics?
Edit: The question is that if I use an LLVM SSA register to represent a complex type (in this case, std:string), here represented by manually making it SSA, can LLVM automatically translate this into a mutating += call in the underlying assembly in the general case and avoid a nasty copy?
SSA means single static assignment. It's a way of dealing with value semantics as applied to registers. Each object is the result of exactly one machine instruction.
LLVM provides a generic "move" instruction, which is useful because there are many instructions across the spectrum of architectures that move 8, 32, N bytes. It also provides structured datatypes and arrays, because it is useful to hoist such things to registers, and they can be used to represent wacky high-level machine constructs. The intent is not to model OOP.