LLVM用数组索引替换指针算术运算

3

我希望使用LLVM 3.1将使用指针算术的循环转换为使用数组索引。例如(为了清晰起见,以C而不是位码显示):

void f() {
    int buf[10];
    int i;
    int *p = buf;
    for (i = 0; i < 10; i++)
        *p++ = 0;
}

应该转换成

void f() {
    int buf[10];
    int i;
    int *p = buf;
    for (i = 0; i < 10; i++)
        p[i] = 0;
}

并且

void g(int *p, int n) {
    int *end = p + n;
    for (; p < end, p++)
        *p = 0;
}

应该转换为

void g(int *p, int n) {
    int i;
    for (i = 0; i < n, i++)
        p[i] = 0;
}

我尝试使用

opt -mem2reg -indvars <bc-file> -S

但我没有看到任何变化。 我确实看到了像IndVarSimplify.cpp文件中评论中那样的示例发生了变化,仅使用整数循环变量。 但是我没有看到任何指针算术被升级为使用数组下标的示例,正如文档中所述。 我是否能够达到我想要的结果?

编辑:

下面是上面两个“f”函数的位码(经过mem2reg处理)。 主要区别在于循环内部的GEP,其中在第一种情况下指针从上一次迭代开始递增,在第二种情况下,每次使用基本指针和索引i计算指针。 这就是我想要的 - 根据归纳变量i存储地址。

第一个f的位码:

define void @f() nounwind uwtable {
entry:
  %buf = alloca [10 x i32], align 16
  %arraydecay = getelementptr inbounds [10 x i32]* %buf, i32 0, i32 0
  br label %for.cond

for.cond:                                         ; preds = %for.inc, %entry
  %p.0 = phi i32* [ %arraydecay, %entry ], [ %incdec.ptr, %for.inc ]
  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
  %cmp = icmp slt i32 %i.0, 10
  br i1 %cmp, label %for.body, label %for.end

for.body:                                         ; preds = %for.cond
  %incdec.ptr = getelementptr inbounds i32* %p.0, i32 1
  store i32 0, i32* %p.0, align 4
  br label %for.inc

for.inc:                                          ; preds = %for.body
  %inc = add nsw i32 %i.0, 1
  br label %for.cond

for.end:                                          ; preds = %for.cond
  ret void
}

第二个f的位码:

define void @f() nounwind uwtable {
entry:
  %buf = alloca [10 x i32], align 16
  %arraydecay = getelementptr inbounds [10 x i32]* %buf, i32 0, i32 0
  br label %for.cond

for.cond:                                         ; preds = %for.inc, %entry
  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
  %cmp = icmp slt i32 %i.0, 10
  br i1 %cmp, label %for.body, label %for.end

for.body:                                         ; preds = %for.cond
  %idxprom = sext i32 %i.0 to i64
  %arrayidx = getelementptr inbounds i32* %arraydecay, i64 %idxprom
  store i32 0, i32* %arrayidx, align 4
  br label %for.inc

for.inc:                                          ; preds = %for.body
  %inc = add nsw i32 %i.0, 1
  br label %for.cond

for.end:                                          ; preds = %for.cond
  ret void
}

我不确定LLVM中是否有一种分析工具可以做到这一点。您能否同时发布位码,以帮助我们了解分析工具需要识别什么? - James
2
“指针算术”和“数组索引”在本质上没有任何区别。在IR级别,它们都是通过GEP指令完成的。我唯一能想到的是,如果您的静态分析可以证明该指针存在已知边界,则将GEP替换为有界GEP。 - SK-logic
@SK-logic:第一种情况是在循环中使用索引1的GEP更新指针值,而第二种情况是在循环中计算从p带有索引i的GEP的指针。 - daniel
@daniel,我不确定在进行了多次InstCombine之后是否会保留这样的差异。 - SK-logic
@SK-logic,感谢您的帮助,但它仍然没有产生我想要的结果,即直接从IV计算指针。我正在使用的命令是“opt -instcombine -instcombine -scalarrepl -instcombine -instcombine -indvars -instcombine -instcombine”(大量的instcombines只是为了确保),是否还需要其他的passes? - daniel
1个回答

1

目前没有LLVM转换可以做到这一点。我编写了自己的instcombine转换来实现它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接