github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/ssa/xposmap.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssa 6 7 import ( 8 "fmt" 9 10 "github.com/go-asm/go/cmd/src" 11 ) 12 13 type lineRange struct { 14 first, last uint32 15 } 16 17 // An xposmap is a map from fileindex and line of src.XPos to int32, 18 // implemented sparsely to save space (column and statement status are ignored). 19 // The sparse skeleton is constructed once, and then reused by ssa phases 20 // that (re)move values with statements attached. 21 type xposmap struct { 22 // A map from file index to maps from line range to integers (block numbers) 23 maps map[int32]*biasedSparseMap 24 // The next two fields provide a single-item cache for common case of repeated lines from same file. 25 lastIndex int32 // -1 means no entry in cache 26 lastMap *biasedSparseMap // map found at maps[lastIndex] 27 } 28 29 // newXposmap constructs an xposmap valid for inputs which have a file index in the keys of x, 30 // and line numbers in the range x[file index]. 31 // The resulting xposmap will panic if a caller attempts to set or add an XPos not in that range. 32 func newXposmap(x map[int]lineRange) *xposmap { 33 maps := make(map[int32]*biasedSparseMap) 34 for i, p := range x { 35 maps[int32(i)] = newBiasedSparseMap(int(p.first), int(p.last)) 36 } 37 return &xposmap{maps: maps, lastIndex: -1} // zero for the rest is okay 38 } 39 40 // clear removes data from the map but leaves the sparse skeleton. 41 func (m *xposmap) clear() { 42 for _, l := range m.maps { 43 if l != nil { 44 l.clear() 45 } 46 } 47 m.lastIndex = -1 48 m.lastMap = nil 49 } 50 51 // mapFor returns the line range map for a given file index. 52 func (m *xposmap) mapFor(index int32) *biasedSparseMap { 53 if index == m.lastIndex { 54 return m.lastMap 55 } 56 mf := m.maps[index] 57 m.lastIndex = index 58 m.lastMap = mf 59 return mf 60 } 61 62 // set inserts p->v into the map. 63 // If p does not fall within the set of fileindex->lineRange used to construct m, this will panic. 64 func (m *xposmap) set(p src.XPos, v int32) { 65 s := m.mapFor(p.FileIndex()) 66 if s == nil { 67 panic(fmt.Sprintf("xposmap.set(%d), file index not found in map\n", p.FileIndex())) 68 } 69 s.set(p.Line(), v) 70 } 71 72 // get returns the int32 associated with the file index and line of p. 73 func (m *xposmap) get(p src.XPos) int32 { 74 s := m.mapFor(p.FileIndex()) 75 if s == nil { 76 return -1 77 } 78 return s.get(p.Line()) 79 } 80 81 // add adds p to m, treating m as a set instead of as a map. 82 // If p does not fall within the set of fileindex->lineRange used to construct m, this will panic. 83 // Use clear() in between set/map interpretations of m. 84 func (m *xposmap) add(p src.XPos) { 85 m.set(p, 0) 86 } 87 88 // contains returns whether the file index and line of p are in m, 89 // treating m as a set instead of as a map. 90 func (m *xposmap) contains(p src.XPos) bool { 91 s := m.mapFor(p.FileIndex()) 92 if s == nil { 93 return false 94 } 95 return s.contains(p.Line()) 96 } 97 98 // remove removes the file index and line for p from m, 99 // whether m is currently treated as a map or set. 100 func (m *xposmap) remove(p src.XPos) { 101 s := m.mapFor(p.FileIndex()) 102 if s == nil { 103 return 104 } 105 s.remove(p.Line()) 106 } 107 108 // foreachEntry applies f to each (fileindex, line, value) triple in m. 109 func (m *xposmap) foreachEntry(f func(j int32, l uint, v int32)) { 110 for j, mm := range m.maps { 111 s := mm.size() 112 for i := 0; i < s; i++ { 113 l, v := mm.getEntry(i) 114 f(j, l, v) 115 } 116 } 117 }