[dev.ssa] cmd/compile/internal/ssa: use width and sign specific opcodes

Bake the bit width and signedness into opcodes.
Pro: Rewrite rules become easier.  Less chance for confusion.
Con: Lots more opcodes.

Let me know what you think.  I'm leaning towards this, but I could be
convinced otherwise if people think this is too ugly.

Update #11467

Change-Id: Icf1b894268cdf73515877bb123839800d97b9df9
Reviewed-on: https://go-review.googlesource.com/12362
Reviewed-by: Alan Donovan <adonovan@google.com>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index d4e4298..889b9d8 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -446,19 +446,122 @@
 	}
 }
 
-var binOpToSSA = [...]ssa.Op{
-	// Comparisons
-	OEQ: ssa.OpEq,
-	ONE: ssa.OpNeq,
-	OLT: ssa.OpLess,
-	OLE: ssa.OpLeq,
-	OGT: ssa.OpGreater,
-	OGE: ssa.OpGeq,
-	// Arithmetic
-	OADD: ssa.OpAdd,
-	OSUB: ssa.OpSub,
-	OLSH: ssa.OpLsh,
-	ORSH: ssa.OpRsh,
+type opAndType struct {
+	op    uint8
+	etype uint8
+}
+
+var opToSSA = map[opAndType]ssa.Op{
+	opAndType{OADD, TINT8}:   ssa.OpAdd8,
+	opAndType{OADD, TUINT8}:  ssa.OpAdd8U,
+	opAndType{OADD, TINT16}:  ssa.OpAdd16,
+	opAndType{OADD, TUINT16}: ssa.OpAdd16U,
+	opAndType{OADD, TINT32}:  ssa.OpAdd32,
+	opAndType{OADD, TUINT32}: ssa.OpAdd32U,
+	opAndType{OADD, TINT64}:  ssa.OpAdd64,
+	opAndType{OADD, TUINT64}: ssa.OpAdd64U,
+
+	opAndType{OSUB, TINT8}:   ssa.OpSub8,
+	opAndType{OSUB, TUINT8}:  ssa.OpSub8U,
+	opAndType{OSUB, TINT16}:  ssa.OpSub16,
+	opAndType{OSUB, TUINT16}: ssa.OpSub16U,
+	opAndType{OSUB, TINT32}:  ssa.OpSub32,
+	opAndType{OSUB, TUINT32}: ssa.OpSub32U,
+	opAndType{OSUB, TINT64}:  ssa.OpSub64,
+	opAndType{OSUB, TUINT64}: ssa.OpSub64U,
+
+	opAndType{OLSH, TINT8}:   ssa.OpLsh8,
+	opAndType{OLSH, TUINT8}:  ssa.OpLsh8,
+	opAndType{OLSH, TINT16}:  ssa.OpLsh16,
+	opAndType{OLSH, TUINT16}: ssa.OpLsh16,
+	opAndType{OLSH, TINT32}:  ssa.OpLsh32,
+	opAndType{OLSH, TUINT32}: ssa.OpLsh32,
+	opAndType{OLSH, TINT64}:  ssa.OpLsh64,
+	opAndType{OLSH, TUINT64}: ssa.OpLsh64,
+
+	opAndType{ORSH, TINT8}:   ssa.OpRsh8,
+	opAndType{ORSH, TUINT8}:  ssa.OpRsh8U,
+	opAndType{ORSH, TINT16}:  ssa.OpRsh16,
+	opAndType{ORSH, TUINT16}: ssa.OpRsh16U,
+	opAndType{ORSH, TINT32}:  ssa.OpRsh32,
+	opAndType{ORSH, TUINT32}: ssa.OpRsh32U,
+	opAndType{ORSH, TINT64}:  ssa.OpRsh64,
+	opAndType{ORSH, TUINT64}: ssa.OpRsh64U,
+
+	opAndType{OEQ, TINT8}:   ssa.OpEq8,
+	opAndType{OEQ, TUINT8}:  ssa.OpEq8,
+	opAndType{OEQ, TINT16}:  ssa.OpEq16,
+	opAndType{OEQ, TUINT16}: ssa.OpEq16,
+	opAndType{OEQ, TINT32}:  ssa.OpEq32,
+	opAndType{OEQ, TUINT32}: ssa.OpEq32,
+	opAndType{OEQ, TINT64}:  ssa.OpEq64,
+	opAndType{OEQ, TUINT64}: ssa.OpEq64,
+
+	opAndType{ONE, TINT8}:   ssa.OpNeq8,
+	opAndType{ONE, TUINT8}:  ssa.OpNeq8,
+	opAndType{ONE, TINT16}:  ssa.OpNeq16,
+	opAndType{ONE, TUINT16}: ssa.OpNeq16,
+	opAndType{ONE, TINT32}:  ssa.OpNeq32,
+	opAndType{ONE, TUINT32}: ssa.OpNeq32,
+	opAndType{ONE, TINT64}:  ssa.OpNeq64,
+	opAndType{ONE, TUINT64}: ssa.OpNeq64,
+
+	opAndType{OLT, TINT8}:   ssa.OpLess8,
+	opAndType{OLT, TUINT8}:  ssa.OpLess8U,
+	opAndType{OLT, TINT16}:  ssa.OpLess16,
+	opAndType{OLT, TUINT16}: ssa.OpLess16U,
+	opAndType{OLT, TINT32}:  ssa.OpLess32,
+	opAndType{OLT, TUINT32}: ssa.OpLess32U,
+	opAndType{OLT, TINT64}:  ssa.OpLess64,
+	opAndType{OLT, TUINT64}: ssa.OpLess64U,
+
+	opAndType{OGT, TINT8}:   ssa.OpGreater8,
+	opAndType{OGT, TUINT8}:  ssa.OpGreater8U,
+	opAndType{OGT, TINT16}:  ssa.OpGreater16,
+	opAndType{OGT, TUINT16}: ssa.OpGreater16U,
+	opAndType{OGT, TINT32}:  ssa.OpGreater32,
+	opAndType{OGT, TUINT32}: ssa.OpGreater32U,
+	opAndType{OGT, TINT64}:  ssa.OpGreater64,
+	opAndType{OGT, TUINT64}: ssa.OpGreater64U,
+
+	opAndType{OLE, TINT8}:   ssa.OpLeq8,
+	opAndType{OLE, TUINT8}:  ssa.OpLeq8U,
+	opAndType{OLE, TINT16}:  ssa.OpLeq16,
+	opAndType{OLE, TUINT16}: ssa.OpLeq16U,
+	opAndType{OLE, TINT32}:  ssa.OpLeq32,
+	opAndType{OLE, TUINT32}: ssa.OpLeq32U,
+	opAndType{OLE, TINT64}:  ssa.OpLeq64,
+	opAndType{OLE, TUINT64}: ssa.OpLeq64U,
+
+	opAndType{OGE, TINT8}:   ssa.OpGeq8,
+	opAndType{OGE, TUINT8}:  ssa.OpGeq8U,
+	opAndType{OGE, TINT16}:  ssa.OpGeq16,
+	opAndType{OGE, TUINT16}: ssa.OpGeq16U,
+	opAndType{OGE, TINT32}:  ssa.OpGeq32,
+	opAndType{OGE, TUINT32}: ssa.OpGeq32U,
+	opAndType{OGE, TINT64}:  ssa.OpGeq64,
+	opAndType{OGE, TUINT64}: ssa.OpGeq64U,
+}
+
+func (s *state) ssaOp(op uint8, t *Type) ssa.Op {
+	etype := t.Etype
+	switch etype {
+	case TINT:
+		etype = TINT32
+		if s.config.PtrSize == 8 {
+			etype = TINT64
+		}
+	case TUINT:
+		etype = TUINT32
+		if s.config.PtrSize == 8 {
+			etype = TUINT64
+		}
+	}
+	x, ok := opToSSA[opAndType{op, etype}]
+	if !ok {
+		s.Unimplementedf("unhandled binary op %s etype=%d", opnames[op], etype)
+	}
+	return x
 }
 
 // expr converts the expression n to ssa, adds it to s and returns the ssa result.
@@ -503,11 +606,11 @@
 	case OLT, OEQ, ONE, OLE, OGE, OGT:
 		a := s.expr(n.Left)
 		b := s.expr(n.Right)
-		return s.newValue2(binOpToSSA[n.Op], ssa.TypeBool, a, b)
+		return s.newValue2(s.ssaOp(n.Op, n.Left.Type), ssa.TypeBool, a, b)
 	case OADD, OSUB, OLSH, ORSH:
 		a := s.expr(n.Left)
 		b := s.expr(n.Right)
-		return s.newValue2(binOpToSSA[n.Op], a.Type, a, b)
+		return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
 	case OANDAND, OOROR:
 		// To implement OANDAND (and OOROR), we introduce a
 		// new temporary variable to hold the result. The
@@ -569,7 +672,7 @@
 	case ODOTPTR:
 		p := s.expr(n.Left)
 		s.nilCheck(p)
-		p = s.newValue2(ssa.OpAdd, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
+		p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
 		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
 
 	case OINDEX:
@@ -742,11 +845,11 @@
 		return p
 	case ODOT:
 		p := s.addr(n.Left)
-		return s.newValue2(ssa.OpAdd, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
+		return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
 	case ODOTPTR:
 		p := s.expr(n.Left)
 		s.nilCheck(p)
-		return s.newValue2(ssa.OpAdd, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
+		return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
 	default:
 		s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0))
 		return nil
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index c6c7bf3..c9e543b 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -6,7 +6,7 @@
 
 type Config struct {
 	arch       string // "amd64", etc.
-	ptrSize    int64  // 4 or 8
+	PtrSize    int64  // 4 or 8
 	Uintptr    Type   // pointer arithmetic type
 	Int        Type
 	lowerBlock func(*Block) bool          // lowering function
@@ -38,11 +38,11 @@
 	c := &Config{arch: arch, fe: fe}
 	switch arch {
 	case "amd64":
-		c.ptrSize = 8
+		c.PtrSize = 8
 		c.lowerBlock = rewriteBlockAMD64
 		c.lowerValue = rewriteValueAMD64
 	case "386":
-		c.ptrSize = 4
+		c.PtrSize = 4
 		c.lowerBlock = rewriteBlockAMD64
 		c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
 	default:
@@ -52,7 +52,7 @@
 	// cache the frequently-used types in the config
 	c.Uintptr = TypeUInt32
 	c.Int = TypeInt32
-	if c.ptrSize == 8 {
+	if c.PtrSize == 8 {
 		c.Uintptr = TypeUInt64
 		c.Int = TypeInt64
 	}
diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go
index a620e8f..edea8f7 100644
--- a/src/cmd/compile/internal/ssa/func_test.go
+++ b/src/cmd/compile/internal/ssa/func_test.go
@@ -267,7 +267,7 @@
 		Bloc("entry",
 			Valu("a", OpConst, TypeInt64, 14, nil),
 			Valu("b", OpConst, TypeInt64, 26, nil),
-			Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
+			Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
 			Valu("mem", OpArg, TypeMem, 0, ".mem"),
 			Goto("exit")),
 		Bloc("exit",
@@ -290,7 +290,7 @@
 				Bloc("entry",
 					Valu("a", OpConst, TypeInt64, 14, nil),
 					Valu("b", OpConst, TypeInt64, 26, nil),
-					Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
 					Valu("mem", OpArg, TypeMem, 0, ".mem"),
 					Goto("exit")),
 				Bloc("exit",
@@ -299,7 +299,7 @@
 				Bloc("entry",
 					Valu("a", OpConst, TypeInt64, 14, nil),
 					Valu("b", OpConst, TypeInt64, 26, nil),
-					Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
 					Valu("mem", OpArg, TypeMem, 0, ".mem"),
 					Goto("exit")),
 				Bloc("exit",
@@ -311,7 +311,7 @@
 				Bloc("entry",
 					Valu("a", OpConst, TypeInt64, 14, nil),
 					Valu("b", OpConst, TypeInt64, 26, nil),
-					Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
 					Valu("mem", OpArg, TypeMem, 0, ".mem"),
 					Goto("exit")),
 				Bloc("exit",
@@ -322,7 +322,7 @@
 				Bloc("entry",
 					Valu("a", OpConst, TypeInt64, 14, nil),
 					Valu("b", OpConst, TypeInt64, 26, nil),
-					Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
 					Valu("mem", OpArg, TypeMem, 0, ".mem"),
 					Goto("exit"))),
 		},
@@ -397,14 +397,14 @@
 					Valu("mem", OpArg, TypeMem, 0, ".mem"),
 					Valu("a", OpConst, TypeInt64, 14, nil),
 					Valu("b", OpConst, TypeInt64, 26, nil),
-					Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
 					Exit("mem"))),
 			Fun(c, "entry",
 				Bloc("entry",
 					Valu("mem", OpArg, TypeMem, 0, ".mem"),
 					Valu("a", OpConst, TypeInt64, 0, nil),
 					Valu("b", OpConst, TypeInt64, 14, nil),
-					Valu("sum", OpAdd, TypeInt64, 0, nil, "b", "a"),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"),
 					Exit("mem"))),
 		},
 	}
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index 3e25929..eba3710 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -13,14 +13,25 @@
 //    Unused portions are junk.
 
 // Lowering arithmetic
-(Add <t> x y) && (is64BitInt(t) || isPtr(t)) -> (ADDQ x y)
-(Add <t> x y) && is32BitInt(t) && !isSigned(t) -> (ADDL x y)
-(Add <t> x y) && is32BitInt(t) && isSigned(t) -> (MOVLQSX (ADDL <t> x y))
-(Add <t> x y) && is16BitInt(t) && !isSigned(t) -> (ADDW x y)
-(Add <t> x y) && is16BitInt(t) && isSigned(t) -> (MOVWQSX (ADDW <t> x y))
-(Add <t> x y) && is8BitInt(t) && !isSigned(t) -> (ADDB x y)
-(Add <t> x y) && is8BitInt(t) && isSigned(t) -> (MOVBQSX (ADDB <t> x y))
-(Sub <t> x y) && is64BitInt(t) -> (SUBQ x y)
+(Add64 x y) -> (ADDQ x y)
+(Add64U x y) -> (ADDQ x y)
+(AddPtr x y) -> (ADDQ x y)
+(Add32U x y) -> (ADDL x y)
+(Add32 x y) -> (MOVLQSX (ADDL <v.Type> x y))
+(Add16U x y) -> (ADDW x y)
+(Add16 x y) -> (MOVWQSX (ADDW <v.Type> x y))
+(Add8U x y) -> (ADDB x y)
+(Add8 x y) -> (MOVBQSX (ADDB <v.Type> x y))
+
+(Sub64 x y) -> (SUBQ x y)
+(Sub64U x y) -> (SUBQ x y)
+(Sub32U x y) -> (SUBL x y)
+(Sub32 x y) -> (MOVLQSX (SUBL <v.Type> x y))
+(Sub16U x y) -> (SUBW x y)
+(Sub16 x y) -> (MOVWQSX (SUBW <v.Type> x y))
+(Sub8U x y) -> (SUBB x y)
+(Sub8 x y) -> (MOVBQSX (SUBB <v.Type> x y))
+
 (Mul <t> x y) && is64BitInt(t) -> (MULQ x y)
 
 (MOVLstore ptr (MOVLQSX x) mem) -> (MOVLstore ptr x mem)
@@ -34,26 +45,26 @@
 // Note: unsigned shifts need to return 0 if shift amount is >= 64.
 //   mask = shift >= 64 ? 0 : 0xffffffffffffffff
 //   result = mask & arg << shift
-(Lsh <t> x y) && is64BitInt(t) ->
+(Lsh64 <t> x y) ->
 	(ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [64] y)))
-(Rsh <t> x y) && is64BitInt(t) && !t.IsSigned() ->
+(Rsh64U <t> x y) ->
 	(ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [64] y)))
 
 // Note: signed right shift needs to return 0/-1 if shift amount is >= 64.
 //   if shift > 63 { shift = 63 }
 //   result = arg >> shift
-(Rsh <t> x y) && is64BitInt(t) && t.IsSigned() ->
+(Rsh64 <t> x y) ->
 	(SARQ <t> x (CMOVQCC <t>
 			(CMPQconst <TypeFlags> [64] y)
 			(Const <t> [63])
 			y))
 
-(Less x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETL (CMPQ <TypeFlags> x y))
-(Leq x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETLE (CMPQ <TypeFlags> x y))
-(Greater x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETG (CMPQ <TypeFlags> x y))
-(Geq x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETGE (CMPQ <TypeFlags> x y))
-(Eq x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETEQ (CMPQ <TypeFlags> x y))
-(Neq x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETNE (CMPQ <TypeFlags> x y))
+(Less64 x y) -> (SETL (CMPQ <TypeFlags> x y))
+(Leq64 x y) -> (SETLE (CMPQ <TypeFlags> x y))
+(Greater64 x y) -> (SETG (CMPQ <TypeFlags> x y))
+(Geq64 x y) -> (SETGE (CMPQ <TypeFlags> x y))
+(Eq64 x y) -> (SETEQ (CMPQ <TypeFlags> x y))
+(Neq64 x y) -> (SETNE (CMPQ <TypeFlags> x y))
 
 (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload ptr mem)
 (Load <t> ptr mem) && is32BitInt(t) -> (MOVLload ptr mem)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index 31beb00..602949e 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -174,6 +174,10 @@
 		{name: "ADDW", reg: gp21, asm: "ADDW"}, // arg0+arg1
 		{name: "ADDB", reg: gp21, asm: "ADDB"}, // arg0+arg1
 
+		{name: "SUBL", reg: gp21, asm: "SUBL"}, // arg0-arg1
+		{name: "SUBW", reg: gp21, asm: "SUBW"}, // arg0-arg1
+		{name: "SUBB", reg: gp21, asm: "SUBB"}, // arg0-arg1
+
 		// (InvertFlags (CMPQ a b)) == (CMPQ b a)
 		// So if we want (SETL (CMPQ a b)) but we can't do that because a is a constant,
 		// then we do (SETL (InvertFlags (CMPQ b a))) instead.
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index a906ec6..e505c43 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -20,20 +20,21 @@
 // For now, the generated successors must be a permutation of the matched successors.
 
 // constant folding
-(Add <t> (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [c+d])
+(Add64 (Const [c]) (Const [d])) -> (Const [c+d])
+(Add64U (Const [c]) (Const [d])) -> (Const [c+d])
 (Mul <t> (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [c*d])
 (IsInBounds (Const [c]) (Const [d])) -> (Const {inBounds(c,d)})
 
 // tear apart slices
 // TODO: anything that generates a slice needs to go in here.
 (SlicePtr (Load ptr mem)) -> (Load ptr mem)
-(SliceLen (Load ptr mem)) -> (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [config.ptrSize])) mem)
-(SliceCap (Load ptr mem)) -> (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [config.ptrSize*2])) mem)
+(SliceLen (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (Const <config.Uintptr> [config.PtrSize])) mem)
+(SliceCap (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (Const <config.Uintptr> [config.PtrSize*2])) mem)
 
 // indexing operations
 // Note: bounds check has already been done
 (ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex <v.Type.PtrTo()> ptr idx) mem)
-(PtrIndex <t> ptr idx) -> (Add ptr (Mul <config.Uintptr> idx (Const <config.Uintptr> [t.Elem().Size()])))
+(PtrIndex <t> ptr idx) -> (AddPtr ptr (Mul <config.Uintptr> idx (Const <config.Uintptr> [t.Elem().Size()])))
 (StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr <v.Type.PtrTo()> [idx] ptr) mem)
 
 // big-object moves
@@ -41,11 +42,11 @@
 (Store dst (Load <t> src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem)
 
 // string ops
-(Const <t> {s}) && t.IsString() -> (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Addr <TypeBytePtr> {config.fe.StringSym(s.(string))} (SB <config.Uintptr>))) (Const <config.Uintptr> [int64(len(s.(string)))])) // TODO: ptr
-(Load <t> ptr mem) && t.IsString() -> (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.ptrSize] ptr) mem))
+(Const <t> {s}) && t.IsString() -> (StringMake (OffPtr <TypeBytePtr> [2*config.PtrSize] (Addr <TypeBytePtr> {config.fe.StringSym(s.(string))} (SB <config.Uintptr>))) (Const <config.Uintptr> [int64(len(s.(string)))])) // TODO: ptr
+(Load <t> ptr mem) && t.IsString() -> (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.PtrSize] ptr) mem))
 (StringPtr (StringMake ptr _)) -> ptr
 (StringLen (StringMake _ len)) -> len
-(Store dst str mem) && str.Type.IsString() -> (Store (OffPtr <TypeBytePtr> [config.ptrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
+(Store dst str mem) && str.Type.IsString() -> (Store (OffPtr <TypeBytePtr> [config.PtrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
 
 (If (Const {c}) yes no) && c.(bool) -> (Plain nil yes)
 (If (Const {c}) yes no) && !c.(bool) -> (Plain nil no)
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index 0af7df1..12c2901 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -8,19 +8,89 @@
 	// 2-input arithmetic
 	// Types must be consistent with Go typing.  Add, for example, must take two values
 	// of the same type and produces that same type.
-	{name: "Add"}, // arg0 + arg1
-	{name: "Sub"}, // arg0 - arg1
+	{name: "Add8"}, // arg0 + arg1
+	{name: "Add16"},
+	{name: "Add32"},
+	{name: "Add64"},
+	{name: "Add8U"},
+	{name: "Add16U"},
+	{name: "Add32U"},
+	{name: "Add64U"},
+	{name: "AddPtr"},
+	// TODO: Add32F, Add64F, Add64C, Add128C
+
+	{name: "Sub8"}, // arg0 - arg1
+	{name: "Sub16"},
+	{name: "Sub32"},
+	{name: "Sub64"},
+	{name: "Sub8U"},
+	{name: "Sub16U"},
+	{name: "Sub32U"},
+	{name: "Sub64U"},
+	// TODO: Sub32F, Sub64F, Sub64C, Sub128C
+
 	{name: "Mul"}, // arg0 * arg1
-	{name: "Lsh"}, // arg0 << arg1
-	{name: "Rsh"}, // arg0 >> arg1 (signed/unsigned depending on signedness of type)
+
+	{name: "Lsh8"}, // arg0 << arg1
+	{name: "Lsh16"},
+	{name: "Lsh32"},
+	{name: "Lsh64"},
+
+	{name: "Rsh8"}, // arg0 >> arg1
+	{name: "Rsh8U"},
+	{name: "Rsh16"},
+	{name: "Rsh16U"},
+	{name: "Rsh32"},
+	{name: "Rsh32U"},
+	{name: "Rsh64"},
+	{name: "Rsh64U"},
 
 	// 2-input comparisons
-	{name: "Eq"},      // arg0 == arg1
-	{name: "Neq"},     // arg0 != arg1
-	{name: "Less"},    // arg0 < arg1
-	{name: "Leq"},     // arg0 <= arg1
-	{name: "Greater"}, // arg0 > arg1
-	{name: "Geq"},     // arg0 <= arg1
+	{name: "Eq8"}, // arg0 == arg1
+	{name: "Eq16"},
+	{name: "Eq32"},
+	{name: "Eq64"},
+
+	{name: "Neq8"}, // arg0 != arg1
+	{name: "Neq16"},
+	{name: "Neq32"},
+	{name: "Neq64"},
+
+	{name: "Less8"}, // arg0 < arg1
+	{name: "Less8U"},
+	{name: "Less16"},
+	{name: "Less16U"},
+	{name: "Less32"},
+	{name: "Less32U"},
+	{name: "Less64"},
+	{name: "Less64U"},
+
+	{name: "Leq8"}, // arg0 <= arg1
+	{name: "Leq8U"},
+	{name: "Leq16"},
+	{name: "Leq16U"},
+	{name: "Leq32"},
+	{name: "Leq32U"},
+	{name: "Leq64"},
+	{name: "Leq64U"},
+
+	{name: "Greater8"}, // arg0 > arg1
+	{name: "Greater8U"},
+	{name: "Greater16"},
+	{name: "Greater16U"},
+	{name: "Greater32"},
+	{name: "Greater32U"},
+	{name: "Greater64"},
+	{name: "Greater64U"},
+
+	{name: "Geq8"}, // arg0 <= arg1
+	{name: "Geq8U"},
+	{name: "Geq16"},
+	{name: "Geq16U"},
+	{name: "Geq32"},
+	{name: "Geq32U"},
+	{name: "Geq64"},
+	{name: "Geq64U"},
 
 	// 1-input ops
 	{name: "Not"}, // !arg0
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 74d30e1..95e2ef7 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -111,19 +111,81 @@
 	OpAMD64ADDL
 	OpAMD64ADDW
 	OpAMD64ADDB
+	OpAMD64SUBL
+	OpAMD64SUBW
+	OpAMD64SUBB
 	OpAMD64InvertFlags
 
-	OpAdd
-	OpSub
+	OpAdd8
+	OpAdd16
+	OpAdd32
+	OpAdd64
+	OpAdd8U
+	OpAdd16U
+	OpAdd32U
+	OpAdd64U
+	OpAddPtr
+	OpSub8
+	OpSub16
+	OpSub32
+	OpSub64
+	OpSub8U
+	OpSub16U
+	OpSub32U
+	OpSub64U
 	OpMul
-	OpLsh
-	OpRsh
-	OpEq
-	OpNeq
-	OpLess
-	OpLeq
-	OpGreater
-	OpGeq
+	OpLsh8
+	OpLsh16
+	OpLsh32
+	OpLsh64
+	OpRsh8
+	OpRsh8U
+	OpRsh16
+	OpRsh16U
+	OpRsh32
+	OpRsh32U
+	OpRsh64
+	OpRsh64U
+	OpEq8
+	OpEq16
+	OpEq32
+	OpEq64
+	OpNeq8
+	OpNeq16
+	OpNeq32
+	OpNeq64
+	OpLess8
+	OpLess8U
+	OpLess16
+	OpLess16U
+	OpLess32
+	OpLess32U
+	OpLess64
+	OpLess64U
+	OpLeq8
+	OpLeq8U
+	OpLeq16
+	OpLeq16U
+	OpLeq32
+	OpLeq32U
+	OpLeq64
+	OpLeq64U
+	OpGreater8
+	OpGreater8U
+	OpGreater16
+	OpGreater16U
+	OpGreater32
+	OpGreater32U
+	OpGreater64
+	OpGreater64U
+	OpGeq8
+	OpGeq8U
+	OpGeq16
+	OpGeq16U
+	OpGeq32
+	OpGeq32U
+	OpGeq64
+	OpGeq64U
 	OpNot
 	OpPhi
 	OpCopy
@@ -928,6 +990,48 @@
 		},
 	},
 	{
+		name: "SUBL",
+		asm:  x86.ASUBL,
+		reg: regInfo{
+			inputs: []regMask{
+				65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+				65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+			},
+			clobbers: 0,
+			outputs: []regMask{
+				65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+			},
+		},
+	},
+	{
+		name: "SUBW",
+		asm:  x86.ASUBW,
+		reg: regInfo{
+			inputs: []regMask{
+				65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+				65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+			},
+			clobbers: 0,
+			outputs: []regMask{
+				65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+			},
+		},
+	},
+	{
+		name: "SUBB",
+		asm:  x86.ASUBB,
+		reg: regInfo{
+			inputs: []regMask{
+				65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+				65535, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+			},
+			clobbers: 0,
+			outputs: []regMask{
+				65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
+			},
+		},
+	},
+	{
 		name: "InvertFlags",
 		reg: regInfo{
 			inputs:   []regMask{},
@@ -937,7 +1041,7 @@
 	},
 
 	{
-		name: "Add",
+		name: "Add8",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -946,7 +1050,142 @@
 		generic: true,
 	},
 	{
-		name: "Sub",
+		name: "Add16",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Add32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Add64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Add8U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Add16U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Add32U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Add64U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "AddPtr",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Sub8",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Sub16",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Sub32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Sub64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Sub8U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Sub16U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Sub32U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Sub64U",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -964,7 +1203,7 @@
 		generic: true,
 	},
 	{
-		name: "Lsh",
+		name: "Lsh8",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -973,7 +1212,7 @@
 		generic: true,
 	},
 	{
-		name: "Rsh",
+		name: "Lsh16",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -982,7 +1221,7 @@
 		generic: true,
 	},
 	{
-		name: "Eq",
+		name: "Lsh32",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -991,7 +1230,7 @@
 		generic: true,
 	},
 	{
-		name: "Neq",
+		name: "Lsh64",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -1000,7 +1239,7 @@
 		generic: true,
 	},
 	{
-		name: "Less",
+		name: "Rsh8",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -1009,7 +1248,7 @@
 		generic: true,
 	},
 	{
-		name: "Leq",
+		name: "Rsh8U",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -1018,7 +1257,7 @@
 		generic: true,
 	},
 	{
-		name: "Greater",
+		name: "Rsh16",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
@@ -1027,7 +1266,403 @@
 		generic: true,
 	},
 	{
-		name: "Geq",
+		name: "Rsh16U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Rsh32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Rsh32U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Rsh64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Rsh64U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Eq8",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Eq16",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Eq32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Eq64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Neq8",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Neq16",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Neq32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Neq64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Less8",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Less8U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Less16",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Less16U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Less32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Less32U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Less64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Less64U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Leq8",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Leq8U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Leq16",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Leq16U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Leq32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Leq32U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Leq64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Leq64U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Greater8",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Greater8U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Greater16",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Greater16U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Greater32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Greater32U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Greater64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Greater64U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Geq8",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Geq8U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Geq16",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Geq16U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Geq32",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Geq32U",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Geq64",
+		reg: regInfo{
+			inputs:   []regMask{},
+			clobbers: 0,
+			outputs:  []regMask{},
+		},
+		generic: true,
+	},
+	{
+		name: "Geq64U",
 		reg: regInfo{
 			inputs:   []regMask{},
 			clobbers: 0,
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index 3e24f9f..9a879a3 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -187,83 +187,34 @@
 		goto end646afc7b328db89ad16ebfa156ae26e5
 	end646afc7b328db89ad16ebfa156ae26e5:
 		;
-	case OpAdd:
-		// match: (Add <t> x y)
-		// cond: (is64BitInt(t) || isPtr(t))
-		// result: (ADDQ x y)
+	case OpAdd16:
+		// match: (Add16 x y)
+		// cond:
+		// result: (MOVWQSX (ADDW <v.Type> x y))
 		{
-			t := v.Type
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(t) || isPtr(t)) {
-				goto endf031c523d7dd08e4b8e7010a94cd94c9
-			}
-			v.Op = OpAMD64ADDQ
+			v.Op = OpAMD64MOVWQSX
 			v.AuxInt = 0
 			v.Aux = nil
 			v.resetArgs()
-			v.AddArg(x)
-			v.AddArg(y)
-			return true
-		}
-		goto endf031c523d7dd08e4b8e7010a94cd94c9
-	endf031c523d7dd08e4b8e7010a94cd94c9:
-		;
-		// match: (Add <t> x y)
-		// cond: is32BitInt(t) && !isSigned(t)
-		// result: (ADDL x y)
-		{
-			t := v.Type
-			x := v.Args[0]
-			y := v.Args[1]
-			if !(is32BitInt(t) && !isSigned(t)) {
-				goto endce1730b0a04d773ed8029e7eac4f3a50
-			}
-			v.Op = OpAMD64ADDL
-			v.AuxInt = 0
-			v.Aux = nil
-			v.resetArgs()
-			v.AddArg(x)
-			v.AddArg(y)
-			return true
-		}
-		goto endce1730b0a04d773ed8029e7eac4f3a50
-	endce1730b0a04d773ed8029e7eac4f3a50:
-		;
-		// match: (Add <t> x y)
-		// cond: is32BitInt(t) && isSigned(t)
-		// result: (MOVLQSX (ADDL <t> x y))
-		{
-			t := v.Type
-			x := v.Args[0]
-			y := v.Args[1]
-			if !(is32BitInt(t) && isSigned(t)) {
-				goto end86e07674e2e9d2e1fc5a8f5f74375513
-			}
-			v.Op = OpAMD64MOVLQSX
-			v.AuxInt = 0
-			v.Aux = nil
-			v.resetArgs()
-			v0 := v.Block.NewValue0(v.Line, OpAMD64ADDL, TypeInvalid)
-			v0.Type = t
+			v0 := v.Block.NewValue0(v.Line, OpAMD64ADDW, TypeInvalid)
+			v0.Type = v.Type
 			v0.AddArg(x)
 			v0.AddArg(y)
 			v.AddArg(v0)
 			return true
 		}
-		goto end86e07674e2e9d2e1fc5a8f5f74375513
-	end86e07674e2e9d2e1fc5a8f5f74375513:
+		goto end2aef2dab49f6b2ca337f58ad0a8209ae
+	end2aef2dab49f6b2ca337f58ad0a8209ae:
 		;
-		// match: (Add <t> x y)
-		// cond: is16BitInt(t) && !isSigned(t)
+	case OpAdd16U:
+		// match: (Add16U x y)
+		// cond:
 		// result: (ADDW x y)
 		{
-			t := v.Type
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is16BitInt(t) && !isSigned(t)) {
-				goto end99632c2482f1963513f12a317c588800
-			}
 			v.Op = OpAMD64ADDW
 			v.AuxInt = 0
 			v.Aux = nil
@@ -272,43 +223,112 @@
 			v.AddArg(y)
 			return true
 		}
-		goto end99632c2482f1963513f12a317c588800
-	end99632c2482f1963513f12a317c588800:
+		goto end8ca34beeb0897b0c70352ba90cca4a1d
+	end8ca34beeb0897b0c70352ba90cca4a1d:
 		;
-		// match: (Add <t> x y)
-		// cond: is16BitInt(t) && isSigned(t)
-		// result: (MOVWQSX (ADDW <t> x y))
+	case OpAdd32:
+		// match: (Add32 x y)
+		// cond:
+		// result: (MOVLQSX (ADDL <v.Type> x y))
 		{
-			t := v.Type
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is16BitInt(t) && isSigned(t)) {
-				goto endd215b5658d14e7d1cb469a516aa554e9
-			}
-			v.Op = OpAMD64MOVWQSX
+			v.Op = OpAMD64MOVLQSX
 			v.AuxInt = 0
 			v.Aux = nil
 			v.resetArgs()
-			v0 := v.Block.NewValue0(v.Line, OpAMD64ADDW, TypeInvalid)
-			v0.Type = t
+			v0 := v.Block.NewValue0(v.Line, OpAMD64ADDL, TypeInvalid)
+			v0.Type = v.Type
 			v0.AddArg(x)
 			v0.AddArg(y)
 			v.AddArg(v0)
 			return true
 		}
-		goto endd215b5658d14e7d1cb469a516aa554e9
-	endd215b5658d14e7d1cb469a516aa554e9:
+		goto end7f18bca004d8c158f50b04e7511af49f
+	end7f18bca004d8c158f50b04e7511af49f:
 		;
-		// match: (Add <t> x y)
-		// cond: is8BitInt(t) && !isSigned(t)
-		// result: (ADDB x y)
+	case OpAdd32U:
+		// match: (Add32U x y)
+		// cond:
+		// result: (ADDL x y)
 		{
-			t := v.Type
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is8BitInt(t) && !isSigned(t)) {
-				goto end41d7f409a1e1076e9645e2e90b7220ce
-			}
+			v.Op = OpAMD64ADDL
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v.AddArg(x)
+			v.AddArg(y)
+			return true
+		}
+		goto end72ff71aa883fa569307ae06289ac1e30
+	end72ff71aa883fa569307ae06289ac1e30:
+		;
+	case OpAdd64:
+		// match: (Add64 x y)
+		// cond:
+		// result: (ADDQ x y)
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64ADDQ
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v.AddArg(x)
+			v.AddArg(y)
+			return true
+		}
+		goto endd88f18b3f39e3ccc201477a616f0abc0
+	endd88f18b3f39e3ccc201477a616f0abc0:
+		;
+	case OpAdd64U:
+		// match: (Add64U x y)
+		// cond:
+		// result: (ADDQ x y)
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64ADDQ
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v.AddArg(x)
+			v.AddArg(y)
+			return true
+		}
+		goto endee28cc0dbdf2664cb3f6a5ddb3960b1b
+	endee28cc0dbdf2664cb3f6a5ddb3960b1b:
+		;
+	case OpAdd8:
+		// match: (Add8 x y)
+		// cond:
+		// result: (MOVBQSX (ADDB <v.Type> x y))
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64MOVBQSX
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v0 := v.Block.NewValue0(v.Line, OpAMD64ADDB, TypeInvalid)
+			v0.Type = v.Type
+			v0.AddArg(x)
+			v0.AddArg(y)
+			v.AddArg(v0)
+			return true
+		}
+		goto end7078e2b21b2da3acc80e79ba1386d098
+	end7078e2b21b2da3acc80e79ba1386d098:
+		;
+	case OpAdd8U:
+		// match: (Add8U x y)
+		// cond:
+		// result: (ADDB x y)
+		{
+			x := v.Args[0]
+			y := v.Args[1]
 			v.Op = OpAMD64ADDB
 			v.AuxInt = 0
 			v.Aux = nil
@@ -317,32 +337,26 @@
 			v.AddArg(y)
 			return true
 		}
-		goto end41d7f409a1e1076e9645e2e90b7220ce
-	end41d7f409a1e1076e9645e2e90b7220ce:
+		goto endb5cb0e4b3566464c17acf1df5e4b0543
+	endb5cb0e4b3566464c17acf1df5e4b0543:
 		;
-		// match: (Add <t> x y)
-		// cond: is8BitInt(t) && isSigned(t)
-		// result: (MOVBQSX (ADDB <t> x y))
+	case OpAddPtr:
+		// match: (AddPtr x y)
+		// cond:
+		// result: (ADDQ x y)
 		{
-			t := v.Type
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is8BitInt(t) && isSigned(t)) {
-				goto end858e823866524b81b4636f7dd7e8eefe
-			}
-			v.Op = OpAMD64MOVBQSX
+			v.Op = OpAMD64ADDQ
 			v.AuxInt = 0
 			v.Aux = nil
 			v.resetArgs()
-			v0 := v.Block.NewValue0(v.Line, OpAMD64ADDB, TypeInvalid)
-			v0.Type = t
-			v0.AddArg(x)
-			v0.AddArg(y)
-			v.AddArg(v0)
+			v.AddArg(x)
+			v.AddArg(y)
 			return true
 		}
-		goto end858e823866524b81b4636f7dd7e8eefe
-	end858e823866524b81b4636f7dd7e8eefe:
+		goto enda1d5640788c7157996f9d4af602dec1c
+	enda1d5640788c7157996f9d4af602dec1c:
 		;
 	case OpAddr:
 		// match: (Addr {sym} base)
@@ -595,16 +609,13 @@
 		goto endcc7894224d4f6b0bcabcece5d0185912
 	endcc7894224d4f6b0bcabcece5d0185912:
 		;
-	case OpEq:
-		// match: (Eq x y)
-		// cond: is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)
+	case OpEq64:
+		// match: (Eq64 x y)
+		// cond:
 		// result: (SETEQ (CMPQ <TypeFlags> x y))
 		{
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)) {
-				goto endad64a62086703de09f52315e190bdf0e
-			}
 			v.Op = OpAMD64SETEQ
 			v.AuxInt = 0
 			v.Aux = nil
@@ -616,19 +627,16 @@
 			v.AddArg(v0)
 			return true
 		}
-		goto endad64a62086703de09f52315e190bdf0e
-	endad64a62086703de09f52315e190bdf0e:
+		goto endae6c62e4e20b4f62694b6ee40dbd9211
+	endae6c62e4e20b4f62694b6ee40dbd9211:
 		;
-	case OpGeq:
-		// match: (Geq x y)
-		// cond: is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)
+	case OpGeq64:
+		// match: (Geq64 x y)
+		// cond:
 		// result: (SETGE (CMPQ <TypeFlags> x y))
 		{
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)) {
-				goto end31ba1968829a3b451a35431111140fec
-			}
 			v.Op = OpAMD64SETGE
 			v.AuxInt = 0
 			v.Aux = nil
@@ -640,19 +648,16 @@
 			v.AddArg(v0)
 			return true
 		}
-		goto end31ba1968829a3b451a35431111140fec
-	end31ba1968829a3b451a35431111140fec:
+		goto end63f44e3fec8d92723b5bde42d6d7eea0
+	end63f44e3fec8d92723b5bde42d6d7eea0:
 		;
-	case OpGreater:
-		// match: (Greater x y)
-		// cond: is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)
+	case OpGreater64:
+		// match: (Greater64 x y)
+		// cond:
 		// result: (SETG (CMPQ <TypeFlags> x y))
 		{
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)) {
-				goto end1cff30b1bf40104e5e30ab73d6568f7f
-			}
 			v.Op = OpAMD64SETG
 			v.AuxInt = 0
 			v.Aux = nil
@@ -664,8 +669,8 @@
 			v.AddArg(v0)
 			return true
 		}
-		goto end1cff30b1bf40104e5e30ab73d6568f7f
-	end1cff30b1bf40104e5e30ab73d6568f7f:
+		goto endaef0cfa5e27e23cf5e527061cf251069
+	endaef0cfa5e27e23cf5e527061cf251069:
 		;
 	case OpIsInBounds:
 		// match: (IsInBounds idx len)
@@ -708,16 +713,13 @@
 		goto endff508c3726edfb573abc6128c177e76c
 	endff508c3726edfb573abc6128c177e76c:
 		;
-	case OpLeq:
-		// match: (Leq x y)
-		// cond: is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)
+	case OpLeq64:
+		// match: (Leq64 x y)
+		// cond:
 		// result: (SETLE (CMPQ <TypeFlags> x y))
 		{
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)) {
-				goto enddb4f100c01cdd95d69d399ffc37e33e7
-			}
 			v.Op = OpAMD64SETLE
 			v.AuxInt = 0
 			v.Aux = nil
@@ -729,19 +731,16 @@
 			v.AddArg(v0)
 			return true
 		}
-		goto enddb4f100c01cdd95d69d399ffc37e33e7
-	enddb4f100c01cdd95d69d399ffc37e33e7:
+		goto endf03da5e28dccdb4797671f39e824fb10
+	endf03da5e28dccdb4797671f39e824fb10:
 		;
-	case OpLess:
-		// match: (Less x y)
-		// cond: is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)
+	case OpLess64:
+		// match: (Less64 x y)
+		// cond:
 		// result: (SETL (CMPQ <TypeFlags> x y))
 		{
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)) {
-				goto endcecf13a952d4c6c2383561c7d68a3cf9
-			}
 			v.Op = OpAMD64SETL
 			v.AuxInt = 0
 			v.Aux = nil
@@ -753,8 +752,8 @@
 			v.AddArg(v0)
 			return true
 		}
-		goto endcecf13a952d4c6c2383561c7d68a3cf9
-	endcecf13a952d4c6c2383561c7d68a3cf9:
+		goto endf8e7a24c25692045bbcfd2c9356d1a8c
+	endf8e7a24c25692045bbcfd2c9356d1a8c:
 		;
 	case OpLoad:
 		// match: (Load <t> ptr mem)
@@ -841,17 +840,14 @@
 		goto end8f83bf72293670e75b22d6627bd13f0b
 	end8f83bf72293670e75b22d6627bd13f0b:
 		;
-	case OpLsh:
-		// match: (Lsh <t> x y)
-		// cond: is64BitInt(t)
+	case OpLsh64:
+		// match: (Lsh64 <t> x y)
+		// cond:
 		// result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [64] y)))
 		{
 			t := v.Type
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(t)) {
-				goto end5d9e2211940fbc82536685578cf37d08
-			}
 			v.Op = OpAMD64ANDQ
 			v.AuxInt = 0
 			v.Aux = nil
@@ -871,8 +867,8 @@
 			v.AddArg(v1)
 			return true
 		}
-		goto end5d9e2211940fbc82536685578cf37d08
-	end5d9e2211940fbc82536685578cf37d08:
+		goto end02b17b9d1aca859d392e527fe6fc58da
+	end02b17b9d1aca859d392e527fe6fc58da:
 		;
 	case OpAMD64MOVBstore:
 		// match: (MOVBstore ptr (MOVBQSX x) mem)
@@ -1289,16 +1285,13 @@
 		goto endfab0d598f376ecba45a22587d50f7aff
 	endfab0d598f376ecba45a22587d50f7aff:
 		;
-	case OpNeq:
-		// match: (Neq x y)
-		// cond: is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)
+	case OpNeq64:
+		// match: (Neq64 x y)
+		// cond:
 		// result: (SETNE (CMPQ <TypeFlags> x y))
 		{
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)) {
-				goto enddccbd4e7581ae8d9916b933d3501987b
-			}
 			v.Op = OpAMD64SETNE
 			v.AuxInt = 0
 			v.Aux = nil
@@ -1310,8 +1303,8 @@
 			v.AddArg(v0)
 			return true
 		}
-		goto enddccbd4e7581ae8d9916b933d3501987b
-	enddccbd4e7581ae8d9916b933d3501987b:
+		goto end8ab0bcb910c0d3213dd8726fbcc4848e
+	end8ab0bcb910c0d3213dd8726fbcc4848e:
 		;
 	case OpNot:
 		// match: (Not x)
@@ -1348,49 +1341,14 @@
 		goto end0429f947ee7ac49ff45a243e461a5290
 	end0429f947ee7ac49ff45a243e461a5290:
 		;
-	case OpRsh:
-		// match: (Rsh <t> x y)
-		// cond: is64BitInt(t) && !t.IsSigned()
-		// result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [64] y)))
-		{
-			t := v.Type
-			x := v.Args[0]
-			y := v.Args[1]
-			if !(is64BitInt(t) && !t.IsSigned()) {
-				goto ende3e068773b8e6def1eaedb4f404ca6e5
-			}
-			v.Op = OpAMD64ANDQ
-			v.AuxInt = 0
-			v.Aux = nil
-			v.resetArgs()
-			v0 := v.Block.NewValue0(v.Line, OpAMD64SHRQ, TypeInvalid)
-			v0.Type = t
-			v0.AddArg(x)
-			v0.AddArg(y)
-			v.AddArg(v0)
-			v1 := v.Block.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid)
-			v1.Type = t
-			v2 := v.Block.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid)
-			v2.Type = TypeFlags
-			v2.AuxInt = 64
-			v2.AddArg(y)
-			v1.AddArg(v2)
-			v.AddArg(v1)
-			return true
-		}
-		goto ende3e068773b8e6def1eaedb4f404ca6e5
-	ende3e068773b8e6def1eaedb4f404ca6e5:
-		;
-		// match: (Rsh <t> x y)
-		// cond: is64BitInt(t) && t.IsSigned()
+	case OpRsh64:
+		// match: (Rsh64 <t> x y)
+		// cond:
 		// result: (SARQ <t> x (CMOVQCC <t> 			(CMPQconst <TypeFlags> [64] y) 			(Const <t> [63]) 			y))
 		{
 			t := v.Type
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(t) && t.IsSigned()) {
-				goto end901ea4851cd5d2277a1ca1bee8f69d59
-			}
 			v.Op = OpAMD64SARQ
 			v.AuxInt = 0
 			v.Aux = nil
@@ -1412,8 +1370,38 @@
 			v.AddArg(v0)
 			return true
 		}
-		goto end901ea4851cd5d2277a1ca1bee8f69d59
-	end901ea4851cd5d2277a1ca1bee8f69d59:
+		goto end831ac9db492245c5e6c83d0b2a96b2d3
+	end831ac9db492245c5e6c83d0b2a96b2d3:
+		;
+	case OpRsh64U:
+		// match: (Rsh64U <t> x y)
+		// cond:
+		// result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [64] y)))
+		{
+			t := v.Type
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64ANDQ
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v0 := v.Block.NewValue0(v.Line, OpAMD64SHRQ, TypeInvalid)
+			v0.Type = t
+			v0.AddArg(x)
+			v0.AddArg(y)
+			v.AddArg(v0)
+			v1 := v.Block.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid)
+			v1.Type = t
+			v2 := v.Block.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid)
+			v2.Type = TypeFlags
+			v2.AuxInt = 64
+			v2.AddArg(y)
+			v1.AddArg(v2)
+			v.AddArg(v1)
+			return true
+		}
+		goto end90c34fa7de598170ea23d23d9a03ebfc
+	end90c34fa7de598170ea23d23d9a03ebfc:
 		;
 	case OpAMD64SARQ:
 		// match: (SARQ x (MOVQconst [c]))
@@ -1743,17 +1731,91 @@
 		goto end6f343b676bf49740054e459f972b24f5
 	end6f343b676bf49740054e459f972b24f5:
 		;
-	case OpSub:
-		// match: (Sub <t> x y)
-		// cond: is64BitInt(t)
-		// result: (SUBQ x y)
+	case OpSub16:
+		// match: (Sub16 x y)
+		// cond:
+		// result: (MOVWQSX (SUBW <v.Type> x y))
 		{
-			t := v.Type
 			x := v.Args[0]
 			y := v.Args[1]
-			if !(is64BitInt(t)) {
-				goto ende6ef29f885a8ecf3058212bb95917323
-			}
+			v.Op = OpAMD64MOVWQSX
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v0 := v.Block.NewValue0(v.Line, OpAMD64SUBW, TypeInvalid)
+			v0.Type = v.Type
+			v0.AddArg(x)
+			v0.AddArg(y)
+			v.AddArg(v0)
+			return true
+		}
+		goto endf9d14f07ce4212200662acd073b77a79
+	endf9d14f07ce4212200662acd073b77a79:
+		;
+	case OpSub16U:
+		// match: (Sub16U x y)
+		// cond:
+		// result: (SUBW x y)
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64SUBW
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v.AddArg(x)
+			v.AddArg(y)
+			return true
+		}
+		goto end1d72e18fad1c22bb770963f167b98c96
+	end1d72e18fad1c22bb770963f167b98c96:
+		;
+	case OpSub32:
+		// match: (Sub32 x y)
+		// cond:
+		// result: (MOVLQSX (SUBL <v.Type> x y))
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64MOVLQSX
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v0 := v.Block.NewValue0(v.Line, OpAMD64SUBL, TypeInvalid)
+			v0.Type = v.Type
+			v0.AddArg(x)
+			v0.AddArg(y)
+			v.AddArg(v0)
+			return true
+		}
+		goto end4c091fbf93fb9599a70c001845424614
+	end4c091fbf93fb9599a70c001845424614:
+		;
+	case OpSub32U:
+		// match: (Sub32U x y)
+		// cond:
+		// result: (SUBL x y)
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64SUBL
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v.AddArg(x)
+			v.AddArg(y)
+			return true
+		}
+		goto end281d1020f0e75fce9df321580f07c4d5
+	end281d1020f0e75fce9df321580f07c4d5:
+		;
+	case OpSub64:
+		// match: (Sub64 x y)
+		// cond:
+		// result: (SUBQ x y)
+		{
+			x := v.Args[0]
+			y := v.Args[1]
 			v.Op = OpAMD64SUBQ
 			v.AuxInt = 0
 			v.Aux = nil
@@ -1762,8 +1824,65 @@
 			v.AddArg(y)
 			return true
 		}
-		goto ende6ef29f885a8ecf3058212bb95917323
-	ende6ef29f885a8ecf3058212bb95917323:
+		goto endd88d5646309fd9174584888ecc8aca2c
+	endd88d5646309fd9174584888ecc8aca2c:
+		;
+	case OpSub64U:
+		// match: (Sub64U x y)
+		// cond:
+		// result: (SUBQ x y)
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64SUBQ
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v.AddArg(x)
+			v.AddArg(y)
+			return true
+		}
+		goto end288f94a53865cdb00a0290d8358bb7da
+	end288f94a53865cdb00a0290d8358bb7da:
+		;
+	case OpSub8:
+		// match: (Sub8 x y)
+		// cond:
+		// result: (MOVBQSX (SUBB <v.Type> x y))
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64MOVBQSX
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v0 := v.Block.NewValue0(v.Line, OpAMD64SUBB, TypeInvalid)
+			v0.Type = v.Type
+			v0.AddArg(x)
+			v0.AddArg(y)
+			v.AddArg(v0)
+			return true
+		}
+		goto endfa3ef95107dcb01ae343f2243e485e80
+	endfa3ef95107dcb01ae343f2243e485e80:
+		;
+	case OpSub8U:
+		// match: (Sub8U x y)
+		// cond:
+		// result: (SUBB x y)
+		{
+			x := v.Args[0]
+			y := v.Args[1]
+			v.Op = OpAMD64SUBB
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v.AddArg(x)
+			v.AddArg(y)
+			return true
+		}
+		goto end8f5160f898dfa43da7d7d9f8cbaf9615
+	end8f5160f898dfa43da7d7d9f8cbaf9615:
 		;
 	case OpZero:
 		// match: (Zero [0] _ mem)
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index ca523ee..7a4b6bf 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -4,23 +4,19 @@
 
 func rewriteValuegeneric(v *Value, config *Config) bool {
 	switch v.Op {
-	case OpAdd:
-		// match: (Add <t> (Const [c]) (Const [d]))
-		// cond: is64BitInt(t)
+	case OpAdd64:
+		// match: (Add64 (Const [c]) (Const [d]))
+		// cond:
 		// result: (Const [c+d])
 		{
-			t := v.Type
 			if v.Args[0].Op != OpConst {
-				goto end279f4ea85ed10e5ffc5b53f9e060529b
+				goto endd2f4bfaaf6c937171a287b73e5c2f73e
 			}
 			c := v.Args[0].AuxInt
 			if v.Args[1].Op != OpConst {
-				goto end279f4ea85ed10e5ffc5b53f9e060529b
+				goto endd2f4bfaaf6c937171a287b73e5c2f73e
 			}
 			d := v.Args[1].AuxInt
-			if !(is64BitInt(t)) {
-				goto end279f4ea85ed10e5ffc5b53f9e060529b
-			}
 			v.Op = OpConst
 			v.AuxInt = 0
 			v.Aux = nil
@@ -28,8 +24,31 @@
 			v.AuxInt = c + d
 			return true
 		}
-		goto end279f4ea85ed10e5ffc5b53f9e060529b
-	end279f4ea85ed10e5ffc5b53f9e060529b:
+		goto endd2f4bfaaf6c937171a287b73e5c2f73e
+	endd2f4bfaaf6c937171a287b73e5c2f73e:
+		;
+	case OpAdd64U:
+		// match: (Add64U (Const [c]) (Const [d]))
+		// cond:
+		// result: (Const [c+d])
+		{
+			if v.Args[0].Op != OpConst {
+				goto endfedc373d8be0243cb5dbbc948996fe3a
+			}
+			c := v.Args[0].AuxInt
+			if v.Args[1].Op != OpConst {
+				goto endfedc373d8be0243cb5dbbc948996fe3a
+			}
+			d := v.Args[1].AuxInt
+			v.Op = OpConst
+			v.AuxInt = 0
+			v.Aux = nil
+			v.resetArgs()
+			v.AuxInt = c + d
+			return true
+		}
+		goto endfedc373d8be0243cb5dbbc948996fe3a
+	endfedc373d8be0243cb5dbbc948996fe3a:
 		;
 	case OpArrayIndex:
 		// match: (ArrayIndex (Load ptr mem) idx)
@@ -60,12 +79,12 @@
 	case OpConst:
 		// match: (Const <t> {s})
 		// cond: t.IsString()
-		// result: (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Addr <TypeBytePtr> {config.fe.StringSym(s.(string))} (SB <config.Uintptr>))) (Const <config.Uintptr> [int64(len(s.(string)))]))
+		// result: (StringMake (OffPtr <TypeBytePtr> [2*config.PtrSize] (Addr <TypeBytePtr> {config.fe.StringSym(s.(string))} (SB <config.Uintptr>))) (Const <config.Uintptr> [int64(len(s.(string)))]))
 		{
 			t := v.Type
 			s := v.Aux
 			if !(t.IsString()) {
-				goto end55cd8fd3b98a2459d0ee9d6cbb456b01
+				goto endedcb8bd24122d6a47bdc9b752460c344
 			}
 			v.Op = OpStringMake
 			v.AuxInt = 0
@@ -73,7 +92,7 @@
 			v.resetArgs()
 			v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid)
 			v0.Type = TypeBytePtr
-			v0.AuxInt = 2 * config.ptrSize
+			v0.AuxInt = 2 * config.PtrSize
 			v1 := v.Block.NewValue0(v.Line, OpAddr, TypeInvalid)
 			v1.Type = TypeBytePtr
 			v1.Aux = config.fe.StringSym(s.(string))
@@ -88,8 +107,8 @@
 			v.AddArg(v3)
 			return true
 		}
-		goto end55cd8fd3b98a2459d0ee9d6cbb456b01
-	end55cd8fd3b98a2459d0ee9d6cbb456b01:
+		goto endedcb8bd24122d6a47bdc9b752460c344
+	endedcb8bd24122d6a47bdc9b752460c344:
 		;
 	case OpIsInBounds:
 		// match: (IsInBounds (Const [c]) (Const [d]))
@@ -117,13 +136,13 @@
 	case OpLoad:
 		// match: (Load <t> ptr mem)
 		// cond: t.IsString()
-		// result: (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.ptrSize] ptr) mem))
+		// result: (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.PtrSize] ptr) mem))
 		{
 			t := v.Type
 			ptr := v.Args[0]
 			mem := v.Args[1]
 			if !(t.IsString()) {
-				goto endd0afd003b70d726a1c5bbaf51fe06182
+				goto endce3ba169a57b8a9f6b12751d49b4e23a
 			}
 			v.Op = OpStringMake
 			v.AuxInt = 0
@@ -138,15 +157,15 @@
 			v1.Type = config.Uintptr
 			v2 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid)
 			v2.Type = TypeBytePtr
-			v2.AuxInt = config.ptrSize
+			v2.AuxInt = config.PtrSize
 			v2.AddArg(ptr)
 			v1.AddArg(v2)
 			v1.AddArg(mem)
 			v.AddArg(v1)
 			return true
 		}
-		goto endd0afd003b70d726a1c5bbaf51fe06182
-	endd0afd003b70d726a1c5bbaf51fe06182:
+		goto endce3ba169a57b8a9f6b12751d49b4e23a
+	endce3ba169a57b8a9f6b12751d49b4e23a:
 		;
 	case OpMul:
 		// match: (Mul <t> (Const [c]) (Const [d]))
@@ -178,12 +197,12 @@
 	case OpPtrIndex:
 		// match: (PtrIndex <t> ptr idx)
 		// cond:
-		// result: (Add ptr (Mul <config.Uintptr> idx (Const <config.Uintptr> [t.Elem().Size()])))
+		// result: (AddPtr ptr (Mul <config.Uintptr> idx (Const <config.Uintptr> [t.Elem().Size()])))
 		{
 			t := v.Type
 			ptr := v.Args[0]
 			idx := v.Args[1]
-			v.Op = OpAdd
+			v.Op = OpAddPtr
 			v.AuxInt = 0
 			v.Aux = nil
 			v.resetArgs()
@@ -198,16 +217,16 @@
 			v.AddArg(v0)
 			return true
 		}
-		goto end88c7c383675420d1581daeb899039fa8
-	end88c7c383675420d1581daeb899039fa8:
+		goto endc181347cd3c740e2a1da431a981fdd7e
+	endc181347cd3c740e2a1da431a981fdd7e:
 		;
 	case OpSliceCap:
 		// match: (SliceCap (Load ptr mem))
 		// cond:
-		// result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [config.ptrSize*2])) mem)
+		// result: (Load (AddPtr <ptr.Type> ptr (Const <config.Uintptr> [config.PtrSize*2])) mem)
 		{
 			if v.Args[0].Op != OpLoad {
-				goto end919cfa3d3539eb2e06a435d5f89654b9
+				goto end83c0ff7760465a4184bad9e4b47f7be8
 			}
 			ptr := v.Args[0].Args[0]
 			mem := v.Args[0].Args[1]
@@ -215,27 +234,27 @@
 			v.AuxInt = 0
 			v.Aux = nil
 			v.resetArgs()
-			v0 := v.Block.NewValue0(v.Line, OpAdd, TypeInvalid)
+			v0 := v.Block.NewValue0(v.Line, OpAddPtr, TypeInvalid)
 			v0.Type = ptr.Type
 			v0.AddArg(ptr)
 			v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid)
 			v1.Type = config.Uintptr
-			v1.AuxInt = config.ptrSize * 2
+			v1.AuxInt = config.PtrSize * 2
 			v0.AddArg(v1)
 			v.AddArg(v0)
 			v.AddArg(mem)
 			return true
 		}
-		goto end919cfa3d3539eb2e06a435d5f89654b9
-	end919cfa3d3539eb2e06a435d5f89654b9:
+		goto end83c0ff7760465a4184bad9e4b47f7be8
+	end83c0ff7760465a4184bad9e4b47f7be8:
 		;
 	case OpSliceLen:
 		// match: (SliceLen (Load ptr mem))
 		// cond:
-		// result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [config.ptrSize])) mem)
+		// result: (Load (AddPtr <ptr.Type> ptr (Const <config.Uintptr> [config.PtrSize])) mem)
 		{
 			if v.Args[0].Op != OpLoad {
-				goto end3d74a5ef07180a709a91052da88bcd01
+				goto end20579b262d017d875d579683996f0ef9
 			}
 			ptr := v.Args[0].Args[0]
 			mem := v.Args[0].Args[1]
@@ -243,19 +262,19 @@
 			v.AuxInt = 0
 			v.Aux = nil
 			v.resetArgs()
-			v0 := v.Block.NewValue0(v.Line, OpAdd, TypeInvalid)
+			v0 := v.Block.NewValue0(v.Line, OpAddPtr, TypeInvalid)
 			v0.Type = ptr.Type
 			v0.AddArg(ptr)
 			v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid)
 			v1.Type = config.Uintptr
-			v1.AuxInt = config.ptrSize
+			v1.AuxInt = config.PtrSize
 			v0.AddArg(v1)
 			v.AddArg(v0)
 			v.AddArg(mem)
 			return true
 		}
-		goto end3d74a5ef07180a709a91052da88bcd01
-	end3d74a5ef07180a709a91052da88bcd01:
+		goto end20579b262d017d875d579683996f0ef9
+	end20579b262d017d875d579683996f0ef9:
 		;
 	case OpSlicePtr:
 		// match: (SlicePtr (Load ptr mem))
@@ -311,13 +330,13 @@
 		;
 		// match: (Store dst str mem)
 		// cond: str.Type.IsString()
-		// result: (Store (OffPtr <TypeBytePtr> [config.ptrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
+		// result: (Store (OffPtr <TypeBytePtr> [config.PtrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
 		{
 			dst := v.Args[0]
 			str := v.Args[1]
 			mem := v.Args[2]
 			if !(str.Type.IsString()) {
-				goto end410559d97aed8018f820cd88723de442
+				goto endb47e037c1e5ac54c3a41d53163d8aef6
 			}
 			v.Op = OpStore
 			v.AuxInt = 0
@@ -325,7 +344,7 @@
 			v.resetArgs()
 			v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid)
 			v0.Type = TypeBytePtr
-			v0.AuxInt = config.ptrSize
+			v0.AuxInt = config.PtrSize
 			v0.AddArg(dst)
 			v.AddArg(v0)
 			v1 := v.Block.NewValue0(v.Line, OpStringLen, TypeInvalid)
@@ -343,8 +362,8 @@
 			v.AddArg(v2)
 			return true
 		}
-		goto end410559d97aed8018f820cd88723de442
-	end410559d97aed8018f820cd88723de442:
+		goto endb47e037c1e5ac54c3a41d53163d8aef6
+	endb47e037c1e5ac54c3a41d53163d8aef6:
 		;
 	case OpStringLen:
 		// match: (StringLen (StringMake _ len))
diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go
index a943257..3a89483 100644
--- a/src/cmd/compile/internal/ssa/schedule_test.go
+++ b/src/cmd/compile/internal/ssa/schedule_test.go
@@ -19,7 +19,7 @@
 				Valu("mem3", OpStore, TypeInt64, 0, nil, "ptr", "sum", "mem2"),
 				Valu("l1", OpLoad, TypeInt64, 0, nil, "ptr", "mem1"),
 				Valu("l2", OpLoad, TypeInt64, 0, nil, "ptr", "mem2"),
-				Valu("sum", OpAdd, TypeInt64, 0, nil, "l1", "l2"),
+				Valu("sum", OpAdd64, TypeInt64, 0, nil, "l1", "l2"),
 				Goto("exit")),
 			Bloc("exit",
 				Exit("mem3"))),
diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go
index 29b47c1..cde48d3 100644
--- a/src/cmd/compile/internal/ssa/shift_test.go
+++ b/src/cmd/compile/internal/ssa/shift_test.go
@@ -10,17 +10,17 @@
 
 func TestShiftConstAMD64(t *testing.T) {
 	c := NewConfig("amd64", DummyFrontend{t})
-	fun := makeConstShiftFunc(c, 18, OpLsh, TypeUInt64)
+	fun := makeConstShiftFunc(c, 18, OpLsh64, TypeUInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
-	fun = makeConstShiftFunc(c, 66, OpLsh, TypeUInt64)
+	fun = makeConstShiftFunc(c, 66, OpLsh64, TypeUInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 0, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
-	fun = makeConstShiftFunc(c, 18, OpRsh, TypeUInt64)
+	fun = makeConstShiftFunc(c, 18, OpRsh64U, TypeUInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHRQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
-	fun = makeConstShiftFunc(c, 66, OpRsh, TypeUInt64)
+	fun = makeConstShiftFunc(c, 66, OpRsh64U, TypeUInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHRQconst: 0, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
-	fun = makeConstShiftFunc(c, 18, OpRsh, TypeInt64)
+	fun = makeConstShiftFunc(c, 18, OpRsh64, TypeInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SARQconst: 1, OpAMD64CMPQconst: 0})
-	fun = makeConstShiftFunc(c, 66, OpRsh, TypeInt64)
+	fun = makeConstShiftFunc(c, 66, OpRsh64, TypeInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SARQconst: 1, OpAMD64CMPQconst: 0})
 }
 
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
index 0bd64a1..5f18aca 100644
--- a/src/cmd/compile/internal/ssa/stackalloc.go
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -82,8 +82,8 @@
 		}
 	}
 
-	n = align(n, f.Config.ptrSize)
-	n += f.Config.ptrSize // space for return address.  TODO: arch-dependent
+	n = align(n, f.Config.PtrSize)
+	n += f.Config.PtrSize // space for return address.  TODO: arch-dependent
 	f.RegAlloc = home
 	f.FrameSize = n