Here is the LLVM IR I get:
julia> @code_llvm debuginfo=:none f.( 1, 1:100 )
; Function Attrs: uwtable
define nonnull {}* @"julia_##dotfunction#315#4_257"(i64 signext %0, [2 x i64]* nocapture nonnull readonly align 8 dereferenceable(16) %1) #0 {
top:
%2 = alloca [1 x [1 x i64]], align 8
%3 = alloca [1 x [1 x i64]], align 8
%4 = getelementptr inbounds [2 x i64], [2 x i64]* %1, i64 0, i64 0
%5 = getelementptr inbounds [2 x i64], [2 x i64]* %1, i64 0, i64 1
%6 = load i64, i64* %5, align 8
%7 = load i64, i64* %4, align 8
%8 = sub i64 %6, %7
%9 = add i64 %8, 1
%10 = icmp ult i64 %8, 9223372036854775807
%11 = select i1 %10, i64 %9, i64 0
%12 = getelementptr inbounds [1 x [1 x i64]], [1 x [1 x i64]]* %2, i64 0, i64 0, i64 0
store i64 %11, i64* %12, align 8
%13 = call nonnull {}* inttoptr (i64 1698961392 to {}* ({}*, i64)*)({}* inttoptr (i64 271088912 to {}*), i64 %11)
%14 = bitcast {}* %13 to { i8*, i64, i16, i16, i32 }*
%15 = getelementptr inbounds { i8*, i64, i16, i16, i32 }, { i8*, i64, i16, i16, i32 }* %14, i64 0, i32 1
%16 = load i64, i64* %15, align 8
%.not.not = icmp eq i64 %16, %11
br i1 %.not.not, label %L23, label %L101
L23: ; preds = %top
%.not18 = icmp sgt i64 %11, 0
%or.cond = select i1 %10, i1 %.not18, i1 false
br i1 %or.cond, label %L43.lr.ph, label %L112
L43.lr.ph: ; preds = %L23
%.not17 = icmp eq i64 %6, %7
%17 = shl i64 %0, 1
%18 = bitcast {}* %13 to i64**
%19 = load i64*, i64** %18, align 8
br i1 %.not17, label %L43.lr.ph.split.us, label %L43.preheader
L43.preheader: ; preds = %L43.lr.ph
%min.iters.check = icmp ult i64 %11, 16
br i1 %min.iters.check, label %L43, label %vector.ph
vector.ph: ; preds = %L43.preheader
%n.vec = and i64 %11, -16
%broadcast.splatinsert = insertelement <4 x i64> poison, i64 %17, i32 0
%broadcast.splatinsert31 = insertelement <4 x i64> poison, i64 %7, i32 0
br label %vector.body
vector.body: ; preds = %vector.body, %vector.ph
%index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
%vec.ind = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, %vector.ph ], [ %vec.ind.next, %vector.body ]
%20 = add <4 x i64> %broadcast.splatinsert, <i64 4, i64 poison, i64 poison, i64 poison>
%21 = add <4 x i64> %broadcast.splatinsert, <i64 8, i64 poison, i64 poison, i64 poison>
%22 = add <4 x i64> %broadcast.splatinsert31, %broadcast.splatinsert
%23 = shufflevector <4 x i64> %22, <4 x i64> poison, <4 x i32> zeroinitializer
%24 = add <4 x i64> %23, %vec.ind
%25 = add <4 x i64> %broadcast.splatinsert31, %20
%26 = shufflevector <4 x i64> %25, <4 x i64> poison, <4 x i32> zeroinitializer
%27 = add <4 x i64> %26, %vec.ind
%28 = add <4 x i64> %broadcast.splatinsert31, %21
%29 = shufflevector <4 x i64> %28, <4 x i64> poison, <4 x i32> zeroinitializer
%30 = add <4 x i64> %29, %vec.ind
%31 = add <4 x i64> %22, <i64 12, i64 poison, i64 poison, i64 poison>
%32 = shufflevector <4 x i64> %31, <4 x i64> poison, <4 x i32> zeroinitializer
%33 = add <4 x i64> %32, %vec.ind
%34 = getelementptr inbounds i64, i64* %19, i64 %index
%35 = bitcast i64* %34 to <4 x i64>*
store <4 x i64> %24, <4 x i64>* %35, align 8
%36 = getelementptr inbounds i64, i64* %34, i64 4
%37 = bitcast i64* %36 to <4 x i64>*
store <4 x i64> %27, <4 x i64>* %37, align 8
%38 = getelementptr inbounds i64, i64* %34, i64 8
%39 = bitcast i64* %38 to <4 x i64>*
store <4 x i64> %30, <4 x i64>* %39, align 8
%40 = getelementptr inbounds i64, i64* %34, i64 12
%41 = bitcast i64* %40 to <4 x i64>*
store <4 x i64> %33, <4 x i64>* %41, align 8
%index.next = add nuw i64 %index, 16
%vec.ind.next = add <4 x i64> %vec.ind, <i64 16, i64 16, i64 16, i64 16>
%42 = icmp eq i64 %index.next, %n.vec
br i1 %42, label %middle.block, label %vector.body
middle.block: ; preds = %vector.body
%cmp.n = icmp eq i64 %11, %n.vec
br i1 %cmp.n, label %L112, label %L43
L43.lr.ph.split.us: ; preds = %L43.lr.ph
%43 = add i64 %17, %6
%min.iters.check42 = icmp ult i64 %11, 16
br i1 %min.iters.check42, label %L43.us, label %vector.ph43
vector.ph43: ; preds = %L43.lr.ph.split.us
%n.vec45 = and i64 %11, -16
%broadcast.splatinsert50 = insertelement <4 x i64> poison, i64 %43, i32 0
%broadcast.splat51 = shufflevector <4 x i64> %broadcast.splatinsert50, <4 x i64> poison, <4 x i32> zeroinitializer
br label %vector.body41
vector.body41: ; preds = %vector.body41, %vector.ph43
%index46 = phi i64 [ 0, %vector.ph43 ], [ %index.next47, %vector.body41 ]
%44 = getelementptr inbounds i64, i64* %19, i64 %index46
%45 = bitcast i64* %44 to <4 x i64>*
store <4 x i64> %broadcast.splat51, <4 x i64>* %45, align 8
%46 = getelementptr inbounds i64, i64* %44, i64 4
%47 = bitcast i64* %46 to <4 x i64>*
store <4 x i64> %broadcast.splat51, <4 x i64>* %47, align 8
%48 = getelementptr inbounds i64, i64* %44, i64 8
%49 = bitcast i64* %48 to <4 x i64>*
store <4 x i64> %broadcast.splat51, <4 x i64>* %49, align 8
%50 = getelementptr inbounds i64, i64* %44, i64 12
%51 = bitcast i64* %50 to <4 x i64>*
store <4 x i64> %broadcast.splat51, <4 x i64>* %51, align 8
%index.next47 = add nuw i64 %index46, 16
%52 = icmp eq i64 %index.next47, %n.vec45
br i1 %52, label %middle.block39, label %vector.body41
middle.block39: ; preds = %vector.body41
%cmp.n49 = icmp eq i64 %11, %n.vec45
br i1 %cmp.n49, label %L112, label %L43.us
L43.us: ; preds = %L43.us, %middle.block39, %L43.lr.ph.split.us
%value_phi119.us = phi i64 [ %54, %L43.us ], [ %n.vec45, %middle.block39 ], [ 0, %L43.lr.ph.split.us ]
%53 = getelementptr inbounds i64, i64* %19, i64 %value_phi119.us
store i64 %43, i64* %53, align 8
%54 = add nuw nsw i64 %value_phi119.us, 1
%exitcond20.not = icmp eq i64 %54, %11
br i1 %exitcond20.not, label %L112, label %L43.us
L43: ; preds = %L43, %middle.block, %L43.preheader
%value_phi119 = phi i64 [ %58, %L43 ], [ %n.vec, %middle.block ], [ 0, %L43.preheader ]
%55 = add i64 %value_phi119, %17
%56 = add i64 %55, %7
%57 = getelementptr inbounds i64, i64* %19, i64 %value_phi119
store i64 %56, i64* %57, align 8
%58 = add nuw nsw i64 %value_phi119, 1
%exitcond.not = icmp eq i64 %58, %11
br i1 %exitcond.not, label %L112, label %L43
L101: ; preds = %top
%59 = getelementptr inbounds [1 x [1 x i64]], [1 x [1 x i64]]* %3, i64 0, i64 0, i64 0
store i64 %16, i64* %59, align 8
%60 = call nonnull {}* @j_throwdm_262([1 x [1 x i64]]* nocapture readonly %3, [1 x [1 x i64]]* nocapture readonly %2) #0
call void @llvm.trap()
unreachable
L112: ; preds = %L43, %L43.us, %middle.block39, %middle.block, %L23
ret {}* %13
}
The c = 2a
part is %17 = shl i64 %0, 1
. It reduces the multiply by two to a left bitshift by one bit.
If we change it to c = 4a
, then it becomes %17 = shl i64 %0, 2
. The multiply by four shifts the bits to the left by two bits.