This is a longer discussion, but the issue is that Halide::clamp(x, 0, in.width()-1) establishes an edge replication boundary condition on x. (Being very clear for others who may be reading that in.width() means in.extent(0) and we are assuming we're working with dimension 0 of in here.)

When processing tiles, one does not want edge replication at the tile boundaries but rather one wishes to require the input tiles have enough padding to satisfy the requested output area. (And if that area extends off the edge of the image, then apply the boundary condition at the image edge.) It should be an error in most cases if tiled processing reads outside of the input tiles at coordinates that are not at the edge of the of the entire image.

Now we can say that images, by convention, always have a 0 origin and that makes the 0 boundary generally the correct place to apply the boundary condition. However the extent (width if talking about dimension 0) is only correct for applying the boundary condition if we pass in the entire image.

I started writing up a lot of stuff on this a long time ago and Andrew and Jonathan and I have talked about it more than once. With Halide as it stands now, the best solution is likely to pass the total image area (extent and possibly origin) as extra parameters to the filter. One could possibly also make it an implicit global using user_context or some such, though I'm not sure that wins anything other than allowing filter signatures to stay the same if adding this functionality. It is however clear that we should consider extending Halide to handle this cleanly.