github.com/aclements/go-misc@v0.0.0-20240129233631-2f6ede80790c/memmodel/outcome.go (about) 1 // Copyright 2016 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 main 6 7 import ( 8 "fmt" 9 "io" 10 ) 11 12 // An Outcome represents the outcomes of all instructions in an 13 // execution. Bit i of an Outcome is set to the result of the load 14 // with ID i. 15 type Outcome uint64 16 17 func init() { 18 if Outcome(1<<MaxTotalOps) == 0 { 19 panic("MaxTotalOps is too large to fit in Outcome") 20 } 21 } 22 23 func (o *Outcome) Set(op Op, result int) { 24 if result != 0 { 25 (*o) |= 1 << op.ID 26 } 27 } 28 29 func (o Outcome) Format(width int) string { 30 var out []byte 31 for l := 0; l < width; l++ { 32 out = append(out, '0'+byte((o>>uint(l))&1)) 33 } 34 return string(out) 35 } 36 37 // An OutcomeSet records the set of permissible outcomes of an 38 // execution. 39 type OutcomeSet struct { 40 bits [(1<<MaxTotalOps + 63) / 64]uint64 41 numLoads int 42 } 43 44 func (b *OutcomeSet) Reset(p *Prog) { 45 b.bits = [(1<<MaxTotalOps + 63) / 64]uint64{} 46 b.numLoads = p.NumLoads 47 } 48 49 func (b *OutcomeSet) Add(o Outcome) { 50 b.bits[o/64] |= 1 << (o % 64) 51 } 52 53 func (b *OutcomeSet) Has(o Outcome) bool { 54 return b.bits[o/64]&(1<<(o%64)) != 0 55 } 56 57 // Contains returns true if every outcome in s2 is contained in s. 58 func (s *OutcomeSet) Contains(s2 *OutcomeSet) bool { 59 for i, bits := range s.bits { 60 if s2.bits[i]&^bits != 0 { 61 return false 62 } 63 } 64 return true 65 } 66 67 // AddAll adds all outcomes in s2 to s. 68 func (s *OutcomeSet) AddAll(s2 *OutcomeSet) { 69 if s.numLoads != s2.numLoads { 70 panic("cannot union OutcomeSets with differing numbers of loads") 71 } 72 for i, bits := range s2.bits { 73 s.bits[i] |= bits 74 } 75 } 76 77 func (b *OutcomeSet) OutcomeIter() <-chan Outcome { 78 ch := make(chan Outcome) 79 go func() { 80 for i, bits := range b.bits { 81 if bits == 0 { 82 continue 83 } 84 for off := uint(0); off < 64; off++ { 85 if bits&(1<<off) == 0 { 86 continue 87 } 88 outcome := Outcome(i*64 + int(off)) 89 ch <- outcome 90 } 91 } 92 close(ch) 93 }() 94 return ch 95 } 96 97 func (b *OutcomeSet) String() string { 98 out := []byte{} 99 for l := 0; l < b.numLoads; l++ { 100 out = append(out, 'a'+byte(l)) 101 } 102 out = append(out, '\n') 103 for outcome := range b.OutcomeIter() { 104 out = append(out, []byte(outcome.Format(b.numLoads))...) 105 } 106 return string(out[:len(out)-1]) 107 } 108 109 func printOutcomeTable(w io.Writer, cols []string, outcomes []OutcomeSet) error { 110 allOutcomes := outcomes[0] 111 for _, o := range outcomes { 112 allOutcomes.AddAll(&o) 113 } 114 115 // Print header. 116 out := []byte{} 117 for l := 0; l < allOutcomes.numLoads; l++ { 118 out = append(out, 'a'+byte(l)) 119 } 120 widths := make([]int, 0, len(cols)) 121 for _, col := range cols { 122 out = append(out, ' ', ' ') 123 out = append(out, []byte(col)...) 124 widths = append(widths, len(col)) 125 } 126 out = append(out, '\n') 127 if _, err := w.Write(out); err != nil { 128 return err 129 } 130 131 // Print rows. 132 for outcome := range allOutcomes.OutcomeIter() { 133 if _, err := fmt.Fprint(w, outcome.Format(allOutcomes.numLoads)); err != nil { 134 return err 135 } 136 var haveY, haveN bool 137 for i := range cols { 138 var ch rune 139 if outcomes[i].Has(outcome) { 140 ch = 'Y' 141 haveY = true 142 } else { 143 ch = 'N' 144 haveN = true 145 } 146 if _, err := fmt.Fprintf(w, " %-*c", widths[i], ch); err != nil { 147 return err 148 } 149 } 150 if haveY && haveN { 151 if _, err := fmt.Fprintf(w, " *"); err != nil { 152 return err 153 } 154 } 155 if _, err := fmt.Fprintf(w, "\n"); err != nil { 156 return err 157 } 158 } 159 160 return nil 161 }