How to define a global variable?

Hi,

I'm trying to define a mutable variable, outside functions. The code
below is trying to evaluate an expression much like "x = 1" at the
module level in Python. It appears that when it tries to JIT the
function there is an error because there is no storage allocated for
'x'. How do I do that?

thanks,
Rob

----- dumped IR -----
; ModuleID = 'repl-module'

%0 = type opaque

@x = external global %0*

define %0* @0() {
entry:
  store %0* inttoptr (i64 4316154480 to %0*), %0** @x
  ret %0* inttoptr (i64 4316154480 to %0*)
}
LLVM ERROR: Could not resolve external global address: x

----- C++ code -----
GlobalVariable *gvar = new GlobalVariable(*module, id_ty, false,
GlobalVariable::ExternalLinkage, 0, str.str());
Value *valv = gen_expr(val);
builder.CreateStore(valv, gvar, false);
...
engine->getPointerToFunction(thunk);

Hi Rob,

Try removing the 'extern', as it implies the variable storage is
elsewhere (ie. another object file).

cheers,
--renato

I have to pass something from the LinkageTypes enum to the
constructor. I tried others, like GlobalVariable::InternalLinkage,
which dumps as "internal global" but the error was the same.

Rob

To be honest, your IR is a bit odd. I'm not a JIT expert, but here are
a few things that will help you find your way through LLVM...

Is this the result of the compilation of a source file (by any
front-end), or is this code generated dynamically via the API?

Opaque types are not valid, you need to resolve it to a real (LLVM)
type before running/compiling. The inttoptr will not resolve it to a
pointer, so that IR is probably invalid anyway.

The internal global probably works in your case and unless you have
another extern variable, I don't know how you can get the "exact" same
error message with an internal global. (Again, I'm not a JIT expert,
that could happen somehow).

This could be perfectly legal in your case, but if I got it right,
you're setting a static address to a supposed pointer (i64
4316154480). That's generally wrong in all but the most simple cases
(deeply embedded systems with no memory management).

I don't know about the Python integration, but if your @x variable is
a Python variable, then extern global is probably what you're looking
for. However, due to the (possible) difference in memory layouts, I
don't think that's the best way to pass information up to the Python
layer. At least when using JNI to interface Java with C, that was a
clear dead end.

Maybe if you tell us a bit more about your project, expectations and
steps, we might be able to help you more than just guessing... :wink:

cheers,
--renato

I have to pass something from the LinkageTypes enum to the
constructor. I tried others, like GlobalVariable::InternalLinkage,
which dumps as "internal global" but the error was the same.

To be honest, your IR is a bit odd. I'm not a JIT expert, but here are
a few things that will help you find your way through LLVM...

Is this the result of the compilation of a source file (by any
front-end), or is this code generated dynamically via the API?

Via the API. More below...

This could be perfectly legal in your case, but if I got it right,
you're setting a static address to a supposed pointer (i64
4316154480). That's generally wrong in all but the most simple cases
(deeply embedded systems with no memory management).
....
I don't know about the Python integration, but if your @x variable is ...

I'm not doing anything with Python, but I mentioned it to illustrate
what kind of expression I was trying to compile. I'm trying to create
a Lisp-like language. I was following parts of the Kaleidoscope
language tutorial in the LLVM docs. The expression for the program
above is actually (def x 1) in this language. At the module level
(ie, not inside a function) this should create a module level "global"
variable called x and set it to 1. These weird pointer casts are the
first, simplest expressions getting compiled. Let's say the reader
(parser) sees "abc" and returns that immutable string object, which is
an expression. It is a self-evaluating expression, so to JIT compile
it, I figured I'd just put it's address into the compiled code, as a
Constant. (The object already exists in memory, because it was read.)
  This has been working okay; it JIT compiles and evaluates simple
literal expressions, like numbers, strings, quoted lists.

Right now, everything is an object, even simple things like an
integer. This is for easy development in the beginning. I'll use
types and/or immediate ints, etc, later. So, for (def x 1) there is a
heap-allocated integer (actually NSNumber) and that's the pointer in
my IR shown before. I want to set 'x' to that object. The type of x
in Objective-C/C++ world is NSObject* or id. I just tried i8* instead
of opaque*, so now it looks like...

(def x 1)

; ModuleID = 'repl-module'

@x = common global i8*

define i8* @0() {
entry:
  store i8* inttoptr (i64 4316154320 to i8*), i8** @x
  ret i8* inttoptr (i64 4316154320 to i8*)
}

LLVM ERROR: Could not resolve external global address: x

That last line is printed when I try to get the JIT'd function with:

engine->getPointerToFunction(thunk);

thanks for the help,
Rob

First, replace %0* with a concrete type (like the i8* in your later post).
Then give @x an initializer. 'undef' is good enough if you don't want
to assign an actual value yet. This should turn it into a definition
instead of a declaration.

Thanks, the initializer did it. Using opaque* works, at least in this
case; but I've replaced it with i8*.

Rob