Nikodemus Siivola via llvm-dev
2017-Jun-04 20:39 UTC
[llvm-dev] [newbie] trouble with global variables and CreateLoad/Store in JIT
Emitting calls to these functions (written in an .ll file linked in) works
fine, and does the right thing.
%Any = type { i8*, i32 }
define dllexport void @setGlobal(%Any* %ptr, %Any %value) {
store %Any %value, %Any* %ptr
ret void
}
define dllexport %Any @getGlobal(%Any* %ptr) {
%val = load %Any, %Any* %ptr
ret %Any %val
}
Trying to replace the setGlobal call with what should be equivalent
builder.CreateStore(value, ptr)
results in what should end up in the second (i32) slot being stored in the
first (i8*).
I've added ::dump() calls where the CreateStore is, and this is what I get:
{ i8*, i32 } { i8* @FixnumClass, i32 32 } ; for value
@foo = external global { i8*, i32 } ; for ptr
Even more bizarrely trying to replace the getGlobal call with
builder.CreateLoad(val)
results in what has been stored in the first (i8*) slot being loaded
correctly, but the second (i32) getting garbage out despite the correct
value being stored in memory. Dump call there reports the @foo pointer
identically.
This is using LLVM 4.0.0
Just so I'm not leaving anything out, what follows are IR dumps of the
sample functions using either the direct store / load, or the setGlobal
getGlobal
functions. As far as I can tell they should do exactly the same thing...
; Does NOT do the right thing
define { i8*, i32 } @"__anonToplevel/2"() {
entry:
%.unpack = load i8*, i8** getelementptr inbounds ({ i8*, i32 }, { i8*,
i32 }* @foo, i32 0, i32 0), align 4
%0 = insertvalue { i8*, i32 } undef, i8* %.unpack, 0
%.unpack1 = load i32, i32* getelementptr inbounds ({ i8*, i32 }, { i8*,
i32 }* @foo, i32 0, i32 1), align 4
%1 = insertvalue { i8*, i32 } %0, i32 %.unpack1, 1
ret { i8*, i32 } %1
}
; Does NOT do the right thing
define { i8*, i32 } @"__anonToplevel/0"() {
entry:
store i8* @FixnumClass, i8** getelementptr inbounds ({ i8*, i32 }, { i8*,
i32 }* @foo, i32 0, i32 0), align 4
store i32 123, i32* getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }*
@foo, i32 0, i32 1), align 4
ret { i8*, i32 } { i8* @FixnumClass, i32 123 }
}
; DOES the right thing
define { i8*, i32 } @"__anonToplevel/0"() {
entry:
call void @setGlobal({ i8*, i32 }* nonnull @foo, { i8*, i32 } { i8*
@FixnumClass, i32 123 })
ret { i8*, i32 } { i8* @FixnumClass, i32 123 }
}
; DOES the right thing
define { i8*, i32 } @"__anonToplevel/1"() {
entry:
%0 = call { i8*, i32 } @getGlobal({ i8*, i32 }* nonnull @foo)
ret { i8*, i32 } %0
}
I'm at my wit's end. Any hints as to what I might be messing up would be
much appreciated. I expect it is something ridiculously obvious...
Cheers,
-- nikodemus
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20170604/0f211052/attachment.html>
Sean Silva via llvm-dev
2017-Jun-05 02:02 UTC
[llvm-dev] [newbie] trouble with global variables and CreateLoad/Store in JIT
This is a bit mystifying. Can you also show the assembly? What offsets are actually used for the stores in the "bad" versions? In other words, try verifying that the offsets that the getelementptr's should generate match your expectations (and if they deviate, in what ways they deviate). -- Sean Silva On Sun, Jun 4, 2017 at 1:39 PM, Nikodemus Siivola via llvm-dev < llvm-dev at lists.llvm.org> wrote:> Emitting calls to these functions (written in an .ll file linked in) works > fine, and does the right thing. > > %Any = type { i8*, i32 } > > define dllexport void @setGlobal(%Any* %ptr, %Any %value) { > store %Any %value, %Any* %ptr > ret void > } > > define dllexport %Any @getGlobal(%Any* %ptr) { > %val = load %Any, %Any* %ptr > ret %Any %val > } > > Trying to replace the setGlobal call with what should be equivalent > > builder.CreateStore(value, ptr) > > results in what should end up in the second (i32) slot being stored in the > first (i8*). > > I've added ::dump() calls where the CreateStore is, and this is what I get: > > { i8*, i32 } { i8* @FixnumClass, i32 32 } ; for value > @foo = external global { i8*, i32 } ; for ptr > > Even more bizarrely trying to replace the getGlobal call with > > builder.CreateLoad(val) > > results in what has been stored in the first (i8*) slot being loaded > correctly, but the second (i32) getting garbage out despite the correct > value being stored in memory. Dump call there reports the @foo pointer > identically. > > This is using LLVM 4.0.0 > > Just so I'm not leaving anything out, what follows are IR dumps of the > sample functions using either the direct store / load, or the setGlobal > getGlobal > functions. As far as I can tell they should do exactly the same thing... > > ; Does NOT do the right thing > define { i8*, i32 } @"__anonToplevel/2"() { > entry: > %.unpack = load i8*, i8** getelementptr inbounds ({ i8*, i32 }, { i8*, > i32 }* @foo, i32 0, i32 0), align 4 > %0 = insertvalue { i8*, i32 } undef, i8* %.unpack, 0 > %.unpack1 = load i32, i32* getelementptr inbounds ({ i8*, i32 }, { i8*, > i32 }* @foo, i32 0, i32 1), align 4 > %1 = insertvalue { i8*, i32 } %0, i32 %.unpack1, 1 > ret { i8*, i32 } %1 > } > > ; Does NOT do the right thing > define { i8*, i32 } @"__anonToplevel/0"() { > entry: > store i8* @FixnumClass, i8** getelementptr inbounds ({ i8*, i32 }, { > i8*, i32 }* @foo, i32 0, i32 0), align 4 > store i32 123, i32* getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* > @foo, i32 0, i32 1), align 4 > ret { i8*, i32 } { i8* @FixnumClass, i32 123 } > } > > ; DOES the right thing > define { i8*, i32 } @"__anonToplevel/0"() { > entry: > call void @setGlobal({ i8*, i32 }* nonnull @foo, { i8*, i32 } { i8* > @FixnumClass, i32 123 }) > ret { i8*, i32 } { i8* @FixnumClass, i32 123 } > } > > ; DOES the right thing > define { i8*, i32 } @"__anonToplevel/1"() { > entry: > %0 = call { i8*, i32 } @getGlobal({ i8*, i32 }* nonnull @foo) > ret { i8*, i32 } %0 > } > > I'm at my wit's end. Any hints as to what I might be messing up would be > much appreciated. I expect it is something ridiculously obvious... > > Cheers, > > -- nikodemus > > > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170604/7338c6a3/attachment.html>
Nikodemus Siivola via llvm-dev
2017-Jun-05 19:57 UTC
[llvm-dev] [newbie] trouble with global variables and CreateLoad/Store in JIT
Since the getelementptrs were implicitly generated by the CreateStore/Load
I'm not sure how to get access to them.
So I hacked the assignment to be done thrice: once using a manual
decomposition into two GEPs and stores, once using the "big"
CreateStore,
once via the setGlobal function, printing addresses and memory contents at
each point to the degree that I have access to them.
It seems the following GEPs compute the same address?! I can buy myself not
understanding how GEP works and doing it wrong, but builder.CreateStore()
creates what look like identical GEPs implicitly...
i8** getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* @foo, i32 0, i32
0), align 4
i32* getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* @foo, i32 0, i32
1), align 4
The details.
This is the relevant part from my codegen:
auto ty = val->getType();
cout << "val type:" << endl;
ty->dump();
cout << "ptr type:" << endl;
ptr->getType()->dump();
// Print memory
ctx.EmitCall1("debugPointer", ptr);
// Set class pointer
auto c = ctx.bld.CreateExtractValue(val, 0, "class");
auto cp = ctx.bld.CreateConstGEP2_32(ty, ptr, 0, 0);
auto cx = ctx.bld.CreatePtrToInt(cp, ctx.Int32Type());
ctx.EmitCall1("debugInt", cx);
ctx.bld.CreateStore(c, cp);
// Set datum
auto d = ctx.bld.CreateExtractValue(val, 1, "datum");
auto dp = ctx.bld.CreateConstGEP2_32(ty, ptr, 0, 1);
auto dx = ctx.bld.CreatePtrToInt(dp, ctx.Int32Type());
ctx.EmitCall1("debugInt", dx);
ctx.bld.CreateStore(d, dp);
// Print memory
ctx.EmitCall1("debugPointer", ptr);
// Do the same with a single store
ctx.bld.CreateStore(val, ptr);
// Print memory
ctx.EmitCall1("debugPointer", ptr);
// Call out
ctx.EmitCall2("setGlobal", ptr, val);
// Print memory
ctx.EmitCall1("debugPointer", ptr);
Here is the compile-time output showing types of the value and the pointer:
val type:
{ i8*, i32 }
ptr type:
{ i8*, i32 }*
Here is the IR dump for the function (after a couple of passes), right
before it's fed to the JIT:
define { i8*, i32 } @"__anonToplevel/0"() prefix { i8*, i32 } (i32)*
@"XEP:__anonToplevel/0" {
entry:
%0 = call { i8*, i32 } @debugPointer({ i8*, i32 }* nonnull @foo)
%1 = call { i8*, i32 } @debugInt(i32 ptrtoint ({ i8*, i32 }* @foo to i32))
store i8* @FixnumClass, i8** getelementptr inbounds ({ i8*, i32 }, { i8*,
i32 }* @foo, i32 0, i32 0), align 4
%2 = call { i8*, i32 } @debugInt(i32 ptrtoint (i32* getelementptr
inbounds ({ i8*, i32 }, { i8*, i32 }* @foo, i32 0, i32 1) to i32))
store i32 123, i32* getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }*
@foo, i32 0, i32 1), align 4
%3 = call { i8*, i32 } @debugPointer({ i8*, i32 }* nonnull @foo)
store i8* @FixnumClass, i8** getelementptr inbounds ({ i8*, i32 }, { i8*,
i32 }* @foo, i32 0, i32 0), align 4
store i32 123, i32* getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }*
@foo, i32 0, i32 1), align 4
%4 = call { i8*, i32 } @debugPointer({ i8*, i32 }* nonnull @foo)
call void @setGlobal({ i8*, i32 }* nonnull @foo, { i8*, i32 } { i8*
@FixnumClass, i32 123 })
%5 = call { i8*, i32 } @debugPointer({ i8*, i32 }* nonnull @foo)
ret { i8*, i32 } { i8* @FixnumClass, i32 123 }
}
​Here is the runtime from calling the JITed function, including memory
addresses and contents, with my annotations:
# Before
p = 03C10000
class: 00000000
datum: 00000000
# Should be address of the class slot --> correct
x = 03C10000
# Should be address of the datum slot, ie address of class slot + 4 -->
incorrect
x = 03C10000
# Yeah, both values want to class slot, so actual class pointer got
clobbered
p = 03C10000
class: 0000007B
datum: 00000000
# Same result from the single CreateStore
p = 03C10000
class: 0000007B
datum: 00000000
# Calling out to setGlobal as in my first email works
p = 03C10000
class: 039D2E98
datum: 0000007B
Finally, I didn't manage nice disassembly yet, so here is the last output
from --print-after-all for the function. The bizarre thing is that even
this looks correct: the debugInt is called first with @foo, then @foo+4,
and the stores seem to be going to the right addresses as well: @foo and
@foo+4!
BB#0: derived from LLVM BB %entry
PUSHi32 <ga:@foo>, %ESP<imp-def>, %ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
CALLpcrel32 <ga:@debugPointer>, <regmask %BH %BL %BP %BPL %BX
%DI
%DIL %EBP %EBX %EDI %ESI %SI %SIL>, %ESP<imp-use>, %ESP<imp-def>,
%EAX<imp-def,dead>, %EDX<imp-def,dead>
%ESP<def,tied1> = ADD32ri8 %ESP<tied0>, 4,
%EFLAGS<imp-def,dead>
CFI_INSTRUCTION <call frame instruction>
PUSHi32 <ga:@foo>, %ESP<imp-def>, %ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
CALLpcrel32 <ga:@debugInt>, <regmask %BH %BL %BP %BPL %BX %DI
%DIL
%EBP %EBX %EDI %ESI %SI %SIL>, %ESP<imp-use>, %ESP<imp-def>,
%EAX<imp-def,dead>, %EDX<imp-def,dead>
%ESP<def,tied1> = ADD32ri8 %ESP<tied0>, 4,
%EFLAGS<imp-def,dead>
CFI_INSTRUCTION <call frame instruction>
MOV32mi %noreg, 1, %noreg, <ga:@foo>, %noreg,
<ga:@JazzFixnumClass>;
mem:ST4[getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* @foo, i32 0,
i32 0)]
PUSHi32 <ga:@foo+4>, %ESP<imp-def>, %ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
CALLpcrel32 <ga:@debugInt>, <regmask %BH %BL %BP %BPL %BX %DI
%DIL
%EBP %EBX %EDI %ESI %SI %SIL>, %ESP<imp-use>, %ESP<imp-def>,
%EAX<imp-def,dead>, %EDX<imp-def,dead>
%ESP<def,tied1> = ADD32ri8 %ESP<tied0>, 4,
%EFLAGS<imp-def,dead>
CFI_INSTRUCTION <call frame instruction>
MOV32mi %noreg, 1, %noreg, <ga:@foo+4>, %noreg, 123;
mem:ST4[getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* @foo, i32 0,
i32 1)]
PUSHi32 <ga:@foo>, %ESP<imp-def>, %ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
CALLpcrel32 <ga:@debugPointer>, <regmask %BH %BL %BP %BPL %BX
%DI
%DIL %EBP %EBX %EDI %ESI %SI %SIL>, %ESP<imp-use>, %ESP<imp-def>,
%EAX<imp-def,dead>, %EDX<imp-def,dead>
%ESP<def,tied1> = ADD32ri8 %ESP<tied0>, 4,
%EFLAGS<imp-def,dead>
CFI_INSTRUCTION <call frame instruction>
MOV32mi %noreg, 1, %noreg, <ga:@foo>, %noreg,
<ga:@JazzFixnumClass>;
mem:ST4[getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* @foo, i32 0,
i32 0)]
MOV32mi %noreg, 1, %noreg, <ga:@foo+4>, %noreg, 123;
mem:ST4[getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* @foo, i32 0,
i32 1)]
PUSHi32 <ga:@foo>, %ESP<imp-def>, %ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
CALLpcrel32 <ga:@debugPointer>, <regmask %BH %BL %BP %BPL %BX
%DI
%DIL %EBP %EBX %EDI %ESI %SI %SIL>, %ESP<imp-use>, %ESP<imp-def>,
%EAX<imp-def,dead>, %EDX<imp-def,dead>
%ESP<def,tied1> = ADD32ri8 %ESP<tied0>, 4,
%EFLAGS<imp-def,dead>
CFI_INSTRUCTION <call frame instruction>
PUSH32i8 123, %ESP<imp-def>, %ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
PUSHi32 <ga:@JazzFixnumClass>, %ESP<imp-def>,
%ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
PUSHi32 <ga:@foo>, %ESP<imp-def>, %ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
CALLpcrel32 <ga:@setGlobal>, <regmask %BH %BL %BP %BPL %BX %DI
%DIL
%EBP %EBX %EDI %ESI %SI %SIL>, %ESP<imp-use>, %ESP<imp-def>
%ESP<def,tied1> = ADD32ri8 %ESP<tied0>, 12,
%EFLAGS<imp-def,dead>
CFI_INSTRUCTION <call frame instruction>
PUSHi32 <ga:@foo>, %ESP<imp-def>, %ESP<imp-use>
CFI_INSTRUCTION <call frame instruction>
CALLpcrel32 <ga:@debugPointer>, <regmask %BH %BL %BP %BPL %BX
%DI
%DIL %EBP %EBX %EDI %ESI %SI %SIL>, %ESP<imp-use>, %ESP<imp-def>,
%EAX<imp-def,dead>, %EDX<imp-def,dead>
%ESP<def,tied1> = ADD32ri8 %ESP<tied0>, 4,
%EFLAGS<imp-def,dead>
CFI_INSTRUCTION <call frame instruction>
%EAX<def> = MOV32ri <ga:@JazzFixnumClass>
%EDX<def> = MOV32ri 123
RETL %EAX<kill>, %EDX<kill>
Also, I have essentially identical code working perfectly fine when the
memory being written to is from @alloca.
I am completely clueless. Any suggestions most welcome.
Cheers,
-- nikodemus
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20170605/8c7c85cb/attachment.html>
Apparently Analagous Threads
- [newbie] trouble with global variables and CreateLoad/Store in JIT
- [newbie] trouble with global variables and CreateLoad/Store in JIT
- [newbie] trouble with global variables and CreateLoad/Store in JIT
- [newbie] trouble with global variables and CreateLoad/Store in JIT
- [LLVMdev] Code Generation Problem llvm 1.9