I have a package for doing such things. The simplest use is like this:
julia> c = [0.7, 0.5, 0.2]; # from question
julia> x = [10, 100, 1000, 10_000]; # from another answer
julia> using Tullio, OffsetArrays
julia> @tullio y[i] := x[i]*c[3] + x[i-1]*c[2] + x[i-2]*c[1]
2-element OffsetArray(::Vector{Float64}, 3:4) with eltype Float64 with indices 3:4:
257.0
2570.0
julia> @tullio y[i] := x[i+k-3] * c[k] # sum over all k, range of i that's safe
2-element OffsetArray(::Array{Float64,1}, 3:4) with eltype Float64 with indices 3:4:
257.0
2570.0
Since eachindex(c) == 1:3, that's the range of k-values which this sums over, and the range of i is as big as it can be so that i+k-3 stays inside eachindex(x) == 1:4.
To extend the range of i by padding x with two zeros in each direction, write pad(i+k-3, 2). And to compute the shift of i needed to produce an ordinary 1-based Array, write i+_ on the left (and then the -3 makes no difference). Then:
julia> @tullio y[i+_] := x[pad(i+k, 2)] * c[k]
6-element Array{Float64,1}:
2.0
25.0
257.0
2570.0
5700.0
7000.0
On larger arrays, this won't be very fast (at the moment) as it must check at every step whether it is inside x or out in the padding. It's very likely that DSP.conv is a bit smarter about this. (Edit -- DSP.jl seems never to be faster for this c; with a kernel of length 1000 it's faster with 10^6 elements in x.)