LLVM GEP 和存储 vs 加载和插入值:将值存储到指向聚合的指针

LLVM GEP and store vs load and insertvalue: Storing value to a pointer to an aggregate

在将值存储到指向聚合类型的指针时,getelementptrstoreloadinsertvalue 有什么区别?在某些情况下是首选吗?如果是这样,为什么?还是我完全走错了方向?

示例:

; 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
}

有趣的是,使用 llc -O=0 ... 它们都编译为相同的指令。大致如下,这也是我所希望的。

movl , -16(%rsp) # GEP + store
movq , -8(%rsp)  # load + insertvalue

背景:

我正在阅读 LLVM Language Reference and I was reading about insertvalue. The reference notes the extractvalue instructions similarity with GEP 和以下差异。

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.

Whosebug 上的以下问题也提到了 getelementptrinsertvalue 的使用,但出于不同的原因。 LLVM insertvalue bad optimized?

在语义上,loading 和稍后 storeing 整个对象更浪费。如果它是一个巨大的结构怎么办?如果它是一个结构数组怎么办? GEP 允许您访问内存中您想要 load/store 的确切位置,而无需 load/store 任何其他内容。

虽然在您的示例中这两种形式被降低为相同的指令,但通常不能保证。