When is it OK to use loads and stores with struct types ?


I would like to understand better the implications of using loads and stores with struct types in LLVM IR.

It seems that using loads and stores on struct types leads to troubles as the struct size grows (detailed observations below).

Hence my questions:

  • Is it reasonable/better to use stores and loads with some struct types or should llvm.memcpy always be preferred ?

  • Is there an official limitation on the size of struct types that can be used in load and store operations ?

Thanks in advance for the guidance,

Jean Perier

Here are more details about what I have observed with struct type loads and stores. Take the example:

%t = type { [N x i8] }

define void @foo(%t* %0, %t* %1) {

%3 = load %t, %t* %1

store %t %3, %t* %0

ret void


I noticed that:

  • llc compile times are not linear at all with N (with a debug build on a powerful machine, N=100 → 0.05s, N=500 → 1.4s, N = 1000 → 2.25s, N = 2000 : 12.5s. … N= 65535 : more than 22 minutes, I did not wait).

  • llc hits a first assert when N >= 65536 (at [1] in the code, reported 10 years ago in bug [2]).

  • llc hits a different assert when N >= 2097153 (at [3] in the code, reported a year ago in bugs [4])

All this leads me to question if I should produce LLVM IR that loads/stores struct types, or just always use llvm.memcpy for them. Why is it allowed to load/store them if it can lead to trouble ?

[1] https://github.com/llvm/llvm-project/blob/4c484f11d355e4293f7b245a9330f0a1e89630ac/llvm/include/llvm/CodeGen/SelectionDAGNodes.h#L1069

[2] https://bugs.llvm.org/show_bug.cgi?id=7250 and more recently duplicated in https://bugs.llvm.org/show_bug.cgi?id=37000

[3] https://github.com/llvm/llvm-project/blob/4c484f11d355e4293f7b245a9330f0a1e89630ac/llvm/lib/IR/Type.cpp#L315

[4] https://bugs.llvm.org/show_bug.cgi?id=48615 and https://bugs.llvm.org/show_bug.cgi?id=50913

Not specifically on the topic you ask about, but we do have some general advice on IR features to prefer vs avoid here: