Hi,
I've written a simple function:
function testfun2()
a = 0
@inbounds @simd for i in UInt64(1):UInt64(1000)
i = i - ((i >> 1) & 0x5555555555555555)
a += ((i & 0x3333333333333333) + ((i >> 2) & 0x3333333333333333))
end
return a
end
I applies the same set of bit operations to a series of UInt64's and
accumulates a result.
And know from the Intel blog on vectorisation, in the llvm code generated
by julia there is a set of instructions to look out for that indicate
vectorised code: vector.head and vector.ph:
I'm wondering why I don't see those instructions in the llvm generated for
this function, I don't think I've violated any of the rules of writing
loops that can be vectorised:
*julia> **@code_llvm testfun2()*
define %jl_value_t* @julia_testfun2_70900() #0 {
top:
%0 = call %jl_value_t*** @jl_get_ptls_states() #1
%1 = alloca [11 x %jl_value_t*], align 8
%.sub = getelementptr inbounds [11 x %jl_value_t*], [11 x %jl_value_t*]*
%1, i64 0, i64 0
%2 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 8
%3 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 2
%a = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 7
%4 = bitcast %jl_value_t** %2 to i8*
call void @llvm.memset.p0i8.i32(i8* %4, i8 0, i32 24, i32 8, i1 false)
%5 = bitcast [11 x %jl_value_t*]* %1 to i64*
%6 = bitcast %jl_value_t** %3 to i8*
call void @llvm.memset.p0i8.i64(i8* %6, i8 0, i64 40, i32 8, i1 false)
store i64 18, i64* %5, align 8
%7 = bitcast %jl_value_t*** %0 to i64*
%8 = load i64, i64* %7, align 8
%9 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 1
%10 = bitcast %jl_value_t** %9 to i64*
store i64 %8, i64* %10, align 8
store %jl_value_t** %.sub, %jl_value_t*** %0, align 8
%"r#274" = alloca %UnitRange.6, align 8
store %jl_value_t* inttoptr (i64 4400218208 to %jl_value_t*),
%jl_value_t** %a, align 8
%11 = getelementptr inbounds %UnitRange.6, %UnitRange.6* %"r#274", i64 0,
i32 0
store i64 1, i64* %11, align 8
%12 = getelementptr inbounds %UnitRange.6, %UnitRange.6* %"r#274", i64 0,
i32 1
store i64 1000, i64* %12, align 8
%13 = call i64 @julia_simd_inner_length_70896(%UnitRange.6* nonnull
%"r#274", i64 0) #0
%14 = icmp eq i64 %13, 0
br i1 %14, label %L.backedge, label %if26.lr.ph
L8: ; preds = %if26
%15 = load %jl_value_t*, %jl_value_t** %a, align 8
store %jl_value_t* %15, %jl_value_t** %40, align 8
%16 = getelementptr inbounds %jl_value_t, %jl_value_t* %15, i64 -1, i32 0
%17 = bitcast %jl_value_t** %16 to i64*
%18 = load i64, i64* %17, align 8
%19 = and i64 %18, -16
%20 = inttoptr i64 %19 to %jl_value_t*
%21 = icmp eq %jl_value_t* %20, inttoptr (i64 4400088496 to %jl_value_t*)
br i1 %21, label %L11, label %L10
L10: ; preds = %L8
%22 = load i64, i64* %46, align 8
store i64 %22, i64* %47, align 8
%23 = and i64 %53, 3689348814741910323
%24 = lshr i64 %53, 2
%25 = and i64 %24, 3689348814741910323
%26 = add nuw nsw i64 %25, %23
store %jl_value_t* inttoptr (i64 4408276712 to %jl_value_t*),
%jl_value_t** %2, align 8
%27 = call %jl_value_t* @jl_box_uint64(i64 zeroext %26)
store %jl_value_t* %27, %jl_value_t** %44, align 8
%28 = call %jl_value_t* @jl_apply_generic(%jl_value_t** %2, i32 3)
store %jl_value_t* %28, %jl_value_t** %41, align 8
br label %L12
L11: ; preds = %L8, %if26
%"#temp#3.0" = phi %jl_value_t* [ inttoptr (i64 4409008592 to
%jl_value_t*), %if26 ], [ inttoptr (i64 4423075536 to %jl_value_t*), %L8 ]
store %jl_value_t* %"#temp#3.0", %jl_value_t** %42, align 8
%29 = load i64, i64* %46, align 8
store i64 %29, i64* %47, align 8
%30 = and i64 %53, 3689348814741910323
%31 = lshr i64 %53, 2
%32 = and i64 %31, 3689348814741910323
%33 = add nuw nsw i64 %32, %30
store %jl_value_t* inttoptr (i64 4408276712 to %jl_value_t*),
%jl_value_t** %2, align 8
%34 = call %jl_value_t* @jl_box_uint64(i64 zeroext %33)
store %jl_value_t* %34, %jl_value_t** %44, align 8
%35 = call %jl_value_t* @jl_invoke(%jl_value_t* %"#temp#3.0",
%jl_value_t** %2, i32 3)
store %jl_value_t* %35, %jl_value_t** %43, align 8
br label %L12
L12: ; preds = %L11, %L10
%storemerge.in.in = phi %jl_value_t* [ %28, %L10 ], [ %35, %L11 ]
%storemerge.in = bitcast %jl_value_t* %storemerge.in.in to i64*
%storemerge = load i64, i64* %storemerge.in, align 1
%36 = call %jl_value_t* @jl_box_uint64(i64 zeroext %storemerge)
store %jl_value_t* %36, %jl_value_t** %a, align 8
%37 = add nuw i64 %"i#277.040", 1
%exitcond = icmp eq i64 %37, %13
br i1 %exitcond, label %L.backedge.loopexit, label %if26
L.backedge.loopexit: ; preds = %L12
br label %L.backedge
L.backedge: ; preds =
%L.backedge.loopexit, %top
%38 = load %jl_value_t*, %jl_value_t** %a, align 8
%39 = load i64, i64* %10, align 8
store i64 %39, i64* %7, align 8
ret %jl_value_t* %38
if26.lr.ph: ; preds = %top
%40 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 3
%41 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 4
%42 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 5
%43 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 6
%44 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 10
%45 = getelementptr [11 x %jl_value_t*], [11 x %jl_value_t*]* %1, i64 0,
i64 9
%46 = bitcast %jl_value_t** %a to i64*
%47 = bitcast %jl_value_t** %45 to i64*
%.pre = load %jl_value_t*, %jl_value_t** %a, align 8
br label %if26
if26: ; preds = %L12,
%if26.lr.ph
%48 = phi %jl_value_t* [ %.pre, %if26.lr.ph ], [ %36, %L12 ]
%"i#277.040" = phi i64 [ 0, %if26.lr.ph ], [ %37, %L12 ]
%49 = load i64, i64* %11, align 8
%50 = add i64 %49, %"i#277.040"
%51 = lshr i64 %50, 1
%52 = and i64 %51, 6148914691236517205
%53 = sub i64 %50, %52
store %jl_value_t* %48, %jl_value_t** %3, align 8
%54 = getelementptr inbounds %jl_value_t, %jl_value_t* %48, i64 -1, i32 0
%55 = bitcast %jl_value_t** %54 to i64*
%56 = load i64, i64* %55, align 8
%57 = and i64 %56, -16
%58 = inttoptr i64 %57 to %jl_value_t*
%59 = icmp eq %jl_value_t* %58, inttoptr (i64 4400097136 to %jl_value_t*)
br i1 %59, label %L11, label %L8
}
Thanks,
Ben.