Size of structs & arrays

I'm trying to work out the size of a struct so that I can pass this to the
'llvm.memcpy' intrinsic. It's easy to find out how I'm supposed to do this,
as I keep seeing the following:

%Size = getelementptr %T* null, int 1
%SizeI = cast %T* %Size to uint

But I'm unsure how I actually do this in the C++ API. Is the 'null' here a
llvm::ConstantPointerNull? Any help here would be much appreciated.

Additionally, I was wondering whether I can use this method to find out the
size of variable-length arrays, such as [0 x i32], for example? I've tried
doing this and am obviously doing something wrong.

%Size = getelementptr [0 x i32]* %1, i32* null, i32 1
%SizeI = ptrtoint i32* %Size to i64

This gives entirely the wrong result, and I'm not surprised, as it doesn't
look correct. Should I instead be implementing these arrays with a size
associated with them? Something like { i32, [0 x i32]}, for instance?

Cheers,
Fraser

I'm trying to work out the size of a struct so that I can pass this to the
'llvm.memcpy' intrinsic. It's easy to find out how I'm supposed to do this,
as I keep seeing the following:

%Size = getelementptr %T* null, int 1
%SizeI = cast %T* %Size to uint

But I'm unsure how I actually do this in the C++ API. Is the 'null' here a
llvm::ConstantPointerNull? Any help here would be much appreciated.

Try llvm::Constant::getNullValue().

Additionally, I was wondering whether I can use this method to find out the
size of variable-length arrays, such as [0 x i32], for example? I've tried
doing this and am obviously doing something wrong.

%Size = getelementptr [0 x i32]* %1, i32* null, i32 1
%SizeI = ptrtoint i32* %Size to i64

This gives entirely the wrong result, and I'm not surprised, as it doesn't
look correct. Should I instead be implementing these arrays with a size
associated with them? Something like { i32, [0 x i32]}, for instance?

Yes; [0 x i32] isn't really a variable-length array, just a
placeholder for an array of unknown size. You have to track the size
yourself.

-Eli

Eli Friedman-2 wrote:

Try llvm::Constant::getNullValue().

I'm trying this:

llvm::Constant* one =
llvm::Constant::getNullValue(llvm::IntegerType::get(mod->getContext(), 64));
llvm::ConstantInt* two = llvm::ConstantInt::get(mod->getContext(),
llvm::APInt(32, llvm::StringRef("1"), 10));

std::vector<llvm::Value*> indices;
indices.push_back(one); indices.push_back(two);
  
llvm::Value* size = builder->CreateGEP(struct_ptr, indices);
llvm::Value* size_int = builder->CreatePtrToInt(size,
llvm::IntegerType::get(mod->getContext(), 64))

And I'm getting the assertion error "Invalid GetElementPtrInst indices for
type!"'. 'struct_ptr' is a pointer to the struct I'm trying to size. I've
also tried using getNullValue on the struct's own type.

Sorry to ask so directly, but I'd quite like to get this sorted.

Eli Friedman-2 wrote:

Try llvm::Constant::getNullValue().

I'm trying this:

llvm::Constant* one =
llvm::Constant::getNullValue(llvm::IntegerType::get(mod->getContext(), 64));
llvm::ConstantInt* two = llvm::ConstantInt::get(mod->getContext(),
llvm::APInt(32, llvm::StringRef("1"), 10));

std::vector<llvm::Value*> indices;
indices.push_back(one); indices.push_back(two);
  
llvm::Value* size = builder->CreateGEP(struct_ptr, indices);
llvm::Value* size_int = builder->CreatePtrToInt(size,
llvm::IntegerType::get(mod->getContext(), 64))

And I'm getting the assertion error "Invalid GetElementPtrInst indices for
type!"'. 'struct_ptr' is a pointer to the struct I'm trying to size. I've
also tried using getNullValue on the struct's own type.

Sorry to ask so directly, but I'd quite like to get this sorted.

Try something more like:

llvm::Constant* base = llvm::Constant::getNullValue(struct_ptr->getType());
llvm::Value* size = builder->CreateConstGEP1_32(base, 1);

-Eli

Hi Fraser,

I'm trying to work out the size of a struct so that I can pass this to the
'llvm.memcpy' intrinsic. It's easy to find out how I'm supposed to do this,
as I keep seeing the following:

%Size = getelementptr %T* null, int 1
%SizeI = cast %T* %Size to uint

But I'm unsure how I actually do this in the C++ API. Is the 'null' here a
llvm::ConstantPointerNull? Any help here would be much appreciated.

you can use ConstantExpr::getSizeOf.

Additionally, I was wondering whether I can use this method to find out the
size of variable-length arrays, such as [0 x i32], for example? I've tried
doing this and am obviously doing something wrong.

%Size = getelementptr [0 x i32]* %1, i32* null, i32 1
%SizeI = ptrtoint i32* %Size to i64

This gives entirely the wrong result,

This will return zero, since this array has size zero. It is not a variable
length array, it is an array with length zero.

  and I'm not surprised, as it doesn't

look correct. Should I instead be implementing these arrays with a size
associated with them? Something like { i32, [0 x i32]}, for instance?

You need to know the length somehow. This is one way.

Ciao, Duncan.

Eli Friedman-2 wrote:

Try llvm::Constant::getNullValue().

Thanks, that's working nicely (so far).

Eli Friedman-2 wrote:

Yes; [0 x i32] isn't really a variable-length array, just a
placeholder for an array of unknown size. You have to track the size
yourself.

This is working, too, however I'm getting a segmentation fault at runtime.

  %MainClass = type { { i32, [0 x i32] } }

  %this = alloca %MainClass*
  %0 = alloca { i32, [5 x i32] }

  ... Here, I store 5 into %0[0] and a constant array into %0[1]. This runs
without error.

  %7 = load %MainClass** %this
  %8 = getelementptr inbounds %MainClass* %7, i32 0, i32 0
  %9 = getelementptr inbounds { i32, [0 x i32] }* %8, i32 0, i32 0
  %10 = getelementptr inbounds { i32, [5 x i32] }* %0, i32 0, i32 0
  %11 = load i32* %10
  store i32 %11, i32* %9
  %12 = getelementptr inbounds { i32, [0 x i32] }* %8, i32 0, i32 1
  %13 = getelementptr inbounds { i32, [5 x i32] }* %0, i32 0, i32 1
  %14 = bitcast [0 x i32]* %12 to i8*
  %15 = bitcast [5 x i32]* %13 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %14, i8* %15, i64 20, i32 4, i1
false)
  ret void

I can't see anything wrong with this bytecode (except for being verbose),
and I don't blame you if you don't want to debug it yourself, but I thought
I'd post it anyway.

If I access a value of MainClass's array after the transfer, and print it
out, then it does so successfully, then continues to segfault. So it looks
like it's copied the memory okay, but I've corrupted something in the
process..

Fraser Cormack wrote:

This is working, too, however I'm getting a segmentation fault at runtime.

Okay so I've delved a bit deeper, and run this program with lli
--force-interpreter and it gets this result:

   LLVM ERROR: Tried to execute an unknown external function: memcpy

I've read that one has to install libffi then re-configure and reinstall
llvm, however this hasn't worked for me. Perhaps I need to link it somehow,
but anyway.

I've also run the program with lli -debug and this is the end result:

********** EMITTING LIVE DEBUG VARIABLES **********
********** Stack Slot Coloring **********
********** Function: java/lang/Object::<init>()
******** Post-regalloc Machine LICM: java/lang/Object::<init>() ********
Machine Function
********** EXPANDING POST-RA PSEUDO INSTRS **********
********** Function: java/lang/Object::<init>()
JITTing function 'java/lang/Object::<init>()'
JIT: Starting CodeGen of Function java/lang/Object::<init>()
JIT: Emitting BB0 at [0x7f09970c8140]
RET
JIT: Finished CodeGen of [0x7f09970c8140] Function:
java/lang/Object::<init>(): 1 bytes of text, 0 relocations
JIT: Binary code:
JIT: 0: 195
SectionIdx: 0, Name: , Size: 0, Offset: 0, SectionData Size: 0
SectionIdx: 1, Name: .text, Size: 1, Offset: 64, SectionData Size: 1
SectionIdx: 2, Name: .eh_frame, Size: 64, Offset: 65, SectionData Size: 64
SectionIdx: 3, Name: .data, Size: 0, Offset: 129, SectionData Size: 0
SectionIdx: 4, Name: .bss, Size: 0, Offset: 129, SectionData Size: 0
SectionIdx: 5, Name: .strtab, Size: 52, Offset: 129, SectionData Size: 52
SectionIdx: 6, Name: .symtab, Size: 168, Offset: 184, SectionData Size: 168
SectionIdx: 7, Name: .shstrtab, Size: 54, Offset: 352, SectionData Size: 54
Segmentation fault

So this information doesn't really help or mean much to me. Any help is, of
course, much appreciated :slight_smile:

Cheers,
Fraser