func add()

in arm/armmap/map.go [133:408]


func add(p *Prog, maskstr, valuestr, text, encoding, tags string) {
	if strings.Contains(tags, "pseudo") {
		return
	}

	// For now, ignore the VFP floating point instructions.
	if strings.HasPrefix(text, "V") && !strings.Contains(tags, "vfp") {
		// TODO
		return
	}

	mask, err := strconv.ParseUint(maskstr, 0, 32)
	if err != nil {
		log.Printf("invalid mask %q", maskstr)
		return
	}
	value, err := strconv.ParseUint(valuestr, 0, 32)
	if err != nil {
		log.Printf("invalid value %q", valuestr)
		return
	}

	// Parse encoding, building size and offset of each field.
	// The first field in the encoding is the largest offset.
	fuzzy := uint32(0) // mask of 'should be' bits
	fieldOffset := map[string]int{}
	fieldWidth := map[string]int{}
	off := 32
	for _, f := range strings.Split(encoding, "|") {
		n := 1
		if i := strings.Index(f, ":"); i >= 0 {
			n, _ = strconv.Atoi(f[i+1:])
		}
		off -= n
		fieldOffset[f] = off
		fieldWidth[f] = n
		if f == "(0)" || f == "(1)" {
			fuzzy |= 1 << uint(off)
		}
	}
	if off != 0 {
		fmt.Fprintf(os.Stderr, "%s: counted %d bits in %s\n", text, 32-off, encoding)
	}

	// Track which encoding fields we found uses for.
	// If we do not find a use for a field, that's an error in the input tables.
	fieldUsed := map[string]bool{}

	// Split text into opcode and arguments.
	var op, argstr string
	if i := strings.Index(text, " "); i >= 0 {
		op = text[:i]
		argstr = text[i:]
	} else {
		op = text
	}
	op = strings.TrimSpace(op)
	argstr = strings.TrimSpace(argstr)

	// Parse opcode suffixes.
	i := strings.Index(op, "<")
	if i < 0 {
		i = len(op)
	}
	if j := strings.Index(op, "{"); j >= 0 && j < i {
		i = j
	}
	op, suffix := op[:i], op[i:]
	if suffix != "" && opSuffix[suffix] == "" {
		fmt.Fprintf(os.Stderr, "%s: invalid op suffix %q in %s\n", text, suffix, op+suffix)
	}

	// Make sure fields needed by opcode suffix are available.
	for _, f := range strings.Split(opSuffix[suffix], ",") {
		if f != "" && fieldWidth[f] == 0 {
			fmt.Fprintf(os.Stderr, "%s: opsuffix %s missing %s in encoding %s\n", text, suffix, f, encoding)
		}
		fieldUsed[f] = true
	}

	// Build list of opcodes that can be generated by this suffix.
	// For example, the opcodes generated by ADD<c> are ADD.EQ, ADD.NE, etc.
	// To simplify the decoding of instruction opcodes, we arrange that this
	// sequence aligns with the encoding, so that decoding amounts to extracting
	// the right bits, concatenating them, and adding them to the first opcode in
	// the sequence. If the condition code is present, we always place it in the
	// low order bits, so that x&^15 == FOO_EQ tests whether x is any of the
	// conditional FOO instructions.
	ops := []string{op}
	opBits := uint64(0) // record of bits to extract and add to opcode base
	opFields := strings.Split(opSuffix[suffix], ",")
	// First the optional elements, like {S} meaning "" or ".S".
	for strings.HasPrefix(suffix, "{") {
		i := strings.Index(suffix, "}")
		var f, option string
		option, suffix = suffix[1:i], suffix[i+1:]
		f, opFields = opFields[0], opFields[1:]
		if option == "W" {
			// The {W} option on PLD{W} uses the R bit which is !W.
			ops = cross(ops, "."+option, "")
		} else {
			ops = cross(ops, "", "."+option)
		}
		if fieldWidth[f] != 1 {
			fmt.Fprintf(os.Stderr, "%s: have %d bits for {%s}\n", text, fieldWidth[f], option)
		}
		// opBits is a sequence of 16-bit chunks describing contiguous bit sections.
		// Each chunk is 8-bit offset followed by 8-bit size.
		opBits = opBits<<16 | uint64(fieldOffset[f])<<8 | 1
	}
	// Then the true field substitutions.
	haveCond := false
	for strings.Contains(suffix, "<") {
		var f, literal, x string
		if len(opFields) == 0 {
			fmt.Fprintf(os.Stderr, "%s: ran out of suffix fields for <%s>\n", text, x)
			break
		}
		f, opFields = opFields[0], opFields[1:]
		i := strings.Index(suffix, "<")
		j := strings.Index(suffix, ">")
		literal, x, suffix = suffix[:i], suffix[i+1:j], suffix[j+1:]

		// Add leading literal text to all opcodes.
		ops = cross(ops, literal)

		// The <c> condition can happen anywhere in the opcode text
		// but we want to generate the actual variation in the low bits
		// of the list index. Remember when and where we've seen <c> and apply
		// it after the loop has finished.
		if x == "c" && f == "cond:4" {
			haveCond = true
			ops = cross(ops, "_COND_")
			continue
		}

		// Otherwise, choices[x] lists the possible expansions of <x>.
		// If <x> is of the form <A,B,C> the choices are A, B, and C.
		expand := choices[x]
		if expand == nil && strings.Contains(x, ",") {
			expand = strings.Split(x, ",")
		}
		if expand == nil {
			fmt.Fprintf(os.Stderr, "%s: unknown choices for <%s>\n", text, x)
			expand = []string{x}
		} else if len(expand) != 1<<uint(fieldWidth[f]) {
			fmt.Fprintf(os.Stderr, "%s: have %d choices for <%s> but %d bits\n", text, len(expand), x, fieldWidth[f])
		}
		opBits = opBits<<16 | uint64(fieldOffset[f])<<8 | uint64(fieldWidth[f])
		ops = cross(ops, expand...)
	}
	if haveCond {
		// Apply condtional suffix last.
		opBits = opBits<<16 | 28<<8 | 4
		ops = crossCond(ops)
	}
	ops = cross(ops, suffix)

	// Now ops is a list of opcodes generated by this opcode pattern.
	// We want to make sure that we can arrange for those opcodes to
	// happen consecutively in the final opcode numbering.
	// Record in p.OpRanges[op] the required consecutive sequence of
	// opcode that includes op. To make searches easier, we record
	// the sequence as a comma-separated list of strings with commas
	// on both ends: [A, B] encodes as ",A,B,".
	if p.OpRanges == nil {
		p.OpRanges = make(map[string]string)
	}
	opstr := "," + strings.Join(ops, ",") + ","
	for _, op := range ops {
		if old := p.OpRanges[op]; old != "" && old != opstr {
			if strings.Contains(old, opstr) {
				opstr = old
			} else if strings.Contains(opstr, old) {
				// great, do nothing
			} else {
				// It would also be okay if there is some subsequence s such that
				// old = x+s and opstr = s+y (or vice versa), in which case we should
				// record opstr = x+s+y. However, this has not come up in practice.
				// Failing that, we can't satisfy the sequencing requirements.
				fmt.Fprintf(os.Stderr, "%s: %s appears in both %s and %s\n", text, op, old, opstr)
			}
		}
	}
	for _, op := range strings.Split(opstr, ",") {
		if op != "" {
			p.OpRanges[op] = opstr
		}
	}

	// Process the arguments, building a list of argument descriptions.
	// Each argument description has the form <argument>|field@off|field@off...
	// where the |field@off suffixes give the name and location of the fields
	// needed by the argument. Each such string maps to a different decoding
	// type in the generated table, according to the argOps map.
	var args []string
	for argstr != "" {
		// Find longest match among argSuffixes pieces.
		best := 0
		for a := range argSuffixes {
			if argstr == a || strings.HasPrefix(argstr, a+",") {
				if best < len(a) {
					best = len(a)
				}
			}
		}
		if best == 0 {
			fmt.Fprintf(os.Stderr, "%s: unknown arg %s\n", text, argstr)
			break
		}

		var arg, desc string
		arg, argstr = argstr[:best], strings.TrimSpace(strings.TrimLeft(argstr[best:], ","))
		desc = arg
		for _, f := range strings.Split(argSuffixes[desc], ",") {
			if f == "" {
				continue
			}
			if fieldWidth[f] == 0 {
				fmt.Fprintf(os.Stderr, "%s: arg %s missing %s in encoding %s\n", text, arg, f, encoding)
			}
			fieldUsed[f] = true
			desc += fmt.Sprintf("|%s@%d", f, fieldOffset[f])
		}
		args = append(args, desc)
	}

	// Check that all encoding fields were used by suffix or argument decoding.
	for f := range fieldWidth {
		switch f {
		case "0", "1", "(0)", "(1)":
			// ok
		default:
			if !fieldUsed[f] {
				fmt.Fprintf(os.Stderr, "%s: encoding field %s not used in %s\n", text, f, encoding)
			}
		}
	}

	// Determine decoding priority. Instructions that say 'SEE X' in the tag
	// are considered lower priority than ones that don't. In theory the
	// structure described by the SEE tags might be richer than that, but
	// in practice it only has those two levels.
	// We leave space for two more priorities according to whether the
	// fuzzy bits are set correctly. The full set of priorities then is:
	//
	//	4 - no SEE tag, fuzzy bits all match
	//	3 - no SEE tag, some fuzzy bits don't match
	//	2 - SEE tag, fuzzy bits all match
	//	1 - SEE tag, some fuzzy bits don't match
	//
	// You could argue for swapping the middle two levels but so far
	// it has not been an issue.
	pri := 4
	if strings.Contains(tags, "SEE") {
		pri = 2
	}

	inst := Inst{
		Text:     text,
		Encoding: encoding,
		Mask:     uint32(mask),
		Value:    uint32(value),
		Priority: pri,
		OpBase:   ops[0],
		OpBits:   opBits,
		Args:     args,
	}
	p.Inst = append(p.Inst, inst)

	if fuzzy != 0 {
		inst.Mask &^= fuzzy
		inst.Priority--
		p.Inst = append(p.Inst, inst)
	}
}