I am trying to implement an opt pass that will compress string constants in ROM and then, at the cost of CPU + RAM, re-materialize the values at runtime. Before implementing compression, I just want to place all strings in a table, and do a lookup.
Example:
printf("Hello");
Would become the equivalent of
char placeholder[6];
int strID = 0;
tableLookup(placeholder, 0 /*ID*/); // Fill array
printf(placeholder);
The LLVM IR I was able to generate looks like the following:
%fakeString = alloca [10 x i8], align 1
call void #llvm.dbg.declare(metadata [10 x i8]* %fakeString, metadata !60, metadata !25), !dbg !64
%arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %fakeString, i32 0, i32 0, !dbg !65
call void #tableLookup(i8* %arraydecay, i32 0) #2, !dbg !66
How would I be able to create this programatically? The two main pieces I am missing:
1. How to create the array reference (after creating the alloca instruction)
2. How to get result from tableLookup and replace the operand in the old printf()
Any help would be much appreciated!
Related
I am having quite some trouble programmatically accessing a function pointer in a global array programmatically. I have a global array of function pointers, my "lookup table" which I basically I am using for "overloads". Every time I try to GetElementPointer (GEP)/getelementptr an element in this array with the desired type, I get a runtime assertion:
warp_compiler: /root/.conan/data/llvm-core/13.0.0/_/_/package /6efbb14f313e71b5e1dbf77c1c011f47614b7c7c/include/llvm/IR/
Instructions.h:960: static llvm::GetElementPtrInst* llvm::GetElementPtrInst::Create(
llvm::Type*, llvm::Value*, llvm::ArrayRef<llvm::Value*>, const llvm::Twine&, llvm::Instruction*):
Assertion `cast<PointerType>(Ptr->getType()->getScalarType()) ->isOpaqueOrPointeeTypeMatches(PointeeType)'
failed.
Aborted (core dumped)
Now the type of the array when compiled is [3 x i32 (i32)*] by default it tries to do a a GEP on [3 x i32 (i32)*]* with element type [3 x i32 (i32)*] which does not work.
If I manaually edit the code to be:
%option_address = getelementptr i32 (i32)*, [3 x i32 (i32)*]* #my_function_1_table, i32 %7
Or too:
%option_address = getelementptr i32 (i32)*, [3 x i32 (i32)*] #my_function_1_table, i32 %7
it works just dandy, the ladder is really what I am looking to do. But I cant seem to do it probrammatically because of this exception.
I have tried casting the array to i32 (i32)* with:
auto first_element = context->builder.CreatePointerBitCastOrAddrSpaceCast(
(llvm::Value*) lookup_table_global,
(llvm::Type*) function->getType(),
"cast"
);
Then trying to access the elements with something like:
auto element = context->builder.CreateGEP(
(llvm::Type*) function->getType(),
first_element,
index_array,
"option_address"
);
But I get that exception again, and it does work if I type it manually into the IR
%option_address = getelementptr i32 (i32)*, i32 (i32)* #my_function_1_table, i32 %7
Seems like a pretty regular way to access an array, right?
But I cant seem to do it programmatically, because if the assertion, I even tried to make a work around by tryng to inherit from GetElementPtrInst directly and omitting the assertion, but couldn't (because its constructor is private).
Currently, my solution is to cast the array to a i32 (i32)* then to a [1 x i32 (i32)*] then do the GEP on a [1 x i32(i32)*]* with a [1 x i32(i32)]
%option_address = getelementptr [1 x i32 (i32)*], [1 x i32 (i32)*]* bitcast ([3 x i32 (i32)*]* #my_function_1_table to [1 x i32 (i32)*]*), i32 %7
This is horrible.
Does anyone know how I can simply access the function pointers I need from a global (constant) array so they can be called?
Also is my current solution portable?
Thank you!
Sorry you've run into this challenging aspect of LLVM. It definitely causes confusion.
There is an entire webpage dedicated to trying to help folks understand the counter-intuitive design of this instruction. While the design is well motivated from within LLVM, it causes lots of folks confusion and frustration when they first encounter it.
The challenge you're hitting is because a GEP instruction in LLVM always operates on a pointer, and with global variables, that pointer is to the variable. When the global variable is an array as in your case, this is extra confusing -- GEP has to go through an extra layer of pointer before it gets to the array you're trying to index with it.
The first section of the GEP site I mentioned above specifically explains how the first index to a GEP works -- it indexes the base pointer directly.
The second section then specifically clarifies why global variables end up surprising here. The global variable, #my_function_1_table in your case, is a pointer to itself. You'll have to index that with a simple i32 0 index first. Then you can add an additional index into the array that global variable points to.
So for a global variable with type [3 x i32 (i32)*], if you want to extract the second element of the array, you need:
%fptr = getelementptr [3 x i32 (i32)*], [3 x i32 (i32)*]* #my_function_1_table, i32 0, i32 2
The first i32 0 here indexes the global itself. The second index of i32 2 indexes into the array.
You can also use Clang to get example LLVM IR that can help explain how to do things. For example, here is some C++ that does something similar to what you're trying to do:
using FPtrT = int (*)(int);
extern FPtrT function_ptrs[3];
int test(int i) {
FPtrT fptr = function_ptrs[i];
return (*fptr)(42);
}
And this turns into the following LLVM IR after some basic optimizations (-O1):
#function_ptrs = external dso_local local_unnamed_addr global [3 x i32 (i32)*], align 16
define dso_local i32 #_Z4testi(i32 %0) local_unnamed_addr #0 {
%2 = sext i32 %0 to i64
%3 = getelementptr inbounds [3 x i32 (i32)*], [3 x i32 (i32)*]* #function_ptrs, i64 0, i64 %2
%4 = load i32 (i32)*, i32 (i32)** %3, align 8, !tbaa !4
%5 = call i32 %4(i32 42)
ret i32 %5
}
attributes #0 = { mustprogress uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
Here you can see %3 is doing a dynamic (and inbounds, but that's orthogonal) version of this indexing.
You can play with this kind of IR generation using Compiler Explorer: https://cpp.compiler-explorer.com/z/ETa8nvTvh
Once you're using the API to create this two index GEP it should start working for you.
Also, just so you (or others) reading this don't get confused: the LLVM IR syntax changed here recently, so the latest versions of LLVM don't look quite the same. You can switch from Clang v13 to a more recent one to see what it looks like, for example here: https://cpp.compiler-explorer.com/z/Kc4er413G
I am new to llvm programming, and I am trying to write cpp to generate llvm ir for a simple C code like this:
int a[10];
a[0] = 1;
I want to generate something like this to store 1 into a[0]
%3 = getelementptr inbounds [10 x i32], [10 x i32]* %2, i64 0, i64 0
store i32 1, i32* %3, align 16
And I tried CreateGEP: auto arrayPtr = builder.CreateInBoundsGEP(var, num); where var and
num are both of type llvm::Value*
but I only get
%1 = getelementptr inbounds [10 x i32], [10 x i32]* %0, i32 0
store i32 1, [10 x i32]* %1
I searched google for a long time and looked the llvm manual but still don't know what Cpp api to use and how to use it.
Really appreciate it if you can help!
Note that the 2nd argument to IRBuilder::CreateInBoundsGEP (1st overload) is actually ArrayRef<Value *>, which means it accepts an array of Value * values (including C-style array, std::vector<Value *> and std::array<Value *, LEN> and others).
To generate a GEP instruction with multiple (child) addresses, pass an array of Value * to the second argument:
Value *i32zero = ConstantInt::get(contexet, APInt(32, 0));
Value *indices[2] = {i32zero, i32zero};
builder.CreateInBoundsGEP(var, ArrayRef<Value *>(indices, 2));
Which will yield
%1 = getelementptr inbounds [10 x i32], [10 x i32]* %0, i32 0, i32 0
You can correctly identify that %1 is of type i32*, pointing to the first item in the array pointed to by %0.
LLVM documentation on GEP instruction: https://llvm.org/docs/GetElementPtr.html
I am trying to initialize and then cast a number of LLVM IR variables in the following way:
store i64 %content, i64* %5
%tt2 = load i64, i64* %5
%ttt2 = trunc i64 %tt2 to i32
While this seems trivial and works fine, I am trapped to do the same thing for a [20 * i8] typed variable. Something like:
store [20 x i8] %content, [20 x i8]* %5
%tt2 = load [20 x i8], [20 x i8]* %5
%ttt2 = trunc [20 x i8] %tt2 to i32
Currently I got the following error msg for the third line:
invalid cast opcode for cast from [20 x i8] to i32
Could anyone shed some lights on this issue? Thanks!
You can trunc from one int to another, but not from an array to an int. That's just how trunc is defined — if the input isn't an int, then trunc would need to do something markedly different from "drop the higher-order bits and preserve the lower-order bits".
I think the most common approach is to cast the pointer and then load/store from a pointer that already matches the type you want to load/store.
(Note that %ttt2 etc. aren't LLVM variables, they're LLVM values. They don't vary, ever.)
I want to implement a string type in LLVM-IR, and my plan is as follows:
When a string variable is declared, allocate memory for a i8*.
When the variable is initialized, store the string somewhere, store the pointer to the first element at the formerly allocated address, and save the length of the string in a member variable.
The problem is, that I can't get the pointer to the first element.
Using the IRBuilder (C++ API), I have yet created the following code:
%str2 = alloca i8*
%1 = alloca [4 x i8]
store [4 x i8] c"foo\00", [4 x i8]* %1
%2 = getelementptr [4 x i8], [4 x i8]* %1, i32 0
store [4 x i8]* %2, i8** %str2
But calling llc on this gives the following error:
error: stored value and pointer type do not match
store [4 x i8]* %2, i8** %str2
^
When using clang to emit llvm-ir on the same (char* instead of string) code, it emits the following:
%str2 = alloca i8*, align 8
store i8* %str, i8** %1, align 8
store i8* getelementptr inbounds ([4 x i8], [4 x i8]* #.str, i32 0, i32 0), i8** %str2, align 8
Which looks very similar imho, but is not the same.
Clang makes the string a global constant (which is hopefully not necessary), uses the offset parameter of getelementptr and gives the type i8* to the store instruction.
Unfortunately I wasn't able to find any API Methods to explicitly give a type to the store instruction, or use the offset parameter (which wouldn't even help, I guess).
So finally my question is: How can I properly get a pointer to the first array element and store it?
Thanks in advance
As in the link in the comment, the solution is to bitcast the [n x i8]* to an i8*
%str2 = alloca i8*
%1 = alloca [4 x i8]
store [4 x i8] c"foo\00", [4 x i8]* %1
%2 = bitcast [4 x i8]* %1 to i8*
store i8* %2, i8** %str2
I am new to LLVM, and I am learning how to use LLVM for profiling. I need to pass an array to an external method, and insert a call instruction to the method in the code. I am currently using the following code, which on execution gives a segmentation fault.
std::vector<Value*> Args(1);
//Vector with array values
SmallVector<Constant*, 2> counts;
counts.push_back(ConstantInt::get(Type::getInt32Ty(BB->getContext()),32, false));
counts.push_back(ConstantInt::get(Type::getInt32Ty(BB->getContext()),12, false));
//Array with 2 integers
Args[0]= ConstantArray::get(llvm::ArrayType::get(llvm::Type::getInt32Ty(BI->getContext()),2), counts);
Here, the external function 'hook' is defined as M.getOrInsertFunction("hook", Type::getVoidTy(M.getContext()),
llvm::ArrayType::get(llvm::Type::getInt32Ty(BI->getContext()),2)
(Type*)0);
After reading a few source files, I've tried using GetElementPtrInst to pass the array
std::vector<Value*> ids(1);
ids.push_back(ConstantInt::get(Type::getInt32Ty(BB->getContext()),0));
Constant* array = ConstantArray::get(llvm::ArrayType::get(llvm::Type::getInt32Ty(BI->getContext()),2), counts);
Args[0] = ConstantExpr::getGetElementPtr(&(*array), ids, false);
but it fails with
7 opt 0x00000000006c59f5 bool llvm::isa<llvm::Constant, llvm::Value*>(llvm::Value* const&) + 24
8 opt 0x00000000006c5a0f llvm::cast_retty<llvm::Constant, llvm::Value*>::ret_type llvm::cast<llvm::Constant, llvm::Value*>(llvm::Value* const&) + 24
9 opt 0x0000000000b2b22f
10 opt 0x0000000000b2a4fe llvm::ConstantFoldGetElementPtr(llvm::Constant*, bool, llvm::ArrayRef<llvm::Value*>) + 55
11 opt 0x0000000000b33df2 llvm::ConstantExpr::getGetElementPtr(llvm::Constant*, llvm::ArrayRef<llvm::Value*>, bool) + 82
Also, in this case, 'hook' is defined as M.getOrInsertFunction("hook", Type::getVoidTy(M.getContext()),
PointerType::get(Type::getInt32PtrTy(M.getContext()),0), //when using GEP
(Type*)0);
Could someone kindly keep me a few pointers on passing arrays to an external function (say with the signature void hook(int abc[]) ). I am probably wrong all the way through, and would really appreciate some help.
A good place to start with "how do I do this c-like thing in LLVM IR" questions is to first write what you want to do in C, then compile it to LLVM IR via Clang and take a look at the result.
In your particular instance, the file:
void f(int a[2]);
void g() {
int x[2];
x[0] = 1;
x[1] = 3;
f(x);
}
Will compile to:
define void #g() nounwind {
%x = alloca [2 x i32], align 4
%1 = getelementptr inbounds [2 x i32]* %x, i32 0, i32 0
store i32 1, i32* %1, align 4
%2 = getelementptr inbounds [2 x i32]* %x, i32 0, i32 1
store i32 3, i32* %2, align 4
%3 = getelementptr inbounds [2 x i32]* %x, i32 0, i32 0
call void #f(i32* %3)
ret void
}
declare void #f(i32*)
So we can see the clang compiled g to receive i32*, not an array. That means you need a way to get an address to the first element of the array from the array itself, and a getelementptr instruction is a straightforward way of doing that.
Notice, however, that you want to generate a GEP (getelementptr instruction), for example via GetElementPtrInst::create. A gep constant expression, which is what you're trying to generate here, is something else, and will only work on compile-time constants.
You should use Clang to compile it. Then, check the boundaries of the array and if all the elements are defined.