diff --git a/Data/Array/Repa/Eval/Cursored.hs b/Data/Array/Repa/Eval/Cursored.hs
--- a/Data/Array/Repa/Eval/Cursored.hs
+++ b/Data/Array/Repa/Eval/Cursored.hs
@@ -33,15 +33,15 @@
 	-> Int#			-- ^ Width of the whole array.
 	-> Int#			-- ^ x0 lower left corner of block to fill
 	-> Int#			-- ^ y0 
-	-> Int#			-- ^ x1 upper right corner of block to fill
-	-> Int#			-- ^ y1
+	-> Int#			-- ^ w0 width of block to fill.
+	-> Int#			-- ^ h0 height of block to fill.
         -> IO ()
 
 {-# INLINE [0] fillBlock2P #-}
-fillBlock2P !write !getElem !imageWidth !x0 !y0 !x1 !y1
+fillBlock2P !write !getElem !imageWidth !x0 !y0 !w0 h0
  = fillCursoredBlock2P 
         write id addDim getElem 
-        imageWidth x0 y0 x1 y1
+        imageWidth x0 y0 w0 h0
 
 
 -- | Fill a block in a rank-2 array sequentially.
@@ -60,15 +60,15 @@
 	-> Int#			-- ^ Width of the whole array.
 	-> Int#			-- ^ x0 lower left corner of block to fill
 	-> Int#			-- ^ y0
-	-> Int#			-- ^ x1 upper right corner of block to fill
-	-> Int#			-- ^ y1
+	-> Int#			-- ^ w0 width of block to fill
+	-> Int#			-- ^ h0 height of block to filll
         -> IO ()
 
 {-# INLINE [0] fillBlock2S #-}
-fillBlock2S !write !getElem imageWidth x0 y0 x1 y1
+fillBlock2S !write !getElem imageWidth x0 y0 w0 h0
  = fillCursoredBlock2S
         write id addDim getElem 
-        imageWidth x0 y0 x1 y1
+        imageWidth x0 y0 w0 h0
 
 
 -- Block filling ----------------------------------------------------------------------------------
@@ -91,46 +91,46 @@
 	-> (DIM2   -> cursor)		-- ^ Make a cursor to a particular element.
 	-> (DIM2   -> cursor -> cursor)	-- ^ Shift the cursor by an offset.
 	-> (cursor -> a)		-- ^ Function to evaluate the element at an index.
-	-> Int#			-- ^ Width of the whole array.
-	-> Int#			-- ^ x0 lower left corner of block to fill
-	-> Int#			-- ^ y0
-	-> Int#			-- ^ x1 upper right corner of block to fill
-	-> Int#			-- ^ y1
+	-> Int#			        -- ^ Width of the whole array.
+	-> Int#			        -- ^ x0 lower left corner of block to fill
+	-> Int#			        -- ^ y0
+	-> Int#			        -- ^ w0 width of block to fill
+	-> Int#			        -- ^ h0 height of block to fill
 	-> IO ()
 
 {-# INLINE [0] fillCursoredBlock2P #-}
 fillCursoredBlock2P
 	!write
 	!makeCursorFCB !shiftCursorFCB !getElemFCB
-	!imageWidth !x0 !y0 !x1 !y1
+	!imageWidth !x0 !y0 !w0 !h0
  = 	gangIO theGang fillBlock
- where	!(I# threads)  = gangSize theGang
-	!blockWidth    = x1 -# x0 +# 1#
+ where	
+        !(I# threads)  = gangSize theGang
 
 	-- All columns have at least this many pixels.
-	!colChunkLen   = I# (blockWidth `quotInt#` threads)
+	!colChunkLen   = w0 `quotInt#` threads
 
 	-- Extra pixels that we have to divide between some of the threads.
-	!colChunkSlack = I# (blockWidth `remInt#` threads)
+	!colChunkSlack = w0 `remInt#` threads
 
 	-- Get the starting pixel of a column in the image.
 	{-# INLINE colIx #-}
 	colIx !ix
-	 | ix < colChunkSlack = (I# x0) +  ix * (colChunkLen  + 1)
-	 | otherwise	      = (I# x0) + (ix * colChunkLen) + colChunkSlack
+	 | ix <# colChunkSlack = x0 +# (ix *# (colChunkLen +# 1#))
+	 | otherwise	       = x0 +# (ix *# colChunkLen) +# colChunkSlack
 
 	-- Give one column to each thread
 	{-# INLINE fillBlock #-}
 	fillBlock :: Int -> IO ()
-	fillBlock !ix
-	 = let	!(I# x0')	= colIx ix
-		!(I# x1')	= colIx (ix + 1) - 1
+	fillBlock !(I# ix)
+	 = let	!x0'	  = colIx ix
+		!w0'      = colIx (ix +# 1#) -# x0'
 		!y0'	  = y0
-		!y1'	  = y1
+		!h0'	  = h0
 	   in	fillCursoredBlock2S
 			write
 			makeCursorFCB shiftCursorFCB getElemFCB
-			imageWidth x0' y0' x1' y1'
+			imageWidth x0' y0' w0' h0'
 
 
 -- | Fill a block in a rank-2 array, sequentially.
@@ -153,30 +153,32 @@
 	-> Int#				-- ^ Width of the whole array.
 	-> Int#				-- ^ x0 lower left corner of block to fill.
 	-> Int#				-- ^ y0
-	-> Int#				-- ^ x1 upper right corner of block to fill.
-	-> Int#				-- ^ y1
+	-> Int#				-- ^ w0 width of block to fill
+	-> Int#				-- ^ h0 height of block to fill
 	-> IO ()
 
 {-# INLINE [0] fillCursoredBlock2S #-}
 fillCursoredBlock2S
 	!write
 	!makeCursor !shiftCursor !getElem
-	!imageWidth !x0 !y0 !x1 !y1
+	!imageWidth !x0 !y0 !w0 h0
 
- = fillBlock y0
+ = do   fillBlock y0
+ where	!x1     = x0 +# w0
+        !y1     = y0 +# h0
 
- where	{-# INLINE fillBlock #-}
+        {-# INLINE fillBlock #-}
 	fillBlock !y
-	 | y ># y1	= return ()
+	 | y >=# y1	= return ()
 	 | otherwise
 	 = do	fillLine4 x0
 		fillBlock (y +# 1#)
 
 	 where	{-# INLINE fillLine4 #-}
 		fillLine4 !x
- 	   	 | x +# 4# ># x1 	= fillLine1 x
+ 	   	 | x +# 4# >=# x1 	= fillLine1 x
 	   	 | otherwise
-	   	 = do	-- Compute each source cursor based on the previous one so that
+	   	 = do   -- Compute each source cursor based on the previous one so that
 			-- the variable live ranges in the generated code are shorter.
 			let srcCur0	= makeCursor  (Z :. (I# y) :. (I# x))
 			let srcCur1	= shiftCursor (Z :. 0 :. 1) srcCur0
@@ -208,9 +210,9 @@
 
 		{-# INLINE fillLine1 #-}
 		fillLine1 !x
- 	   	 | x ># x1		= return ()
+ 	   	 | x >=# x1		= return ()
 	   	 | otherwise
-	   	 = do	write (I# (x +# (y *# imageWidth)))
-                              (getElem $ makeCursor (Z :. (I# y) :. (I# x)))
+	   	 = do	let val0     = (getElem $ makeCursor (Z :. (I# y) :. (I# x)))
+                        write (I# (x +# (y *# imageWidth))) val0
 			fillLine1 (x +# 1#)
 
diff --git a/Data/Array/Repa/Eval/Fill.hs b/Data/Array/Repa/Eval/Fill.hs
--- a/Data/Array/Repa/Eval/Fill.hs
+++ b/Data/Array/Repa/Eval/Fill.hs
@@ -29,6 +29,10 @@
  -- | Ensure the strucure of a mutable array is fully evaluated.
  deepSeqMArr      :: MArr r e -> a -> a
 
+ -- | Ensure the array is still live at this point.
+ --   Needed when the mutable array is a ForeignPtr with a finalizer.
+ touchMArr        :: MArr r e -> IO ()
+
 
 -- | O(n). Construct a manifest array from a list.
 fromList
diff --git a/Data/Array/Repa/Operators/Mapping.hs b/Data/Array/Repa/Operators/Mapping.hs
--- a/Data/Array/Repa/Operators/Mapping.hs
+++ b/Data/Array/Repa/Operators/Mapping.hs
@@ -179,9 +179,9 @@
 
 
 -- Undefined --------------------------
-instance Combine X a D b where
- cmap           = map
- czipWith       = zipWith
+instance Combine X a X b where
+ cmap     _   (AUndefined sh) = AUndefined sh
+ czipWith _ _ (AUndefined sh) = AUndefined sh
 
 
  
diff --git a/Data/Array/Repa/Repr/Cursored.hs b/Data/Array/Repa/Repr/Cursored.hs
--- a/Data/Array/Repa/Repr/Cursored.hs
+++ b/Data/Array/Repa/Repr/Cursored.hs
@@ -68,7 +68,8 @@
         fillCursoredBlock2P 
                 (unsafeWriteMArr marr) 
                 makec shiftc loadc
-                w 0# 0# (w -# 1#) (h -# 1#) 
+                w 0# 0# w h
+        touchMArr marr
         traceEventIO "Repa.fillP[Cursored]: end"
  {-# INLINE fillP #-}
         
@@ -77,7 +78,8 @@
         fillCursoredBlock2S 
                 (unsafeWriteMArr marr) 
                 makec shiftc loadc
-                w 0# 0# (w -# 1#) (h -# 1#) 
+                w 0# 0# w h
+        touchMArr marr
         traceEventIO "Repa.fillS[Cursored]: end"
  {-# INLINE fillS #-}
         
@@ -85,23 +87,25 @@
 -- | Compute a range of elements in a rank-2 array.
 instance (Fillable r2 e, Elt e) => FillRange C r2 DIM2 e where
  fillRangeP  (ACursored (Z :. _h :. (I# w)) makec shiftc loadc) marr
-             (Z :. (I# y0) :. (I# x0)) (Z :. (I# y1) :. (I# x1))
+             (Z :. (I# y0) :. (I# x0)) (Z :. (I# h0) :. (I# w0))
   = do  traceEventIO "Repa.fillRangeP[Cursored]: start"
         fillCursoredBlock2P 
                 (unsafeWriteMArr marr) 
                 makec shiftc loadc
-                w x0 y0 x1 y1
+                w x0 y0 w0 h0
+        touchMArr marr
         traceEventIO "Repa.fillRangeP[Cursored]: end"
  {-# INLINE fillRangeP #-}
         
  fillRangeS  (ACursored (Z :. _h :. (I# w)) makec shiftc loadc) marr
              (Z :. (I# y0) :. (I# x0)) 
-             (Z :. (I# y1) :. (I# x1))
+             (Z :. (I# h0) :. (I# w0))
   = do  traceEventIO "Repa.fillRangeS[Cursored]: start"
         fillCursoredBlock2S
                 (unsafeWriteMArr marr) 
                 makec shiftc loadc
-                w x0 y0 x1 y1
+                w x0 y0 w0 h0
+        touchMArr marr
         traceEventIO "Repa.fillRangeS[Cursored]: end"
  {-# INLINE fillRangeS #-}
         
diff --git a/Data/Array/Repa/Repr/Delayed.hs b/Data/Array/Repa/Repr/Delayed.hs
--- a/Data/Array/Repa/Repr/Delayed.hs
+++ b/Data/Array/Repa/Repr/Delayed.hs
@@ -50,6 +50,7 @@
   = marr `deepSeqMArr` 
     do  traceEventIO "Repa.fillP[Delayed]: start"
         fillChunkedP (size sh) (unsafeWriteMArr marr) (getElem . fromIndex sh) 
+        touchMArr marr
         traceEventIO "Repa.fillP[Delayed]: end"
  {-# INLINE [4] fillP #-}
 
@@ -57,29 +58,33 @@
   = marr `deepSeqMArr` 
     do  traceEventIO "Repa.fillS[Delayed]: start"
         fillChunkedS (size sh) (unsafeWriteMArr marr) (getElem . fromIndex sh)
+        touchMArr marr
         traceEventIO "Repa.fillS[Delayed]: end"
+
  {-# INLINE [4] fillS #-}
 
 
 -- | Compute a range of elements in a rank-2 array.
 instance (Fillable r2 e, Elt e) => FillRange D r2 DIM2 e where
  fillRangeP  (ADelayed (Z :. _h :. (I# w)) getElem) marr
-             (Z :. (I# y0) :. (I# x0)) (Z :. (I# y1) :. (I# x1))
+             (Z :. (I# y0) :. (I# x0)) (Z :. (I# h0) :. (I# w0))
   = marr `deepSeqMArr` 
     do  traceEventIO "Repa.fillRangeP[Delayed]: start"
         fillBlock2P (unsafeWriteMArr marr) 
                         getElem
-                        w x0 y0 x1 y1
+                        w x0 y0 w0 h0
+        touchMArr marr
         traceEventIO "Repa.fillRangeP[Delayed]: end"
  {-# INLINE [1] fillRangeP #-}
 
  fillRangeS  (ADelayed (Z :. _h :. (I# w)) getElem) marr
-             (Z :. (I# y0) :. (I# x0)) (Z :. (I# y1) :. (I# x1))
+             (Z :. (I# y0) :. (I# x0)) (Z :. (I# h0) :. (I# w0))
   = marr `deepSeqMArr`
     do  traceEventIO "Repa.fillRangeS[Delayed]: start"
         fillBlock2S (unsafeWriteMArr marr) 
                 getElem
-                w x0 y0 x1 y1
+                w x0 y0 w0 h0
+        touchMArr marr
         traceEventIO "Repa.fillRangeS[Delayed]: end"
  {-# INLINE [1] fillRangeS #-}
 
diff --git a/Data/Array/Repa/Repr/ForeignPtr.hs b/Data/Array/Repa/Repr/ForeignPtr.hs
--- a/Data/Array/Repa/Repr/ForeignPtr.hs
+++ b/Data/Array/Repa/Repr/ForeignPtr.hs
@@ -62,6 +62,8 @@
         return           $ FPArr n fptr
  {-# INLINE newMArr #-}
 
+ -- CAREFUL: Unwrapping the foreignPtr like this means we need to be careful
+ -- to touch it after the last use, otherwise the finaliser might run too early.
  unsafeWriteMArr (FPArr _ fptr) !ix !x
   = pokeElemOff (Unsafe.unsafeForeignPtrToPtr fptr) ix x
  {-# INLINE unsafeWriteMArr #-}
@@ -70,9 +72,13 @@
   =     return  $ AForeignPtr sh len fptr
  {-# INLINE unsafeFreezeMArr #-}
 
- deepSeqMArr !(FPArr _ ptr) x
-  = Unsafe.unsafeForeignPtrToPtr ptr `seq` x
+ deepSeqMArr !(FPArr _ fptr) x
+  = Unsafe.unsafeForeignPtrToPtr fptr `seq` x
  {-# INLINE deepSeqMArr #-}
+
+ touchMArr (FPArr _ fptr)
+  = touchForeignPtr fptr
+ {-# INLINE touchMArr #-}
 
 
 -- Conversions ----------------------------------------------------------------
diff --git a/Data/Array/Repa/Repr/Partitioned.hs b/Data/Array/Repa/Repr/Partitioned.hs
--- a/Data/Array/Repa/Repr/Partitioned.hs
+++ b/Data/Array/Repa/Repr/Partitioned.hs
@@ -9,7 +9,6 @@
 import Data.Array.Repa.Shape
 import Data.Array.Repa.Eval
 import Data.Array.Repa.Repr.Delayed
-import Data.Array.Repa.Repr.Undefined
 
 
 -- | Partitioned arrays.
@@ -62,8 +61,8 @@
 
 
 deepSeqRange :: Shape sh => Range sh -> b -> b
-deepSeqRange (Range low high f) y
-        = low `deepSeq` high `deepSeq` f `seq` y
+deepSeqRange (Range ix sz f) y
+        = ix `deepSeq` sz `deepSeq` f `seq` y
 {-# INLINE deepSeqRange #-}
 
 
@@ -71,12 +70,12 @@
 instance ( FillRange r1 r3 sh e, Fill r2 r3 sh e
          , Fillable r3 e)
         => Fill (P r1 r2) r3 sh e where
- fillP (APart _ (Range ix10 ix11 _) arr1 arr2) marr
-  = do  fillRangeP arr1 marr ix10 ix11
+ fillP (APart _ (Range ix sz _) arr1 arr2) marr
+  = do  fillRangeP arr1 marr ix sz
         fillP arr2 marr
  {-# INLINE fillP #-}
 
- fillS (APart _ (Range ix10 ix11 _) arr1 arr2) marr
-  = do  fillRangeS arr1 marr ix10 ix11
+ fillS (APart _ (Range ix sz _) arr1 arr2) marr
+  = do  fillRangeS arr1 marr ix sz
         fillS arr2 marr
  {-# INLINE fillS #-}
diff --git a/Data/Array/Repa/Repr/Unboxed.hs b/Data/Array/Repa/Repr/Unboxed.hs
--- a/Data/Array/Repa/Repr/Unboxed.hs
+++ b/Data/Array/Repa/Repr/Unboxed.hs
@@ -75,6 +75,10 @@
   = vec `seq` x
  {-# INLINE deepSeqMArr #-}
 
+ touchMArr _ 
+  = return ()
+ {-# INLINE touchMArr #-}
+
 
 -- Conversions ----------------------------------------------------------------
 -- | Sequential computation of array elements..
diff --git a/Data/Array/Repa/Repr/Undefined.hs b/Data/Array/Repa/Repr/Undefined.hs
--- a/Data/Array/Repa/Repr/Undefined.hs
+++ b/Data/Array/Repa/Repr/Undefined.hs
@@ -27,10 +27,12 @@
         = sh
  {-# INLINE extent #-}
 
- index (AUndefined _) _        = error "Repa: array element is undefined."
+ index (AUndefined _) _ 
+        = error $ "Repa: array element is undefined."
  {-# INLINE index #-}
         
- linearIndex (AUndefined _) _  = error "Repa: array element is undefined."
+ linearIndex (AUndefined _) ix
+        = error $ "Repa: array element at " ++ show ix ++ " is undefined."
  {-# INLINE linearIndex #-}
  
 
diff --git a/Data/Array/Repa/Repr/Vector.hs b/Data/Array/Repa/Repr/Vector.hs
--- a/Data/Array/Repa/Repr/Vector.hs
+++ b/Data/Array/Repa/Repr/Vector.hs
@@ -68,6 +68,11 @@
   = x
  {-# INLINE deepSeqMArr #-}
 
+ touchMArr _ 
+  = return ()
+ {-# INLINE touchMArr #-}
+
+
 -- Conversions ----------------------------------------------------------------
 -- | Sequential computation of array elements.
 --
diff --git a/Data/Array/Repa/Specialised/Dim2.hs b/Data/Array/Repa/Specialised/Dim2.hs
--- a/Data/Array/Repa/Specialised/Dim2.hs
+++ b/Data/Array/Repa/Specialised/Dim2.hs
@@ -66,6 +66,7 @@
 	  | otherwise	= sh :. y	   :. x
 
 
+
 -- | Make a 2D partitioned array from two others, one to produce the elements
 --   in the internal region, and one to produce elements in the border region.
 --   The two arrays must have the same extent.
@@ -80,18 +81,18 @@
 	-> Array (P r1 (P r2 (P r2 (P r2 (P r2 X))))) DIM2 a
 
 {-# INLINE makeBordered2 #-}
-makeBordered2 sh@(_ :. aHeight :. aWidth) borderWidth arrInternal arrBorder
+makeBordered2 sh@(_ :. aHeight :. aWidth) bWidth arrInternal arrBorder
  = checkDims `seq` 
    let
 	-- minimum and maximum indicies of values in the inner part of the image.
-	!xMin		= borderWidth
-	!yMin		= borderWidth
-	!xMax		= aWidth  - borderWidth  - 1
-	!yMax		= aHeight - borderWidth - 1
+	!inX		= bWidth
+	!inY		= bWidth
+        !inW            = aWidth  - 2 * bWidth 
+        !inH            = aHeight - 2 * bWidth
 
 	inInternal (Z :. y :. x)
-		=  x >= xMin && x <= xMax
-		&& y >= yMin && y <= yMax
+		=  x >= inX && x < (inX + inW)
+		&& y >= inY && y < (inY + inH)
         {-# INLINE inInternal #-}
 
 	inBorder 	= not . inInternal
@@ -99,13 +100,13 @@
 
    in	
     --  internal region
-        APart sh (Range (Z :. yMin :. xMin)         (Z :. yMax :. xMax )    inInternal) arrInternal
+        APart sh (Range (Z :. inY     :. inX)       (Z :. inH :. inW )    inInternal) arrInternal
 
     --  border regions
-    $   APart sh (Range (Z :. 0        :. 0)        (Z :. yMin -1        :. aWidth - 1) inBorder)   arrBorder
-    $   APart sh (Range (Z :. yMax + 1 :. 0)        (Z :. aHeight - 1    :. aWidth - 1) inBorder)   arrBorder
-    $   APart sh (Range (Z :. yMin     :. 0)        (Z :. yMax           :. xMin - 1)   inBorder)   arrBorder
-    $   APart sh (Range (Z :. yMin     :. xMax + 1) (Z :. yMax           :. aWidth - 1) inBorder)   arrBorder
+    $   APart sh (Range (Z :. 0         :. 0)         (Z :. bWidth :. aWidth) inBorder) arrBorder
+    $   APart sh (Range (Z :. inY + inH :. 0)         (Z :. bWidth :. aWidth) inBorder) arrBorder
+    $   APart sh (Range (Z :. inY       :. 0)         (Z :. inH    :. bWidth) inBorder) arrBorder
+    $   APart sh (Range (Z :. inY       :. inX + inW) (Z :. inH    :. bWidth) inBorder) arrBorder
     $   AUndefined sh
 
  where
@@ -115,3 +116,4 @@
                 else error "makeBordered2: internal and border arrays have different extents"
         {-# NOINLINE checkDims #-}
         --  NOINLINE because we don't want the branch in the core code.
+
diff --git a/Data/Array/Repa/Stencil/Dim2.hs b/Data/Array/Repa/Stencil/Dim2.hs
--- a/Data/Array/Repa/Stencil/Dim2.hs
+++ b/Data/Array/Repa/Stencil/Dim2.hs
@@ -25,6 +25,7 @@
 import Data.Array.Repa.Repr.Undefined
 import Data.Array.Repa.Stencil.Base
 import Data.Array.Repa.Stencil.Template
+import Data.Array.Repa.Stencil.Partition
 import GHC.Exts
 
 -- | A index into the flat array.
@@ -67,19 +68,24 @@
 	sHeight2	= sHeight `div` 2
 	sWidth2		= sWidth  `div` 2
 
-	-- minimum and maximum indicies of values in the inner part of the image.
-	!xMin		= sWidth2
-	!yMin		= sHeight2
-	!xMax		= aWidth  - sWidth2  - 1
-	!yMax		= aHeight - sHeight2 - 1
+        -- Partition the array into the internal and border regions.
+        ![ Region    inX    inY    inW    inH
+         , Region  westX  westY  westW  westH
+         , Region  eastX  eastY  eastW  eastH
+         , Region northX northY northW northH 
+         , Region southX southY southW southH ] 
+           = partitionForStencil 
+                (Size   aWidth   aHeight) 
+                (Size   sWidth   sHeight)
+                (Offset sWidth2  sHeight2)
 
 	{-# INLINE inInternal #-}
 	inInternal (Z :. y :. x)
-		=  x >= xMin && x <= xMax
-		&& y >= yMin && y <= yMax
+		=  x >= inX && x < (inX + inW)
+		&& y >= inY && y < (inY + inH)
 
 	{-# INLINE inBorder #-}
-	inBorder 	= not . inInternal
+	inBorder       = not . inInternal
 
 	-- Cursor functions ----------------
 	{-# INLINE makec #-}
@@ -92,32 +98,31 @@
 	 $ case ix of
 		Z :. y :. x	-> off + y * aWidth + x
 
-	{-# INLINE getInner' #-}
-	getInner' cur
-	 = unsafeAppStencilCursor2 shiftc stencil arr cur
-
-	{-# INLINE getBorder' #-}
-	getBorder' ix
-	 = case boundary of
-		BoundConst c	-> c
-		BoundClamp 	-> unsafeAppStencilCursor2_clamp addDim stencil
-					arr ix
-
         {-# INLINE arrInternal #-}
         arrInternal     = makeCursored (extent arr) makec shiftc getInner' 
-        
+
+        {-# INLINE getInner' #-}
+        getInner' cur   = unsafeAppStencilCursor2 shiftc stencil arr cur
+
         {-# INLINE arrBorder #-}
         arrBorder       = ASmall (fromFunction (extent arr) getBorder')
 
+        {-# INLINE getBorder' #-}
+        getBorder' ix
+         = case boundary of
+                BoundConst c    -> c
+                BoundClamp      -> unsafeAppStencilCursor2_clamp addDim stencil
+                                        arr ix
+
    in
     --  internal region
-        APart sh (Range (Z :. yMin :. xMin)         (Z :. yMax :. xMax )    inInternal) arrInternal
+        APart sh (Range (Z :.    inY :.    inX) (Z :.    inH :.    inW) inInternal) arrInternal
 
     --  border regions
-    $   APart sh (Range (Z :. 0        :. 0)        (Z :. yMin -1        :. aWidth - 1) inBorder)   arrBorder
-    $   APart sh (Range (Z :. yMax + 1 :. 0)        (Z :. aHeight - 1    :. aWidth - 1) inBorder)   arrBorder
-    $   APart sh (Range (Z :. yMin     :. 0)        (Z :. yMax           :. xMin - 1)   inBorder)   arrBorder
-    $   APart sh (Range (Z :. yMin     :. xMax + 1) (Z :. yMax           :. aWidth - 1) inBorder)   arrBorder
+    $   APart sh (Range (Z :.  westY :.  westX) (Z :.  westH :.  westW) inBorder)   arrBorder
+    $   APart sh (Range (Z :.  eastY :.  eastX) (Z :.  eastH :.  eastW) inBorder)   arrBorder
+    $   APart sh (Range (Z :. northY :. northX) (Z :. northH :. northW) inBorder)   arrBorder
+    $   APart sh (Range (Z :. southY :. southX) (Z :. southH :. southW) inBorder)   arrBorder
     $   AUndefined sh
 
 
diff --git a/Data/Array/Repa/Stencil/Partition.hs b/Data/Array/Repa/Stencil/Partition.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Repa/Stencil/Partition.hs
@@ -0,0 +1,74 @@
+
+module Data.Array.Repa.Stencil.Partition
+        ( Offset (..)
+        , Size   (..)
+        , Region (..)
+        , partitionForStencil)
+where
+
+-- | An offset in the 2d plane.
+data Offset
+        = Offset !Int !Int
+
+-- | Size of a region in the 2d plane.
+data Size
+        = Size   !Int !Int
+
+-- | A region in the 2d plane.
+data Region 
+        = Region
+        { regionX       :: !Int
+        , regionY       :: !Int
+        , regionWidth   :: !Int
+        , regionHeight  :: !Int }
+        deriving Show
+
+
+-- | Create a new region of the given size.
+regionOfSize :: Size -> Region
+regionOfSize (Size w h)
+        = Region 0 0 w h
+{-# INLINE regionOfSize #-}
+
+-- | Offset a region.
+offsetRegion :: Offset -> Region -> Region
+offsetRegion (Offset x y) (Region x0 y0 w h)
+        = Region (x0 + x) (y0 + y) w h
+{-# INLINE offsetRegion #-}
+
+-- | Partition a region into inner and border regions for the given stencil.
+partitionForStencil
+        :: Size         -- ^ Size of array
+        -> Size         -- ^ Size of stencil
+        -> Offset       -- ^ Focus of stencil
+        -> [Region]
+
+partitionForStencil
+          (Size   arrW arrH)
+          (Size   krnW krnH)
+          (Offset focX focY)
+ = let  
+        gapNorth        = focY
+        gapSouth        = krnH - focY - 1
+        gapWest         = focX
+        gapEast         = krnW - focX - 1
+
+        innerW          = arrW - gapWest  - gapEast
+        innerH          = arrH - gapNorth - gapSouth
+
+        regionInner     = offsetRegion (Offset  gapWest           gapNorth)
+                        $ regionOfSize (Size    innerW            innerH)
+
+        regionNorth     = regionOfSize (Size    arrW              gapNorth)
+
+        regionSouth     = offsetRegion (Offset  0                 (gapNorth + innerH))
+                        $ regionOfSize (Size    arrW              gapSouth)
+
+        regionWest      = offsetRegion (Offset  0                 gapNorth)
+                        $ regionOfSize (Size    gapWest           innerH)
+
+        regionEast      = offsetRegion (Offset (gapWest + innerW) gapNorth)
+                        $ regionOfSize (Size    gapEast           innerH)
+
+  in    [regionInner, regionNorth, regionSouth, regionWest, regionEast]
+{-# INLINE partitionForStencil #-}
diff --git a/repa.cabal b/repa.cabal
--- a/repa.cabal
+++ b/repa.cabal
@@ -1,5 +1,5 @@
 Name:                repa
-Version:             3.1.1.1
+Version:             3.1.2.1
 License:             BSD3
 License-file:        LICENSE
 Author:              The DPH Team
@@ -68,6 +68,7 @@
         Data.Array.Repa.Repr.Vector
         Data.Array.Repa.Specialised.Dim2
         Data.Array.Repa.Stencil.Dim2
+        Data.Array.Repa.Stencil.Partition
         Data.Array.Repa.Eval
         Data.Array.Repa.Index
         Data.Array.Repa.Shape
