I'm experimenting with LLVM IR as an alternative to assembly for programming AVR chips, but I have encountered a stumbling block.
I have the following working code:
target triple = "avr-atmel-none"
define void #main() {
%1 = load i8, i8* inttoptr (i8 34 to i8*)
%or = or i8 %1, 1
store i8 %or, i8* inttoptr (i8 34 to i8*)
ret void
}
Notice the inttoptr (i8 34 to i8*) - that's a memory-mapped IO location on my chip, which I will interact with a lot, so I'd like to give it a name like #PORTA. However, I can't find a way to initialise a global variable as pointing to a specific memory address. This doesn't work:
#PORTA = constant i8* inttoptr (i8 34 to i8*)
as it initialises the contents of a pointer variable #PORTA, rather than creating it pointing to that address.
Is it possible to make a global alias for a certain memory address in LLVM IR? If not, is there some other shortcut that would allow me to alias these names?
Do you really need to create such alias on IR level? LLVM IR isn't supposed to be comfortable to write manually.
If you are generating code from C++ API then just make that inttoptr constant expression global and use it wherever you like:
ConstantExpr* porta = ...
void foo()
{
new LoadInst(..., porta);
...
new StoreInst(..., porta);
}
Related
I am writing an LLVM pass where I want to print out the values of function arguments. I am only focusing on integers and pointers to integers (which will also involve char, I guess but that is not a problem for my purposes). If the argument is a pointer, I want to dereference it and print the value that is pointed to by the pointer. To guard against null pointers, in normal C code I can do:
function foo(int* bar, int** baz) {
if (bar) {
printf("bar: %d\n", *bar);
}
if (baz) {
printf("baz: %d\n", **baz);
}
}
Is there a way to do something similar in LLVM? Currently I am doing the following to actually load the value by dereferencing the pointer. I am working off a StoreInst that LLVM generates to set up the values of function parameters. For example, for the function above, there would be something like:
%bar.addr = alloca i32*, align 8
%baz.addr = alloca i32**, align 8
store i32* %bar, i32** %bar.addr, align 8
store i32** %baz, i32*** %baz.addr, align 8
So using that StoreInst, I am doing something like this:
auto *value = store->getValueOperand();
auto *type = value->getType();
int indirection = 0;
while (type->isPointerTy()) {
indirection++;
type = type->getPointerElementType();
}
Value* load = value;
unsigned int bitWidth = type->getIntegerBitWidth(); // I have already verified earlier on that
// this eventually resolves to an IntegerType
while (indirection > 0) {
load = (indirection == 1) ? irb.CreateLoad(getIntegerType(bitWidth), load)
: irb.CreateLoad(getPointerToIntegerType(indirection - 1, bitWidth), load);
--indirection;
}
value = load;
The getIntegerType is just a convenience function that returns an IntegerType with the provided bit-width and using the current LLVM context. The getPointerToIntegerType function is as follows:
Type* getPointerToIntegerType(int indirection, unsigned int bitWidth) {
Type* type = getIntegerType(bitWidth);
while (indirection > 0) {
type = PointerType::get(type, 0);
--indirection;
}
return type;
}
Using this I get the following load instructions after the store instructions (I've omitted some stuff from the call instructions for brevity):
store i32* %bar, i32** %bar.addr, align 8
%1 = load i32, i32* %bar
call void (i8, ...) #__print_argument_value(...)
store i32** %baz, i32*** %baz.addr, align 8
%2 = load i32*, i32** %baz
%3 = load i32, i32* %2
call void (i8, ...) #__print_argument_value(...)
This works perfectly as long as the pointers are not null. Is there an easy way I can generate IR to guard the call to __print_argument_value? I did write out an explicit if (bar) { ... } and a if (baz) { ... } and then looked at the generated IR to see how LLVM generates it. I saw that it performs an icmp ne of the pointer (the .addr variable) against null. Then if the result is true, it breaks to a label if.then where it calls the function, or else to the label if.end which skips over it.
The problem is that I'm having a hard time trying to figure out how I can generate IR like that from my LLVM pass. Are there any examples I can look at? I did look up the documentation but I still can't figure out how to put the pieces together using the LLVM API even though I know what the IR should look like. I saw some documentation about to PHI nodes which I don't see in my IR from the explicit null check, but I am not entirely clear on what they are and how they would help me.
PS: Please excuse any weirdness in the C/C++ code; I usually program in Java.
I don't understand why #a is type of i32*. Can someone explain it me, please?
#a = internal global i32 0
define i32 #main() {
store i32 42, i32* #a
%1 = load i32* #a
ret i32 %1
}
From the language reference (emphasis mine):
Global variables define regions of memory allocated at compilation time instead of run-time.
[...]
As SSA values, global variables define pointer values that are in scope (i.e. they dominate) all basic blocks in the program. Global variables always define a pointer to their “content” type because they describe a region of memory, and all memory objects in LLVM are accessed through pointers.
I'm generating LLVM IR for JIT purposes, and I notice that LLVM's calling conventions don't seem to match the C calling conventions when aggregate values are involved. For instance, when I declare a function as taking a {i32, i32} (that is, a struct {int a, b;} in C terms) parameter, it appears to pass each of the struct elements in its own x86-64 GPR to the function, even though the x86-64 ABI specifies (sec. 3.2.3) that such a struct should be packed in a single 64-bit GPR.
This is in spite of LLVM's documentation claiming to match the C calling convention by default:
“ccc” - The C calling convention
This calling convention (the default if no other calling convention is specified) matches the target C calling conventions. This calling convention supports varargs function calls and tolerates some mismatch in the declared prototype and implemented declaration of the function (as does normal C).
My question, then, is: Am I doing something wrong to cause LLVM to not match the C calling convention, or is this known behavior? (At the very least, the documentation seems to be wrong, no?)
I can find only very few references to the issue at all on the web, such as this bug report from 2007, which claims to be fixed. It also claims that "First, LLVM has no way to deal with aggregates as singular Value*'s", which I don't know if it was true in 2007, but it doesn't seem to be true now, given the extractvalue/insertvalue instructions. I also found this SO question whose second (non-accepted) answer simply seems to accept implicitly that argument coercion has to be done manually.
I'm currently building code for doing argument coercion in my IR generator, but it is complicating my design considerably (not to mention making it architecture-specific), so if I'm simply doing something wrong, I'd rather know about that. :)
LLVM's support for C-language compatible calling convention is extremely limited I'm afraid. Several folks have wished for more direct calling convention support in LLVM (or a related library), but so far this has not emerged. That logic is currently encoded in the C-language frontend (Clang for example).
What LLVM provides is a mapping from specific LLVM IR types to specific C ABI lowerings for a specific CPU backend. You can see which IR types to use for a given C function by using Clang to emit LLVM IR, much as the comment above suggests:
https://c.compiler-explorer.com/z/8jWExWPYq
struct S { int x, y; };
void f(struct S s);
void test(int x, int y) {
struct S s = {x, y};
f(s);
}
Turns into:
define dso_local void #test(i32 noundef %0, i32 noundef %1) #0 {
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca %struct.S, align 4
store i32 %0, ptr %3, align 4
store i32 %1, ptr %4, align 4
%6 = getelementptr inbounds %struct.S, ptr %5, i32 0, i32 0
%7 = load i32, ptr %3, align 4
store i32 %7, ptr %6, align 4
%8 = getelementptr inbounds %struct.S, ptr %5, i32 0, i32 1
%9 = load i32, ptr %4, align 4
store i32 %9, ptr %8, align 4
%10 = load i64, ptr %5, align 4
call void #f(i64 %10)
ret void
}
declare void #f(i64) #1
There is sadly some non-trivial logic to map specific C types into the LLVM IR that will match the ABI when lowered for a platform. Outside of extremely simple types (basic C integer types, pointers, float, double, maybe a few others), these aren't even portable between the different architecture ABIs/calling-conventions.
FWIW, the situation is even worse for C++ which has much more complexity here I'm afraid.
So your choices are to:
Use a very small set of types in a limited range of signatures that you build custom logic to lower correctly into LLVM IR, checking that it matches what Clang (or another C frontend) produces in every case.
Directly use Clang or another C frontend to emit the LLVM IR.
Take on the major project of extracting this ABI/calling-convention logic from Clang into a re-usable library. There has in the past been appetite for this in the LLVM/Clang communities, but it is a very large and complex undertaking from my understanding. There are some partial efforts (specifically for C and JITs) that you may be able to find and re-use, but I don't have a good memory of where all those are.
I'm new to llvm and I'm writing a small llvm IR Builder.
I use the IRBuilder and all these Create* functions to generate my IR.
What I'm trying to do is to create a load instruction which create a new SSA local variable with value of a previously allocated llvm::Value.
What I expected to have :
%2 = load i32* %1
With %2 results of load instruction and %1 my previously allocated Value (CreateAlloca)
Here is what I tried :
// Get Ptr from Val
Value* ptr = ConstantExpr::getIntToPtr((Constant*)loc[n],PointerType::getUnqual(builder->getInt32Ty()));
// Générate load instruction with the new Ptr
builder->CreateLoad(ptr);
And here is what I have :
%2 = load i32* null
loc is an array which contains all my llvm::Value*
Can you please tell me what I'm doing wrong ? Or maybe if I'm on a bad way ?
Thanks.
ConstantExpr::getIntToPtr() creates a constant expression. So in effect, what you're trying to generate is equivalent to this IR:
%2 = load i32* inttoptr (i32 %1 to i32*)
But this is illegal since a constant expression, as hinted by its name, only supports constants, and %1 isn't a constant. ConstantExpr::getIntToPtr() requires a Constant as a first argument to verify it, but you passed it a non-constant value which was forcefully cast to a constant.
The correct way to convert a non-constant integer to a pointer is with IRBuilder::createIntToPtr. However, since you say the previous value (loc[n]) was created via an alloca then it's already a pointer, and you don't need to perform any conversion: just do builder->CreateLoad(loc[n]).
By the way, the proper way to cast a Value to a Constant in LLVM is not via a c-style cast but via cast<>, like so: cast<Constant>(loc[n]).
I have a source C++ code which I parse using clang, producing llvm bytecode. From this point I want to process the file myself...
However I encoudered a problem. Consider the following scenario:
- I create a class with a nontrivial destructor or copy constructor.
- I define a function, where an object of this class is passed as a parameter, by value (no reference or pointer).
In the produced bytecode, I get a pointer instead. For classes without the destructor, the parameter is annotated as 'byval', but it is not so in this case.
As a result, I cannot distinguish if the parameter is passed by value, or really by a pointer.
Consider the following example:
Input file - cpass.cpp:
class C {
public:
int x;
~C() {}
};
void set(C val, int x) {val.x=x;};
void set(C *ptr, int x) {ptr->x=x;}
Compilation command line:
clang++ -c cpass.cpp -emit-llvm -o cpass.bc; llvm-dis cpass.bc
Produced output file (cpass.ll):
; ModuleID = 'cpass.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"
%class.C = type { i32 }
define void #_Z3set1Ci(%class.C* %val, i32 %x) nounwind {
%1 = alloca i32, align 4
store i32 %x, i32* %1, align 4
%2 = load i32* %1, align 4
%3 = getelementptr inbounds %class.C* %val, i32 0, i32 0
store i32 %2, i32* %3, align 4
ret void
}
define void #_Z3setP1Ci(%class.C* %ptr, i32 %x) nounwind {
%1 = alloca %class.C*, align 8
%2 = alloca i32, align 4
store %class.C* %ptr, %class.C** %1, align 8
store i32 %x, i32* %2, align 4
%3 = load i32* %2, align 4
%4 = load %class.C** %1, align 8
%5 = getelementptr inbounds %class.C* %4, i32 0, i32 0
store i32 %3, i32* %5, align 4
ret void
}
As you can see, the parameters of both set functions look exactly the same. So how can I tell that the first function was meant to take the parameter by value, instead of a pointer?
One solution could be to somehow parse the mangled function name, but it may not be always viable. What if somebody puts extern "C" before the function?
Is there a way to tell clang to keep the byval annotation, or to produce an extra annotation for each function parameter passed by a value?
Anton Korobeynikov suggests that I should dig into clang's LLVM IR emission. Unfortunately I know almost nothing about clang internals, the documentation is rather sparse. The Internals Manual of clang does not talk about IR emission. So I don't really know how to start, where to go to get the problem solved, hopefully without actually going through all of clang source code. Any pointers? Hints? Further reading?
In response to Anton Korobeynikov:
I know more-or-less how C++ ABI looks like with respect of parameter passing. Found some good reading here: http://agner.org./optimize/calling_conventions.pdf. But this is very platform dependent! This approach might not be feasable on different architectures or in some special circumstances.
In my case, for example, the function is going to be run on a different device than where it is being called from. The two devices don't share memory, so they don't even share the stack. Unless the user is passing a pointer (in which case we assume he knows what he is doing), an object should always be passed within the function-parameters message. If it has a nontrivial copy constructor, it should be executed by the caller, but the object should be created in the parameter area as well.
So, what I would like to do is to somehow override the ABI in clang, without too much intrusion into their source code. Or maybe add some additional annotation, which would be ignored in a normal compilation pipeline, but I could detect when parsing the .bc/.ll file. Or somehow differently reconstruct the function signature.
Unfortunately, "byval" is not just "annotation", it's parameter attribute which means a alot for optimizers and backends. Basically, the rules how to pass small structs / classes with and without non-trivial functions are government by platform C++ ABI, so you cannot just always use byval here.
In fact, byval here is just a result of minor optimization at frontend level. When you're passing stuff by value, then temporary object should be constructed on stack (via the default copy ctor). When you have a class which is something POD-like, then clang can deduce that copy ctor will be trivial and will optimize the pair of ctor / dtor out, passing just the "contents".
For non-trivial classes (like in your case) clang cannot perform such optimization and have to call both ctor and dtor. Thus you're seeing the pointer to temporary object is created.
Try to call your set() functions and you'll see what's going there.