[LLVMdev] loop vectorizer: Unexpected extract/insertelement

Frank Winter fwinter at jlab.org
Wed Nov 6 08:15:49 PST 2013


The following IR implements the following nested loop:

for (int i = start ; i < end ; ++i )
   for (int p = 0 ; p < 4 ; ++p )
     a[i*4+p] = b[i*4+p] + c[i*4+p];




define void @main(i64 %arg0, i64 %arg1, i1 %arg2, i64 %arg3, float* 
noalias %arg4, float* noalias %arg5, float* noalias %arg6) {
entrypoint:
   br i1 %arg2, label %L0, label %L1

L0:                                               ; preds = %entrypoint
   %0 = add nsw i64 %arg0, %arg3
   %1 = add nsw i64 %arg1, %arg3
   br label %L2

L1:                                               ; preds = %entrypoint
   br label %L2

L2:                                               ; preds = %L0, %L1
   %2 = phi i64 [ %arg0, %L1 ], [ %0, %L0 ]
   %3 = phi i64 [ %arg1, %L1 ], [ %1, %L0 ]
   %4 = sdiv i64 %2, 4
   %5 = sdiv i64 %3, 4
   br label %L5

L3:                                               ; preds = %L3, %L5
   %6 = phi i64 [ %15, %L3 ], [ 0, %L5 ]
   %7 = mul i64 %19, 4
   %8 = add nsw i64 %7, %6
   %9 = getelementptr float* %arg5, i64 %8
   %10 = load float* %9
   %11 = getelementptr float* %arg6, i64 %8
   %12 = load float* %11
   %13 = fadd float %12, %10
   %14 = getelementptr float* %arg4, i64 %8
   store float %13, float* %14
   %15 = add nsw i64 %6, 1
   %16 = icmp sge i64 %15, 4
   br i1 %16, label %L4, label %L3

L4:                                               ; preds = %L3
   %17 = add nsw i64 %19, 1
   %18 = icmp sge i64 %17, %5
   br i1 %18, label %L6, label %L5

L5:                                               ; preds = %L4, %L2
   %19 = phi i64 [ %17, %L4 ], [ %4, %L2 ]
   br label %L3

L6:                                               ; preds = %L4
   ret void
}


L3 is the inner loop with constant trip count 4.

When calling the loop vectorizer,

opt -loop-vectorize -debug-only=loop-vectorize 
-vectorizer-min-trip-count 4 loop4.ll -S

LV:
Checking a loop in "main"
LV: Found a loop: L3
LV: Found an induction variable.
LV: We need to do 0 pointer comparisons.
LV: We don't need a runtime memory check.
LV: We can vectorize this loop!
LV: Found trip count: 4
LV: The Widest type: 32 bits.
LV: The Widest register is: 128 bits.
....
LV: Vector loop of width 4 costs: 7.
LV: Selecting VF = : 4.
LV: Found a vectorizable loop (4) in loop4.ll
LV: Unroll Factor is 1

we can see that the loop was vectorized. However, the code that is 
produced doesn't look too good:


define void @main(i64 %arg0, i64 %arg1, i1 %arg2, i64 %arg3, float* 
noalias %arg4, float* noalias %arg5, float* noalias %arg6) {
entrypoint:
   br i1 %arg2, label %L0, label %L1

L0:                                               ; preds = %entrypoint
   %0 = add nsw i64 %arg0, %arg3
   %1 = add nsw i64 %arg1, %arg3
   br label %L2

L1:                                               ; preds = %entrypoint
   br label %L2

L2:                                               ; preds = %L1, %L0
   %2 = phi i64 [ %arg0, %L1 ], [ %0, %L0 ]
   %3 = phi i64 [ %arg1, %L1 ], [ %1, %L0 ]
   %4 = sdiv i64 %2, 4
   %5 = sdiv i64 %3, 4
   br label %L5

L3:                                               ; preds = %scalar.ph, %L3
   %6 = phi i64 [ %15, %L3 ], [ %trunc.resume.val, %scalar.ph ]
   %7 = mul i64 %19, 4
   %8 = add nsw i64 %7, %6
   %9 = getelementptr float* %arg5, i64 %8
   %10 = load float* %9
   %11 = getelementptr float* %arg6, i64 %8
   %12 = load float* %11
   %13 = fadd float %12, %10
   %14 = getelementptr float* %arg4, i64 %8
   store float %13, float* %14
   %15 = add nsw i64 %6, 1
   %16 = icmp sge i64 %15, 4
   br i1 %16, label %L4, label %L3, !llvm.loop !0

L4:                                               ; preds = 
%middle.block, %L3
   %17 = add nsw i64 %19, 1
   %18 = icmp sge i64 %17, %5
   br i1 %18, label %L6, label %L5

L5:                                               ; preds = %L4, %L2
   %19 = phi i64 [ %17, %L4 ], [ %4, %L2 ]
   br i1 false, label %middle.block, label %vector.ph

vector.ph:                                        ; preds = %L5
   %broadcast.splatinsert1 = insertelement <4 x i64> undef, i64 %19, i32 0
   %broadcast.splat2 = shufflevector <4 x i64> %broadcast.splatinsert1, 
<4 x i64> undef, <4 x i32> zeroinitializer
   br label %vector.body

vector.body:                                      ; preds = 
%vector.body, %vector.ph
   %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
   %broadcast.splatinsert = insertelement <4 x i64> undef, i64 %index, i32 0
   %broadcast.splat = shufflevector <4 x i64> %broadcast.splatinsert, <4 
x i64> undef, <4 x i32> zeroinitializer
   %induction = add <4 x i64> %broadcast.splat, <i64 0, i64 1, i64 2, i64 3>
   %20 = mul <4 x i64> %broadcast.splat2, <i64 4, i64 4, i64 4, i64 4>
   %21 = add nsw <4 x i64> %20, %induction
   %22 = extractelement <4 x i64> %21, i32 0
   %23 = getelementptr float* %arg5, i64 %22
   %24 = insertelement <4 x float*> undef, float* %23, i32 0
   %25 = extractelement <4 x i64> %21, i32 1
   %26 = getelementptr float* %arg5, i64 %25
   %27 = insertelement <4 x float*> %24, float* %26, i32 1
   %28 = extractelement <4 x i64> %21, i32 2
   %29 = getelementptr float* %arg5, i64 %28
   %30 = insertelement <4 x float*> %27, float* %29, i32 2
   %31 = extractelement <4 x i64> %21, i32 3
   %32 = getelementptr float* %arg5, i64 %31
   %33 = insertelement <4 x float*> %30, float* %32, i32 3
   %34 = extractelement <4 x i64> %21, i32 0
   %35 = getelementptr float* %arg5, i64 %34
   %36 = getelementptr float* %35, i32 0
   %37 = bitcast float* %36 to <4 x float>*
   %wide.load = load <4 x float>* %37
   %38 = extractelement <4 x i64> %21, i32 0
   %39 = getelementptr float* %arg6, i64 %38
   %40 = insertelement <4 x float*> undef, float* %39, i32 0
   %41 = extractelement <4 x i64> %21, i32 1
   %42 = getelementptr float* %arg6, i64 %41
   %43 = insertelement <4 x float*> %40, float* %42, i32 1
   %44 = extractelement <4 x i64> %21, i32 2
   %45 = getelementptr float* %arg6, i64 %44
   %46 = insertelement <4 x float*> %43, float* %45, i32 2
   %47 = extractelement <4 x i64> %21, i32 3
   %48 = getelementptr float* %arg6, i64 %47
   %49 = insertelement <4 x float*> %46, float* %48, i32 3
   %50 = extractelement <4 x i64> %21, i32 0
   %51 = getelementptr float* %arg6, i64 %50
   %52 = getelementptr float* %51, i32 0
   %53 = bitcast float* %52 to <4 x float>*
   %wide.load3 = load <4 x float>* %53
   %54 = fadd <4 x float> %wide.load3, %wide.load
   %55 = extractelement <4 x i64> %21, i32 0
   %56 = getelementptr float* %arg4, i64 %55
   %57 = insertelement <4 x float*> undef, float* %56, i32 0
   %58 = extractelement <4 x i64> %21, i32 1
   %59 = getelementptr float* %arg4, i64 %58
   %60 = insertelement <4 x float*> %57, float* %59, i32 1
   %61 = extractelement <4 x i64> %21, i32 2
   %62 = getelementptr float* %arg4, i64 %61
   %63 = insertelement <4 x float*> %60, float* %62, i32 2
   %64 = extractelement <4 x i64> %21, i32 3
   %65 = getelementptr float* %arg4, i64 %64
   %66 = insertelement <4 x float*> %63, float* %65, i32 3
   %67 = extractelement <4 x i64> %21, i32 0
   %68 = getelementptr float* %arg4, i64 %67
   %69 = getelementptr float* %68, i32 0
   %70 = bitcast float* %69 to <4 x float>*
   store <4 x float> %54, <4 x float>* %70
   %71 = add nsw <4 x i64> %induction, <i64 1, i64 1, i64 1, i64 1>
   %72 = icmp sge <4 x i64> %71, <i64 4, i64 4, i64 4, i64 4>
   %index.next = add i64 %index, 4
   %73 = icmp eq i64 %index.next, 4
   br i1 %73, label %middle.block, label %vector.body

middle.block:                                     ; preds = 
%vector.body, %L5
   %resume.val = phi i64 [ 0, %L5 ], [ 4, %vector.body ]
   %trunc.resume.val = phi i64 [ 0, %L5 ], [ 4, %vector.body ]
   %cmp.n = icmp eq i64 4, %resume.val
   br i1 %cmp.n, label %L4, label %scalar.ph

scalar.ph:                                        ; preds = %middle.block
   br label %L3

L6:                                               ; preds = %L4
   ret void
}



Why did the loop vectorizer produced so many insertelement and 
extractelement instructions?

I don't remember that those instructions entered when vectorizing other 
loops. Is this harmless? Which pass can clean up these instructions?

Frank




More information about the llvm-dev mailing list