)
 
 type Config struct {
-       arch       string                     // "amd64", etc.
-       IntSize    int64                      // 4 or 8
-       PtrSize    int64                      // 4 or 8
-       lowerBlock func(*Block) bool          // lowering function
-       lowerValue func(*Value, *Config) bool // lowering function
-       fe         Frontend                   // callbacks into compiler frontend
-       HTML       *HTMLWriter                // html writer, for debugging
-       ctxt       *obj.Link                  // Generic arch information
-       optimize   bool                       // Do optimization
-       curFunc    *Func
+       arch         string                     // "amd64", etc.
+       IntSize      int64                      // 4 or 8
+       PtrSize      int64                      // 4 or 8
+       lowerBlock   func(*Block) bool          // lowering function
+       lowerValue   func(*Value, *Config) bool // lowering function
+       fe           Frontend                   // callbacks into compiler frontend
+       HTML         *HTMLWriter                // html writer, for debugging
+       ctxt         *obj.Link                  // Generic arch information
+       optimize     bool                       // Do optimization
+       noDuffDevice bool                       // Don't use Duff's device
+       curFunc      *Func
 
        // TODO: more stuff. Compiler flags of interest, ...
 
        c.ctxt = ctxt
        c.optimize = optimize
 
+       // Don't use Duff's device on Plan 9, because floating
+       // point operations are not allowed in note handler.
+       if obj.Getgoos() == "plan9" {
+               c.noDuffDevice = true
+       }
+
        // Assign IDs to preallocated values/blocks.
        for i := range c.values {
                c.values[i].ID = ID(i)
 
                (MOVOstore dst (MOVOload src mem) mem))
 
 // Medium copying uses a duff device.
-(Move [size] dst src mem) && size >= 32 && size <= 16*64 && size%16 == 0 ->
+(Move [size] dst src mem) && size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice ->
        (DUFFCOPY [14*(64-size/16)] dst src mem)
 // 14 and 64 are magic constants.  14 is the number of bytes to encode:
 //     MOVUPS  (SI), X0
 // and 64 is the number of such blocks. See src/runtime/duff_amd64.s:duffcopy.
 
 // Large copying uses REP MOVSQ.
-(Move [size] dst src mem) && size > 16*64 && size%8 == 0 ->
+(Move [size] dst src mem) && (size > 16*64 || config.noDuffDevice) && size%8 == 0 ->
        (REPMOVSQ dst src (MOVQconst [size/8]) mem)
 
 (Not x) -> (XORBconst [1] x)
                                (MOVQstoreconst [0] destptr mem))))
 
 // Medium zeroing uses a duff device.
-(Zero [size] destptr mem) && size <= 1024 && size%8 == 0 && size%16 != 0 ->
+(Zero [size] destptr mem) && size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice ->
        (Zero [size-8] (ADDQconst [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
-(Zero [size] destptr mem) && size <= 1024 && size%16 == 0 ->
+(Zero [size] destptr mem) && size <= 1024 && size%16 == 0 && !config.noDuffDevice ->
        (DUFFZERO [duffStart(size)] (ADDQconst [duffAdj(size)] destptr) (MOVOconst [0]) mem)
 
 // Large zeroing uses REP STOSQ.
-(Zero [size] destptr mem) && size > 1024 && size%8 == 0 ->
+(Zero [size] destptr mem) && (size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0 ->
        (REPSTOSQ destptr (MOVQconst [size/8]) (MOVQconst [0]) mem)
 
 // Absorb InvertFlags into branches.
 
                return true
        }
        // match: (Move [size] dst src mem)
-       // cond: size >= 32 && size <= 16*64 && size%16 == 0
+       // cond: size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice
        // result: (DUFFCOPY [14*(64-size/16)] dst src mem)
        for {
                size := v.AuxInt
                dst := v.Args[0]
                src := v.Args[1]
                mem := v.Args[2]
-               if !(size >= 32 && size <= 16*64 && size%16 == 0) {
+               if !(size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice) {
                        break
                }
                v.reset(OpAMD64DUFFCOPY)
                return true
        }
        // match: (Move [size] dst src mem)
-       // cond: size > 16*64 && size%8 == 0
+       // cond: (size > 16*64 || config.noDuffDevice) && size%8 == 0
        // result: (REPMOVSQ dst src (MOVQconst [size/8]) mem)
        for {
                size := v.AuxInt
                dst := v.Args[0]
                src := v.Args[1]
                mem := v.Args[2]
-               if !(size > 16*64 && size%8 == 0) {
+               if !((size > 16*64 || config.noDuffDevice) && size%8 == 0) {
                        break
                }
                v.reset(OpAMD64REPMOVSQ)
                return true
        }
        // match: (Zero [size] destptr mem)
-       // cond: size <= 1024 && size%8 == 0 && size%16 != 0
+       // cond: size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice
        // result: (Zero [size-8] (ADDQconst [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
        for {
                size := v.AuxInt
                destptr := v.Args[0]
                mem := v.Args[1]
-               if !(size <= 1024 && size%8 == 0 && size%16 != 0) {
+               if !(size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice) {
                        break
                }
                v.reset(OpZero)
                return true
        }
        // match: (Zero [size] destptr mem)
-       // cond: size <= 1024 && size%16 == 0
+       // cond: size <= 1024 && size%16 == 0 && !config.noDuffDevice
        // result: (DUFFZERO [duffStart(size)] (ADDQconst [duffAdj(size)] destptr) (MOVOconst [0]) mem)
        for {
                size := v.AuxInt
                destptr := v.Args[0]
                mem := v.Args[1]
-               if !(size <= 1024 && size%16 == 0) {
+               if !(size <= 1024 && size%16 == 0 && !config.noDuffDevice) {
                        break
                }
                v.reset(OpAMD64DUFFZERO)
                return true
        }
        // match: (Zero [size] destptr mem)
-       // cond: size > 1024 && size%8 == 0
+       // cond: (size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0
        // result: (REPSTOSQ destptr (MOVQconst [size/8]) (MOVQconst [0]) mem)
        for {
                size := v.AuxInt
                destptr := v.Args[0]
                mem := v.Args[1]
-               if !(size > 1024 && size%8 == 0) {
+               if !((size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0) {
                        break
                }
                v.reset(OpAMD64REPSTOSQ)