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  }