arm64/instgen: add support for register lists

This CL generates CL 763820.

Change-Id: I7d17aebcd80f85796955b02748249cb54468ada4
Reviewed-on: https://go-review.googlesource.com/c/arch/+/763780
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
diff --git a/arm64/instgen/encodings.go b/arm64/instgen/encodings.go
index 08ca665..c6750ae 100644
--- a/arm64/instgen/encodings.go
+++ b/arm64/instgen/encodings.go
@@ -205,7 +205,7 @@
 	`Is the name of the second source scalable vector register, encoded in the "Zm" field.
 bit range mappings:
 Zm: [16:21)
-`: {"encodeZm1621", `return v << 16, true`, "enc_Zm"},
+`: {"encodeZm1621V2", `return v << 16, true`, "enc_Zm"},
 	`Is the name of the second source scalable vector register, encoded in the "Zm" field.
 bit range mappings:
 Zm: [5:10)
@@ -1490,4 +1490,97 @@
 		return 1 << 23, true
 	}
 	return 0, false`, "enc_tszh_tszl"},
+	`For the "Byte" variant: is the vector segment index, in the range 0 to 3, encoded in the "i2" field.
+bit range mappings:
+i2: [22:24)
+`: {"encodeI22224", `if v > 3 {
+		return 0, false
+	}
+	return v << 22, true`, "enc_i2"},
+	`For the "Byte, single register table" variant: is the vector segment index, in the range 0 to 1, encoded in the "i1" field.
+bit range mappings:
+i1: [23:24)
+`: {"encodeI12324B", `if v > 1 {
+		return 0, false
+	}
+	return v << 23, true`, "enc_i1"},
+	`For the "Halfword" variant: is the vector segment index, in the range 0 to 7, encoded in the "i3h:i3l" fields.
+bit range mappings:
+i3h: [22:24)
+i3l: [12:13)
+`: {"encodeI3224I31213", `if v > 7 {
+		return 0, false
+	}
+	return (v&1)<<12 | (v>>1)<<22, true`, "enc_i3h_i3l"},
+	`For the "Halfword, single register table" and "Halfword, two register table" variants: is the vector segment index, in the range 0 to 3, encoded in the "i2" field.
+bit range mappings:
+i2: [22:24)
+`: {"encodeI22224HW", `if v > 3 {
+		return 0, false
+	}
+	return v << 22, true`, "enc_i2"},
+	`Is the name of the first destination scalable predicate register, encoded as "Pd" times 2.
+bit range mappings:
+Pd: [1:4)
+`: {"encodePd14", `if v > 14 {
+		return 0, false
+	}
+	if v&1 != 0 {
+		return 0, false
+	}
+	return v, true`, "enc_Pd"},
+	`Is the name of the first destination scalable predicate register, encoded in the "Pd" field.
+bit range mappings:
+Pd: [0:4)
+`: {"encodePd04", `return v, true`, "enc_Pd"},
+	`Is the name of the first scalable vector register of the source multi-vector group, encoded in the "Zn" field.
+bit range mappings:
+Zn: [5:10)
+`: {"encodeZn510MultiSrc1", `return v << 5, true`, "enc_Zn"},
+	`Is the name of the first table vector register, encoded as "Zn".
+bit range mappings:
+Zn: [5:10)
+`: {"encodeZn510Table1", `return v << 5, true`, "enc_Zn"},
+	`Is the name of the second destination scalable predicate register, encoded as "Pd" times 2 plus 1.
+bit range mappings:
+Pd: [1:4)
+`: {"encodePd14Plus1", `if v&1 == 0 {
+		return 0, false
+	}
+	return v - 1, true`, "enc_Pd"},
+	`Is the name of the second destination scalable predicate register, encoded in the "Pd" field.
+bit range mappings:
+Pd: [0:4)
+`: {"encodePd04Plus1", `// This "second destination" incurs Pd + 1 == v
+	return v - 1, true`, "enc_Pd"},
+	`Is the name of the second scalable vector register of the source multi-vector group, encoded in the "Zn" field.
+bit range mappings:
+Zn: [5:10)
+`: {"encodeZn510MultiSrc2", `return (v - 1) << 5, true`, "enc_Zn"},
+	`Is the name of the second table vector register, encoded as "Zn" plus 1 modulo 32.
+bit range mappings:
+Zn: [5:10)
+`: {"encodeZn510Table2", `return ((v - 1) & 0x1f) << 5, true`, "enc_Zn"},
+	`Is the name of the source scalable vector register, encoded in the "Zm" field.
+bit range mappings:
+Zm: [16:21)
+`: {"encodeZm1621V1", `return v << 16, true`, "enc_Zm"},
+	`Is the name of the table vector register, encoded in the "Zn" field.
+bit range mappings:
+Zn: [5:10)
+`: {"encodeZn510Table3", `return v << 5, true`, "enc_Zn"},
+	`Is the portion index, in the range 0 to 1, encoded in the "i1" field.
+bit range mappings:
+i1: [8:9)
+`: {"encodeI189", `if v > 1 {
+		return 0, false
+	}
+	return v << 8, true`, "enc_i1"},
+	`Is the vector segment index, in the range 0 to 1, encoded in the "i1" field.
+bit range mappings:
+i1: [23:24)
+`: {"encodeI12324", `if v > 1 {
+		return 0, false
+	}
+	return v << 23, true`, "enc_i1"},
 }
diff --git a/arm64/instgen/generator.go b/arm64/instgen/generator.go
index 9f734be..5dbda31 100644
--- a/arm64/instgen/generator.go
+++ b/arm64/instgen/generator.go
@@ -196,17 +196,21 @@
 `
 
 var operandTypeOrders = map[string]int{
-	"AC_ARNG":    0,
-	"AC_PREG":    0,
-	"AC_PREGZ":   0,
-	"AC_PREGZM":  0,
-	"AC_ZREG":    0,
-	"AC_SPZGREG": 1,
-	"AC_VREG":    1,
-	"AC_ARNGIDX": 2,
-	"AC_ZREGIDX": 2,
-	"AC_PREGIDX": 2,
-	"AC_IMM":     3,
+	"AC_ARNG":     0,
+	"AC_PREG":     0,
+	"AC_PREGZ":    0,
+	"AC_PREGZM":   0,
+	"AC_ZREG":     0,
+	"AC_SPZGREG":  1,
+	"AC_VREG":     1,
+	"AC_ARNGIDX":  2,
+	"AC_ZREGIDX":  2,
+	"AC_PREGIDX":  2,
+	"AC_IMM":      3,
+	"AC_REGLIST1": 4,
+	"AC_REGLIST2": 4,
+	"AC_REGLIST3": 4,
+	"AC_REGLIST4": 4,
 }
 
 func readExistingGoOps(aoutPath string) map[string]bool {
@@ -866,9 +870,7 @@
 				log.Fatalf("Unsupported operand type in constructInstance: %s, enc: %s", op.Typ, enc.String())
 			}
 			highFeat = max(highFeat, operandTypeOrders[op.Typ])
-			if op.Typ == "AC_ARNG" || op.Typ == "AC_PREG" || op.Typ == "AC_PREGZM" || op.Typ == "AC_ZREG" {
-				// Operands that takes SVE registers and arrangement.
-
+			generateSVERegOp := func(opName string) (string, string, string, int, string) {
 				var parts []string
 				var isPred bool
 				if strings.Contains(opName, ".") {
@@ -885,66 +887,79 @@
 				if len(parts) > 1 {
 					arrName = strings.TrimSuffix(strings.TrimPrefix(parts[1], "<"), ">")
 				}
-				reg := regMap[regName]
+				resolvedArr := arrName
+				regNameSanitized := strings.TrimRight(regName, "0123456789")
+				reg := regMap[regNameSanitized]
+				if reg == "" {
+					reg = regMap[regName]
+				}
+				var goAsmOp, gnuAsmOp string
+				var regIdx int
 				if arrMap[arrName] || errCase == nil {
 					// Give error case a random mutation to trigger an error.
 					// Variables, needs mutation
 					switch reg {
 					case "Z":
-						regIdx := cachedOrNew(regCache, regName, 32)
+						regIdx = cachedOrNew(regCache, regName, 32)
 						arrIdx := cachedOrNew(arrCache, arrName, len(sveArr))
-						asmOp := fmt.Sprintf("Z%d.%s", regIdx, sveArr[arrIdx])
-						gnuAsmOps = append([]string{asmOp}, gnuAsmOps...)
-						// go operand order is gnu reversed
-						goAsmOps = append(goAsmOps, asmOp)
+						resolvedArr = sveArr[arrIdx]
+						goAsmOp = fmt.Sprintf("Z%d.%s", regIdx, resolvedArr)
+						gnuAsmOp = goAsmOp
 					case "P", "PN":
-						regIdx := cachedOrNew(regCache, regName, 15)
+						regIdx = cachedOrNew(regCache, regName, 15)
 						if isPred {
 							arrIdx := cachedOrNew(arrCache, arrName, len(svePred))
-							// Go use "." for predication, GNU use "/"
-							gnuAsmOps = append([]string{fmt.Sprintf("%s%d/%s", reg, regIdx, svePred[arrIdx])}, gnuAsmOps...)
-							goAsmOps = append(goAsmOps, fmt.Sprintf("%s%d.%s", reg, regIdx, svePred[arrIdx]))
+							resolvedArr = svePred[arrIdx]
+							gnuAsmOp = fmt.Sprintf("%s%d/%s", reg, regIdx, resolvedArr)
+							goAsmOp = fmt.Sprintf("%s%d.%s", reg, regIdx, resolvedArr)
 						} else {
 							arrIdx := cachedOrNew(arrCache, arrName, len(sveArr))
-							asmOp := fmt.Sprintf("%s%d.%s", reg, regIdx, sveArr[arrIdx])
-							gnuAsmOps = append([]string{asmOp}, gnuAsmOps...)
-							goAsmOps = append(goAsmOps, asmOp)
+							resolvedArr = sveArr[arrIdx]
+							goAsmOp = fmt.Sprintf("%s%d.%s", reg, regIdx, resolvedArr)
+							gnuAsmOp = goAsmOp
 						}
 					case "V":
-						regIdx := cachedOrNew(regCache, regName, 32)
+						regIdx = cachedOrNew(regCache, regName, 32)
 						arrIdx := cachedOrNew(arrCache, arrName, len(neonArrGNU))
-						gnuAsmOps = append([]string{fmt.Sprintf("V%d.%s", regIdx, neonArrGNU[arrIdx])}, gnuAsmOps...)
-						goAsmOps = append(goAsmOps, fmt.Sprintf("V%d.%s", regIdx, neonArrGo[arrIdx]))
+						resolvedArr = neonArrGNU[arrIdx]
+						gnuAsmOp = fmt.Sprintf("V%d.%s", regIdx, neonArrGNU[arrIdx])
+						goAsmOp = fmt.Sprintf("V%d.%s", regIdx, neonArrGo[arrIdx])
 					}
 				} else {
 					// Fixed arrangement or predications
+					var dotArr string
 					if arrName != "" {
-						arrName = "." + arrName
+						dotArr = "." + arrName
 					}
 					switch reg {
 					case "Z":
-						regIdx := cachedOrNew(regCache, regName, 32)
-						asmOp := fmt.Sprintf("Z%d%s", regIdx, arrName)
-						gnuAsmOps = append([]string{asmOp}, gnuAsmOps...)
-						goAsmOps = append(goAsmOps, asmOp)
+						regIdx = cachedOrNew(regCache, regName, 32)
+						goAsmOp = fmt.Sprintf("Z%d%s", regIdx, dotArr)
+						gnuAsmOp = goAsmOp
 					case "P", "PN":
-						regIdx := cachedOrNew(regCache, regName, 15)
+						regIdx = cachedOrNew(regCache, regName, 15)
 						if isPred {
 							var arrNameGNU string
 							if arrName != "" {
-								arrNameGNU = "/" + arrName[1:]
+								arrNameGNU = "/" + arrName
 							}
-							gnuAsmOps = append([]string{fmt.Sprintf("%s%d%s", reg, regIdx, arrNameGNU)}, gnuAsmOps...)
-							goAsmOps = append(goAsmOps, fmt.Sprintf("%s%d%s", reg, regIdx, arrName))
+							gnuAsmOp = fmt.Sprintf("%s%d%s", reg, regIdx, arrNameGNU)
+							goAsmOp = fmt.Sprintf("%s%d%s", reg, regIdx, dotArr)
 						} else {
-							asmOp := fmt.Sprintf("%s%d%s", reg, regIdx, arrName)
-							gnuAsmOps = append([]string{asmOp}, gnuAsmOps...)
-							goAsmOps = append(goAsmOps, asmOp)
+							goAsmOp = fmt.Sprintf("%s%d%s", reg, regIdx, dotArr)
+							gnuAsmOp = goAsmOp
 						}
 					case "V":
 						log.Fatalf("Unexpected V with fixed arrangement: %s", opName)
 					}
 				}
+				return goAsmOp, gnuAsmOp, reg, regIdx, resolvedArr
+			}
+
+			if op.Typ == "AC_ARNG" || op.Typ == "AC_PREG" || op.Typ == "AC_PREGZM" || op.Typ == "AC_ZREG" {
+				goAsmOp, gnuAsmOp, _, _, _ := generateSVERegOp(opName)
+				gnuAsmOps = append([]string{gnuAsmOp}, gnuAsmOps...)
+				goAsmOps = append(goAsmOps, goAsmOp)
 			} else if op.Typ == "AC_ARNGIDX" || op.Typ == "AC_ZREGIDX" || op.Typ == "AC_PREGIDX" {
 				// Operands that takes SVE/SIMD registers and arrangement with index.
 				// reg.T[index]
@@ -1108,6 +1123,59 @@
 					goAsmOps = append(goAsmOps, fmt.Sprintf("$%s", imm))
 				}
 				gnuAsmOps = append([]string{fmt.Sprintf("#%s", imm)}, gnuAsmOps...)
+			} else if op.Typ == "AC_REGLIST1" || op.Typ == "AC_REGLIST2" || op.Typ == "AC_REGLIST3" || op.Typ == "AC_REGLIST4" {
+				// Register list, they must be contiguous modulo 32 (16 for P registers).
+				// Only AC_REGLIST2 has a P register variant though.
+				// { <Zn>.<T> }
+				// { <Pd1>.<T>, <Pd2>.<T> }
+				// { <Zn1>.B, <Zn2>.B }
+				// { <Zt1>.B, <Zt2>.B, <Zt3>.B }
+				// { <Zt1>.B, <Zt2>.B, <Zt3>.B, <Zt4>.B }
+				// We can probably reuse the logic for these registers in AC_ARNG case.
+				// In Go, the register list is wrapped around [], while in GNU it's wrapped around {}.
+				nRegs := 1
+				switch op.Typ {
+				case "AC_REGLIST2":
+					nRegs = 2
+				case "AC_REGLIST3":
+					nRegs = 3
+				case "AC_REGLIST4":
+					nRegs = 4
+				}
+
+				// Extract the first operand inside the list.
+				trimmedName := strings.Trim(op.Name, "{} ")
+				parts := strings.Split(trimmedName, ",")
+				firstOp := strings.TrimSpace(parts[0])
+
+				_, _, regPrefix, regIdx, arr := generateSVERegOp(firstOp)
+
+				limit := 32
+				if regPrefix == "P" || regPrefix == "PN" {
+					limit = 16
+				}
+
+				goRegs := []string{}
+				gnuRegs := []string{}
+				for i := 0; i < nRegs; i++ {
+					currIdx := (regIdx + i) % limit
+					var goReg, gnuReg string
+					if arr != "" {
+						goReg = fmt.Sprintf("%s%d.%s", regPrefix, currIdx, arr)
+						gnuReg = goReg
+					} else {
+						goReg = fmt.Sprintf("%s%d", regPrefix, currIdx)
+						gnuReg = goReg
+					}
+					goRegs = append(goRegs, goReg)
+					gnuRegs = append(gnuRegs, gnuReg)
+				}
+
+				goAsmOp := "[" + strings.Join(goRegs, ", ") + "]"
+				gnuAsmOp := "{" + strings.Join(gnuRegs, ", ") + "}"
+
+				goAsmOps = append(goAsmOps, goAsmOp)
+				gnuAsmOps = append([]string{gnuAsmOp}, gnuAsmOps...)
 			}
 		}
 		// Try to assemble the GNU version.
@@ -1157,7 +1225,7 @@
 		}
 		return validCase, errCase
 	}
-	if name == "ADDQP" || name == "ADDSUBP" || name == "SCVTFLT" || name == "UCVTFLT" {
+	if name == "ADDQP" || name == "ADDSUBP" || name == "SCVTFLT" || name == "UCVTFLT" || name == "LUTI6" {
 		// Very new instructions
 		// GNU toolchain 2.45 doesn't know about these instruction yet.
 		todoCase := e2eData{GoOp: enc.GoOp[1:], Asm: fmt.Sprintf("// TODO: %s", name), highFeat: highFeat}
diff --git a/arm64/instgen/xmlspec/parser.go b/arm64/instgen/xmlspec/parser.go
index 0c8194e..2deb524 100644
--- a/arm64/instgen/xmlspec/parser.go
+++ b/arm64/instgen/xmlspec/parser.go
@@ -1060,7 +1060,18 @@
 // This function also checks that the operand has the expected number of elements
 // after resolving the constraints.
 func (op *Operand) resolveConstraints() {
-	insertElmAt := func(idx int, symbol, textExpWithRanges string) {
+	// insertElmAt takes idx as the index in the old op.Elems slice.
+	// we need to keep track of the index shifts brought by prior insertions.
+	insertionHistory := make([]int, expectedElemCount[op.Typ])
+	insertElmAt := func(idx int, symbol, textExpWithRanges string, needOffset bool) {
+		if needOffset {
+			offset := 0
+			for i := range idx {
+				offset += insertionHistory[i]
+			}
+			insertionHistory[idx]++
+			idx += offset
+		}
 		op.Elems = append(op.Elems[:idx], append([]Element{
 			{
 				encodedIn:         "nil",
@@ -1072,7 +1083,7 @@
 	}
 	// Constraint format: COP_<AClass>__<index>_(_<constraintTypes>)*
 	// <AClass> is the operand class, e.g. AC_SPZGREG, AC_IMM, etc.
-	// <index> is the index of the operand in the instruction, e.g. 0, 1, 2, etc.
+	// <index> is the index of the constrained element in the operand, e.g. 0, 1, 2, etc.
 	// <constraintTypes> is the type of the constraint, e.g. ARNG, MODAMT, etc.
 	for _, constraint := range op.constraints {
 		constraint = strings.TrimPrefix(constraint, "COP_")
@@ -1092,53 +1103,39 @@
 		for _, constraintType := range constraintTypes {
 			switch constraintType {
 			case "ARNGB":
-				insertElmAt(index+1, "B", "Check this is a B arrangement")
-				index++
+				insertElmAt(index+1, "B", "Check this is a B arrangement", true)
 			case "ARNGD":
-				insertElmAt(index+1, "D", "Check this is a D arrangement")
-				index++
+				insertElmAt(index+1, "D", "Check this is a D arrangement", true)
 			case "ARNGH":
-				insertElmAt(index+1, "H", "Check this is a H arrangement")
-				index++
+				insertElmAt(index+1, "H", "Check this is a H arrangement", true)
 			case "ARNGQ":
-				insertElmAt(index+1, "Q", "Check this is a Q arrangement")
-				index++
+				insertElmAt(index+1, "Q", "Check this is a Q arrangement", true)
 			case "ARNGS":
-				insertElmAt(index+1, "S", "Check this is a S arrangement")
-				index++
+				insertElmAt(index+1, "S", "Check this is a S arrangement", true)
 			case "R64":
 				// Width constraints are preceeding the element.
-				insertElmAt(index, "X", "Check this is a 64-bit scalar register")
-				index++
+				insertElmAt(index, "X", "Check this is a 64-bit scalar register", true)
 			case "R32":
-				insertElmAt(index, "W", "Check this is a 32-bit scalar register")
-				index++
+				insertElmAt(index, "W", "Check this is a 32-bit scalar register", true)
 			case "LSL1", "LSL2", "LSL3", "LSL4", "SXTW", "UXTW", "MODAMT1", "MODAMT2", "MODAMT3":
 				if acl == "AC_MEMEXT" {
 					switch constraintType {
 					case "LSL1", "LSL2", "LSL3", "LSL4":
-						insertElmAt(index+1, "LSL", "Check this is mod and is LSL")
-						index++
+						insertElmAt(index+1, "LSL", "Check this is mod and is LSL", true)
 					case "UXTW":
-						insertElmAt(index+1, "UXTW", "Check this is mod and is UXTW")
-						index++
+						insertElmAt(index+1, "UXTW", "Check this is mod and is UXTW", true)
 					case "SXTW":
-						insertElmAt(index+1, "SXTW", "Check this is mod and is SXTW")
-						index++
+						insertElmAt(index+1, "SXTW", "Check this is mod and is SXTW", true)
 					}
 					switch constraintType {
 					case "LSL1", "MODAMT1":
-						insertElmAt(index+1, "#1", "Check this is mod amount and is 1")
-						index++
+						insertElmAt(index+1, "#1", "Check this is mod amount and is 1", true)
 					case "LSL2", "MODAMT2":
-						insertElmAt(index+1, "#2", "Check this is mod amount and is 2")
-						index++
+						insertElmAt(index+1, "#2", "Check this is mod amount and is 2", true)
 					case "LSL3", "MODAMT3":
-						insertElmAt(index+1, "#3", "Check this is mod amount and is 3")
-						index++
+						insertElmAt(index+1, "#3", "Check this is mod amount and is 3", true)
 					case "LSL4":
-						insertElmAt(index+1, "#4", "Check this is mod amount and is 4")
-						index++
+						insertElmAt(index+1, "#4", "Check this is mod amount and is 4", true)
 					}
 				} else {
 					log.Printf("Unknown constraint: %s", constraint)
@@ -1155,60 +1152,60 @@
 		case "#0.0":
 			if el == 1 && len(op.Elems) == 0 {
 				op.Elems = make([]Element, 0, 1)
-				insertElmAt(0, "#0.0", "Check this is immediate 0.0")
+				insertElmAt(0, "#0.0", "Check this is immediate 0.0", false)
 				resolved = true
 			}
 		case "#<imm>{, <shift>}":
 			if el == 1 && len(op.Elems) == 2 {
 				// The 2 elements explanation need to be merged
-				insertElmAt(0, "#<imm>{, <shift>}", op.Elems[0].TextExpWithRanges+"\n"+op.Elems[1].TextExpWithRanges)
+				insertElmAt(0, "#<imm>{, <shift>}", op.Elems[0].TextExpWithRanges+"\n"+op.Elems[1].TextExpWithRanges, false)
 				op.Elems = op.Elems[:1]
 				resolved = true
 			}
 		case "<Pd>", "<Pg>", "<Pn>", "<PNg>", "<Pt>", "<Pv>", "<Zd>", "<Zm>", "<Zn>", "<Zt>":
 			if el == 2 && len(op.Elems) == 1 {
-				insertElmAt(1, "nil", noOpCheck)
+				insertElmAt(1, "nil", noOpCheck, false)
 				resolved = true
 			}
 		case "<Dd>":
 			if el == 2 && len(op.Elems) == 1 {
-				insertElmAt(0, "nil", "Check this SIMD vector register is of width 64-bit.")
+				insertElmAt(0, "nil", "Check this SIMD vector register is of width 64-bit.", false)
 				resolved = true
 			}
 		case "<PNg>/Z", "<Pg>/Z":
 			if el == 2 && len(op.Elems) == 1 {
-				insertElmAt(1, "Z", "Check this is a zeroing predication")
+				insertElmAt(1, "Z", "Check this is a zeroing predication", false)
 				resolved = true
 			}
 		case "<Pg>/M", "<Pv>/M":
 			if el == 2 && len(op.Elems) == 1 {
-				insertElmAt(1, "M", "Check this is a merging predication")
+				insertElmAt(1, "M", "Check this is a merging predication", false)
 				resolved = true
 			}
 		case "<PNn>[<imm>]":
 			if el == 3 && len(op.Elems) == 2 {
-				insertElmAt(1, "nil", noOpCheck)
+				insertElmAt(1, "nil", noOpCheck, false)
 				resolved = true
 			}
 		case "<Pd>.<T>{, <pattern>}":
 			if el == 4 && len(op.Elems) == 3 {
-				insertElmAt(3, "nil", noOpCheck)
+				insertElmAt(3, "nil", noOpCheck, false)
 				resolved = true
 			}
 		case "<Zd>{[<imm>]}", "<Zm>[<index>]", "<Zn>{[<imm>]}":
 			if el == 3 && len(op.Elems) == 2 {
-				insertElmAt(1, "nil", noOpCheck)
+				insertElmAt(1, "nil", noOpCheck, false)
 				resolved = true
 			}
 		case "[<Xn|SP>, <Xm>]", "[<Xn|SP>, <Zm>.D]", "[<Xn|SP>{, <Xm>}]", "[<Zn>.D{, <Xm>}]", "[<Zn>.S{, <Xm>}]":
 			if el == 6 && len(op.Elems) == 4 {
-				insertElmAt(4, "nil", noOpCheck)
-				insertElmAt(5, "nil", noOpCheck)
+				insertElmAt(4, "nil", noOpCheck, false)
+				insertElmAt(5, "nil", noOpCheck, false)
 				resolved = true
 			}
 		case "[<Xn|SP>, <Zm>.S, <mod>]", "[<Xn|SP>, <Zm>.D, <mod>]":
 			if el == 6 && len(op.Elems) == 5 {
-				insertElmAt(5, "nil", noOpCheck)
+				insertElmAt(5, "nil", noOpCheck, false)
 				resolved = true
 			}
 		}