diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt
index 7e2c99393..32609ee3a 100644
--- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt
+++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt
@@ -119,7 +119,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
                     origAssign.operator.dropLast(1)
                 }
             }
-            value = PtBinaryExpression(operator, origAssign.value.type, origAssign.value.position)
+            value = PtBinaryExpression(operator, origAssign.target.type, origAssign.value.position)
             val left: PtExpression = origAssign.target.children.single() as PtExpression
             value.add(left)
             value.add(origAssign.value)
@@ -997,10 +997,14 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
 
     private fun operatorShiftRightInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? {
         if(array!=null) {
-            TODO(">> in array")
+            if(array.splitWords)
+                return null // TODO("optimized >> in split word array")
+            else {
+                return null // TODO("optimized >> in array")
+            }
         }
         if(constAddress==null && memory!=null)
-            return null  // TODO("optimized memory in-place >>"")
+            return null  //  TODO("optimized memory in-place >>"")
 
         val result = mutableListOf<IRCodeChunkBase>()
         if(codeGen.isOne(operand)) {
@@ -1025,7 +1029,11 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
 
     private fun operatorShiftLeftInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
         if(array!=null) {
-            TODO("<< in array")
+            if(array.splitWords)
+                return null // TODO("optimized << in split word array")
+            else {
+                return null // TODO("optimized << in array")
+            }
         }
         if(constAddress==null && memory!=null)
             return null  // TODO("optimized memory in-place <<"")
diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt
index 454684d3c..82eff60cc 100644
--- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt
+++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt
@@ -549,10 +549,24 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
         val index = arr?.index?.asConstInteger()
         if(arr!=null && index!=null) {
             val variable = arr.variable.name
-            if(arr.splitWords)
-                TODO("IR rol/ror on split words array")
-            val offset = codeGen.program.memsizer.memorySize(arr.type, index)
-            addInstr(result, IRInstruction(opcodeMemAndReg.first, vmDt, labelSymbol = variable, symbolOffset = offset), null)
+            if(arr.splitWords) {
+                result += IRCodeChunk(null, null).also {
+                    when(opcodeMemAndReg.first) {
+                        Opcode.ROXRM, Opcode.RORM -> {
+                            it += IRInstruction(opcodeMemAndReg.first, IRDataType.BYTE, labelSymbol = "${variable}_msb", symbolOffset = index)
+                            it += IRInstruction(opcodeMemAndReg.first, IRDataType.BYTE, labelSymbol = "${variable}_lsb", symbolOffset = index)
+                        }
+                        Opcode.ROXLM, Opcode.ROLM -> {
+                            it += IRInstruction(opcodeMemAndReg.first, IRDataType.BYTE, labelSymbol = "${variable}_lsb", symbolOffset = index)
+                            it += IRInstruction(opcodeMemAndReg.first, IRDataType.BYTE, labelSymbol = "${variable}_msb", symbolOffset = index)
+                        }
+                        else -> throw AssemblyError("wrong rol/ror opcode")
+                    }
+                }
+            } else {
+                val offset = codeGen.program.memsizer.memorySize(arr.type, index)
+                addInstr(result, IRInstruction(opcodeMemAndReg.first, vmDt, labelSymbol = variable, symbolOffset = offset), null)
+            }
             return ExpressionCodeResult(result, vmDt, -1, -1)
         }
 
diff --git a/docs/source/todo.rst b/docs/source/todo.rst
index 5c16d7e1a..7c9d1b6f3 100644
--- a/docs/source/todo.rst
+++ b/docs/source/todo.rst
@@ -1,6 +1,9 @@
 TODO
 ====
 
+- IR: implement "optimized << in array" / "optimized >> in array"
+- IR: implement "optimized << in split word array" / "optimized >> in split word array"
+
 - add paypal donation button as well?
 - announce prog8 on the 6502.org site?
 
@@ -47,8 +50,6 @@ IR/VM
 -----
 - getting it in shape for code generation...: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)
 - add BZ and BNZ instructions?  To replace CMPI #0 + Branch?
-- fix TODO("IR rol/ror on split words array")
-- fix "<< in array" / ">> in array"
 - implement fast code paths for TODO("inplace split....
 - sometimes source lines end up missing in the output p8ir, for example the first assignment is gone in:
      sub start() {
diff --git a/examples/test.p8 b/examples/test.p8
index 7751e737c..6bb2ced35 100644
--- a/examples/test.p8
+++ b/examples/test.p8
@@ -4,7 +4,72 @@
 
 main {
     sub start() {
-        txt.print_uw(cx16.r0)
+        uword wv = %01000010_01000010
+
+        ; expected:  $8484  $4242
+        sys.set_carry()
+        rol(wv)
+        txt.print_uwhex(wv, true)
+        sys.set_carry()
+        ror(wv)
+        txt.print_uwhex(wv, true)
+        txt.nl()
+
+        wv = %01000010_01000010
+        sys.set_carry()
+        rol2(wv)
+        txt.print_uwhex(wv, true)
+        sys.set_carry()
+        ror2(wv)
+        txt.print_uwhex(wv, true)
+        txt.nl()
+
+        uword[] @nosplit arr = [ %01000010_01000010 , %01000010_01000010, %01000010_01000010 ]
+        uword[] @split arrsplit = [ %01000010_01000010 , %01000010_01000010, %01000010_01000010 ]
+
+        sys.set_carry()
+        rol(arr[2])
+        txt.print_uwhex(arr[2], true)
+        sys.set_carry()
+        ror(arr[2])
+        txt.print_uwhex(arr[2], true)
+        txt.nl()
+        sys.set_carry()
+        rol2(arr[1])
+        txt.print_uwhex(arr[1], true)
+        sys.set_carry()
+        ror2(arr[1])
+        txt.print_uwhex(arr[1], true)
+        txt.nl()
+
+        sys.set_carry()
+        rol(arrsplit[2])
+        txt.print_uwhex(arrsplit[2], true)
+        sys.set_carry()
+        ror(arrsplit[2])
+        txt.print_uwhex(arrsplit[2], true)
+        txt.nl()
+        sys.set_carry()
+        rol2(arrsplit[1])
+        txt.print_uwhex(arrsplit[1], true)
+        sys.set_carry()
+        ror2(arrsplit[1])
+        txt.print_uwhex(arrsplit[1], true)
+        txt.nl()
+
+
+        ; expected $2468  $1234
+        arr[2] = $1234
+        arr[2] <<= 1
+        txt.print_uwhex(arr[2], true)
+        arr[2] >>= 1
+        txt.print_uwhex(arr[2], true)
+        txt.nl()
+        arrsplit[2] = $1234
+        arrsplit[2] <<= 1
+        txt.print_uwhex(arrsplit[2], true)
+        arrsplit[2] >>= 1
+        txt.print_uwhex(arrsplit[2], true)
         txt.nl()
     }
 }