in x86/x86spec/parse.go [746:949]
func processListing(p *listing, insts *[]*instruction) {
if debugging {
for _, table := range p.mtables {
fmt.Printf("table:\n")
for _, row := range table {
fmt.Printf("%q\n", row)
}
}
fmt.Printf("enctable:\n")
for _, table := range p.enctables {
for _, row := range table {
fmt.Printf("%q\n", row)
}
}
fmt.Printf("compat:\n%s", p.compat)
}
if *flagCompat && p.compat != "" {
fmt.Printf("# p.%d: %s\n#\t%s\n", p.pageNum, p.name, strings.Replace(p.compat, "\n", "\n#\t", -1))
}
encs := make(map[string][]string)
for _, table := range p.enctables {
for _, row := range table[1:] {
for len(row) > 1 && (row[len(row)-1] == "NA" || row[len(row)-1] == "" || row[len(row)-1] == " source") {
row = row[:len(row)-1]
}
encs[row[0]] = row[1:]
}
}
var wrong string
for _, table := range p.mtables {
heading := table[0]
for _, row := range table[1:] {
if row[0] == heading[0] && reflect.DeepEqual(row, heading) {
continue
}
if len(row) >= 5 && row[1] == "CMOVG r64, r/m64" && row[3] == "V/N.E." && row[4] == "NA" {
row[3] = "V"
row[4] = "N.E."
}
inst := new(instruction)
inst.page = p.pageNum
inst.compat = strings.Join(strings.Fields(p.compat), " ")
for i, hdr := range heading {
x := row[i]
x = strings.Replace(x, "\n", " ", -1)
switch strings.TrimSpace(hdr) {
default:
wrong = "unexpected header: " + strconv.Quote(hdr)
goto BadTable
case "Opcode/Instruction":
x = row[i]
if strings.HasPrefix(x, "\nVEX") {
x = x[1:]
row[i] = x
}
if strings.Contains(x, "\n/r ") {
x = strings.Replace(x, "\n/r ", " /r ", -1)
row[i] = x
}
if strings.Contains(x, ",\nimm") {
x = strings.Replace(x, ",\nimm", ", imm", -1)
row[i] = x
}
if strings.Count(x, "\n") < 1 {
wrong = "bad Opcode/Instruction pairing: " + strconv.Quote(x)
goto BadTable
}
i := strings.Index(x, "\n")
inst.opcode = x[:i]
inst.syntax = strings.Replace(x[i+1:], "\n", " ", -1)
case "Opcode":
inst.opcode = x
case "Instruction":
inst.syntax = x
case "Op/En":
inst.args = encs[x]
if inst.args == nil && len(encs) == 1 && encs["A"] != nil {
inst.args = encs["A"]
}
// In the December 2015 manual, PREFETCHW says
// encoding A but the table gives encoding M.
if inst.args == nil && inst.syntax == "PREFETCHW m8" && x == "A" && len(encs) == 1 && encs["M"] != nil {
inst.args = encs["M"]
}
case "64-Bit Mode":
x, ok := parseMode(x)
if !ok {
wrong = "unexpected value for 64-Bit Mode column: " + x
goto BadTable
}
inst.valid64 = x
case "Compat/Leg Mode":
x, ok := parseMode(x)
if !ok {
wrong = "unexpected value for Compat/Leg Mode column: " + x
goto BadTable
}
inst.valid32 = x
case "64/32-Bit Mode":
i := strings.Index(x, "/")
if i < 0 {
wrong = "unexpected value for 64/32-Bit Mode column: " + x
goto BadTable
}
x1, ok1 := parseMode(x[:i])
x2, ok2 := parseMode(x[i+1:])
if !ok1 || !ok2 {
wrong = "unexpected value for 64/32-Bit Mode column: " + x
goto BadTable
}
inst.valid64 = x1
inst.valid32 = x2
case "CPUID Feature Flag":
inst.cpuid = x
case "Description":
if inst.desc != "" {
inst.desc += " "
}
inst.desc += x
}
}
// Fixup various typos or bugs in opcode descriptions.
if inst.opcode == "VEX.128.66.0F.W0 6E /" {
inst.opcode += "r"
}
fix := func(old, new string) {
inst.opcode = strings.Replace(inst.opcode, old, new, -1)
}
fix(" imm8", " ib")
fix("REX.w", "REX.W")
fix("REX.W+", "REX.W +")
fix(" 0f ", " 0F ")
fix(". 0F38", ".0F38")
fix("0F .WIG", "0F.WIG")
fix("0F38 .WIG", "0F38.WIG")
fix("NDS .LZ", "NDS.LZ")
fix("58+ r", "58+r")
fix("B0+ ", "B0+")
fix("B8+ ", "B8+")
fix("40+ ", "40+")
fix("*", "")
fix(",", " ")
fix("/", " /")
fix("REX.W +", "REX.W")
fix("REX +", "REX")
fix("REX 0F BE", "REX.W 0F BE")
fix("REX 0F B2", "REX.W 0F B2")
fix("REX 0F B4", "REX.W 0F B4")
fix("REX 0F B5", "REX.W 0F B5")
fix("0F38.0", "0F38.W0")
fix(".660F.", ".66.0F.")
fix("VEX128", "VEX.128")
fix("0F3A.W0.1D", "0F3A.W0 1D")
inst.opcode = strings.Join(strings.Fields(inst.opcode), " ")
fix = func(old, new string) {
inst.syntax = strings.Replace(inst.syntax, old, new, -1)
}
fix("xmm1 xmm2", "xmm1, xmm2")
fix("r16/m16", "r/m16")
fix("r32/m161", "r32/m16") // really r32/m16¹ (footnote)
fix("r32/m32", "r/m32")
fix("r64/m64", "r/m64")
fix("\u2013", "-")
fix("mm3 /m", "mm3/m")
fix("mm3/.m", "mm3/m")
inst.syntax = joinSyntax(splitSyntax(inst.syntax))
fix = func(old, new string) {
inst.cpuid = strings.Replace(inst.cpuid, old, new, -1)
}
fix("PCLMUL- QDQ", "PCLMULQDQ")
fix("PCL- MULQDQ", "PCLMULQDQ")
fix("Both PCLMULQDQ and AVX flags", "PCLMULQDQ+AVX")
if !instBlacklist[inst.syntax] {
*insts = append(*insts, inst)
}
}
}
return
BadTable:
fmt.Fprintf(os.Stderr, "p.%d: reading %v: %v\n", p.pageNum, p.name, wrong)
for _, table := range p.mtables {
for _, t := range table {
fmt.Fprintf(os.Stderr, "\t%q\n", t)
}
}
fmt.Fprintf(os.Stderr, "\n")
}