Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LLVM replace pointer arithmetic with array indexing

Tags:

llvm

I would like to use LLVM 3.1 to transform loops using pointer arithmetic to instead use array indexing. For example (shown in C rather than bitcode for clarity):

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

should transform into

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

and

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

should transform into

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

I have tried using

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

but I do not see any changes. I do see changes on examples like that in the comment of the IndVarSimplify.cpp file, using only integer loop variables. But I cannot see any examples of pointer arithmetic being raised to use array subscripts, as subscribed in the docs. Is it possible to achieve the results I'm looking for?

Edit:

Below is the bitcode (after mem2reg) for the two "f" functions above. The key difference is the GEP inside the loop, which in the first case is incrementing the pointer from the previous iteration, and in the second case is computing the pointer each time using the base pointer and the index i. This is what I want - to have the address being stored to based on the induction variable i.

Bitcode for first 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
}

Bitcode for second 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
}
like image 585
daniel Avatar asked Jun 08 '26 12:06

daniel


1 Answers

There is no LLVM transformation that does this. I wrote my own instcombine transformation to do it.

like image 101
David Greene Avatar answered Jun 11 '26 22:06

David Greene



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!