What is the difference between getelementptr
and store
vs. load
and insertvalue
when storing a value to a pointer to an aggregate type? Is one preferred in certain circumstances? And if so why? Or am I headed entirely in the wrong direction?
; A contrived example
%X = type {i32, i64}
define i32 @main(i32 %argc, i8** %argv) {
entry:
%sX.0 = alloca %X
; change the first value with GEP + store
%val1 = getelementptr %X, %X* %sX.0, i32 0, i32 0
store i32 42, i32* %val1
; change the second value with load + insertvalue
%sX.1 = load %X, %X* %sX.0
%sX.2 = insertvalue %X %sX.1, i64 42, 1
store %X %sX.2, %X* %sX.0 ; I suppose this could be considered less than ideal
; however in some cases it is nice to have the
; struct `load`ed
ret i32 0
}
Interestingly using llc -O=0 ...
they both compile to the the same instructions. What amounts to the following, which is what I had hoped.
movl $42, -16(%rsp) # GEP + store
movq $42, -8(%rsp) # load + insertvalue
I was reading the LLVM Language Reference and I was reading about insertvalue. The reference notes the extractvalue
instructions similarity with GEP and the following differences.
The major differences to getelementptr indexing are:
Since the value being indexed is not a pointer, the first index is omitted and assumed to be zero.
At least one index must be specified.
Not only struct indices but also array indices must be in bounds.
The following question on StackOverflow also mentions the use of getelementptr
and insertvalue
, but for different reasons. LLVM insertvalue bad optimized?
Semantically, load
ing and later store
ing the entire object is more wasteful. What if it's a huge struct? What if it's an array of structs? GEP allows you to access an exact location in memory where you want to load/store, without the need to load/store anything else.
While the two forms were lowered to the same instructions in your example, it isn't generally guaranteed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With