OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [testsuite/] [go.test/] [test/] [chan/] [select5.go] - Rev 700

Compare with Previous | Blame | View Log

// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
// $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: select5
// rm -f tmp.go

// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Generate test of channel operations and simple selects.
// Only doing one real send or receive at a time, but phrased
// in various ways that the compiler may or may not rewrite
// into simpler expressions.

package main

import (
        "bufio"
        "fmt"
        "io"
        "os"
        "text/template"
)

func main() {
        out := bufio.NewWriter(os.Stdout)
        fmt.Fprintln(out, header)
        a := new(arg)

        // Generate each kind of test as a separate function to avoid
        // hitting the 6g optimizer with one enormous function.
        // If we name all the functions init we don't have to
        // maintain a list of which ones to run.
        do := func(t *template.Template) {
                fmt.Fprintln(out, `func init() {`)
                for ; next(); a.reset() {
                        run(t, a, out)
                }
                fmt.Fprintln(out, `}`)
        }

        do(recv)
        do(send)
        do(recvOrder)
        do(sendOrder)
        do(nonblock)

        fmt.Fprintln(out, "//", a.nreset, "cases")
        out.Flush()
}

func run(t *template.Template, a interface{}, out io.Writer) {
        if err := t.Execute(out, a); err != nil {
                panic(err)
        }
}

type arg struct {
        def    bool
        nreset int
}

func (a *arg) Maybe() bool {
        return maybe()
}

func (a *arg) MaybeDefault() bool {
        if a.def {
                return false
        }
        a.def = maybe()
        return a.def
}

func (a *arg) MustDefault() bool {
        return !a.def
}

func (a *arg) reset() {
        a.def = false
        a.nreset++
}

const header = `// GENERATED BY select5.go; DO NOT EDIT

package main

// channel is buffered so test is single-goroutine.
// we are not interested in the concurrency aspects
// of select, just testing that the right calls happen.
var c = make(chan int, 1)
var nilch chan int
var n = 1
var x int
var i interface{}
var dummy = make(chan int)
var m = make(map[int]int)
var order = 0

func f(p *int) *int {
        return p
}

// check order of operations by ensuring that
// successive calls to checkorder have increasing o values.
func checkorder(o int) {
        if o <= order {
                println("invalid order", o, "after", order)
                panic("order")
        }
        order = o
}

func fc(c chan int, o int) chan int {
        checkorder(o)
        return c
}

func fp(p *int, o int) *int {
        checkorder(o)
        return p
}

func fn(n, o int) int {
        checkorder(o)
        return n
}

func die(x int) {
        println("have", x, "want", n)
        panic("chan")
}

func main() {
        // everything happens in init funcs
}
`

func parse(name, s string) *template.Template {
        t, err := template.New(name).Parse(s)
        if err != nil {
                panic(fmt.Sprintf("%q: %s", name, err))
        }
        return t
}

var recv = parse("recv", `
        {{/*  Send n, receive it one way or another into x, check that they match. */}}
        c <- n
        {{if .Maybe}}
        x = <-c
        {{else}}
        select {
        {{/*  Blocking or non-blocking, before the receive. */}}
        {{/*  The compiler implements two-case select where one is default with custom code, */}}
        {{/*  so test the default branch both before and after the send. */}}
        {{if .MaybeDefault}}
        default:
                panic("nonblock")
        {{end}}
        {{/*  Receive from c.  Different cases are direct, indirect, :=, interface, and map assignment. */}}
        {{if .Maybe}}
        case x = <-c:
        {{else}}{{if .Maybe}}
        case *f(&x) = <-c:
        {{else}}{{if .Maybe}}
        case y := <-c:
                x = y
        {{else}}{{if .Maybe}}
        case i = <-c:
                x = i.(int)
        {{else}}
        case m[13] = <-c:
                x = m[13]
        {{end}}{{end}}{{end}}{{end}}
        {{/*  Blocking or non-blocking again, after the receive. */}}
        {{if .MaybeDefault}}
        default:
                panic("nonblock")
        {{end}}
        {{/*  Dummy send, receive to keep compiler from optimizing select. */}}
        {{if .Maybe}}
        case dummy <- 1:
                panic("dummy send")
        {{end}}
        {{if .Maybe}}
        case <-dummy:
                panic("dummy receive")
        {{end}}
        {{/*  Nil channel send, receive to keep compiler from optimizing select. */}}
        {{if .Maybe}}
        case nilch <- 1:
                panic("nilch send")
        {{end}}
        {{if .Maybe}}
        case <-nilch:
                panic("nilch recv")
        {{end}}
        }
        {{end}}
        if x != n {
                die(x)
        }
        n++
`)

var recvOrder = parse("recvOrder", `
        {{/*  Send n, receive it one way or another into x, check that they match. */}}
        {{/*  Check order of operations along the way by calling functions that check */}}
        {{/*  that the argument sequence is strictly increasing. */}}
        order = 0
        c <- n
        {{if .Maybe}}
        {{/*  Outside of select, left-to-right rule applies. */}}
        {{/*  (Inside select, assignment waits until case is chosen, */}}
        {{/*  so right hand side happens before anything on left hand side. */}}
        *fp(&x, 1) = <-fc(c, 2)
        {{else}}{{if .Maybe}}
        m[fn(13, 1)] = <-fc(c, 2)
        x = m[13]
        {{else}}
        select {
        {{/*  Blocking or non-blocking, before the receive. */}}
        {{/*  The compiler implements two-case select where one is default with custom code, */}}
        {{/*  so test the default branch both before and after the send. */}}
        {{if .MaybeDefault}}
        default:
                panic("nonblock")
        {{end}}
        {{/*  Receive from c.  Different cases are direct, indirect, :=, interface, and map assignment. */}}
        {{if .Maybe}}
        case *fp(&x, 100) = <-fc(c, 1):
        {{else}}{{if .Maybe}}
        case y := <-fc(c, 1):
                x = y
        {{else}}{{if .Maybe}}
        case i = <-fc(c, 1):
                x = i.(int)
        {{else}}
        case m[fn(13, 100)] = <-fc(c, 1):
                x = m[13]
        {{end}}{{end}}{{end}}
        {{/*  Blocking or non-blocking again, after the receive. */}}
        {{if .MaybeDefault}}
        default:
                panic("nonblock")
        {{end}}
        {{/*  Dummy send, receive to keep compiler from optimizing select. */}}
        {{if .Maybe}}
        case fc(dummy, 2) <- fn(1, 3):
                panic("dummy send")
        {{end}}
        {{if .Maybe}}
        case <-fc(dummy, 4):
                panic("dummy receive")
        {{end}}
        {{/*  Nil channel send, receive to keep compiler from optimizing select. */}}
        {{if .Maybe}}
        case fc(nilch, 5) <- fn(1, 6):
                panic("nilch send")
        {{end}}
        {{if .Maybe}}
        case <-fc(nilch, 7):
                panic("nilch recv")
        {{end}}
        }
        {{end}}{{end}}
        if x != n {
                die(x)
        }
        n++
`)

var send = parse("send", `
        {{/*  Send n one way or another, receive it into x, check that they match. */}}
        {{if .Maybe}}
        c <- n
        {{else}}
        select {
        {{/*  Blocking or non-blocking, before the receive (same reason as in recv). */}}
        {{if .MaybeDefault}}
        default:
                panic("nonblock")
        {{end}}
        {{/*  Send c <- n.  No real special cases here, because no values come back */}}
        {{/*  from the send operation. */}}
        case c <- n:
        {{/*  Blocking or non-blocking. */}}
        {{if .MaybeDefault}}
        default:
                panic("nonblock")
        {{end}}
        {{/*  Dummy send, receive to keep compiler from optimizing select. */}}
        {{if .Maybe}}
        case dummy <- 1:
                panic("dummy send")
        {{end}}
        {{if .Maybe}}
        case <-dummy:
                panic("dummy receive")
        {{end}}
        {{/*  Nil channel send, receive to keep compiler from optimizing select. */}}
        {{if .Maybe}}
        case nilch <- 1:
                panic("nilch send")
        {{end}}
        {{if .Maybe}}
        case <-nilch:
                panic("nilch recv")
        {{end}}
        }
        {{end}}
        x = <-c
        if x != n {
                die(x)
        }
        n++
`)

var sendOrder = parse("sendOrder", `
        {{/*  Send n one way or another, receive it into x, check that they match. */}}
        {{/*  Check order of operations along the way by calling functions that check */}}
        {{/*  that the argument sequence is strictly increasing. */}}
        order = 0
        {{if .Maybe}}
        fc(c, 1) <- fn(n, 2)
        {{else}}
        select {
        {{/*  Blocking or non-blocking, before the receive (same reason as in recv). */}}
        {{if .MaybeDefault}}
        default:
                panic("nonblock")
        {{end}}
        {{/*  Send c <- n.  No real special cases here, because no values come back */}}
        {{/*  from the send operation. */}}
        case fc(c, 1) <- fn(n, 2):
        {{/*  Blocking or non-blocking. */}}
        {{if .MaybeDefault}}
        default:
                panic("nonblock")
        {{end}}
        {{/*  Dummy send, receive to keep compiler from optimizing select. */}}
        {{if .Maybe}}
        case fc(dummy, 3) <- fn(1, 4):
                panic("dummy send")
        {{end}}
        {{if .Maybe}}
        case <-fc(dummy, 5):
                panic("dummy receive")
        {{end}}
        {{/*  Nil channel send, receive to keep compiler from optimizing select. */}}
        {{if .Maybe}}
        case fc(nilch, 6) <- fn(1, 7):
                panic("nilch send")
        {{end}}
        {{if .Maybe}}
        case <-fc(nilch, 8):
                panic("nilch recv")
        {{end}}
        }
        {{end}}
        x = <-c
        if x != n {
                die(x)
        }
        n++
`)

var nonblock = parse("nonblock", `
        x = n
        {{/*  Test various combinations of non-blocking operations. */}}
        {{/*  Receive assignments must not edit or even attempt to compute the address of the lhs. */}}
        select {
        {{if .MaybeDefault}}
        default:
        {{end}}
        {{if .Maybe}}
        case dummy <- 1:
                panic("dummy <- 1")
        {{end}}
        {{if .Maybe}}
        case nilch <- 1:
                panic("nilch <- 1")
        {{end}}
        {{if .Maybe}}
        case <-dummy:
                panic("<-dummy")
        {{end}}
        {{if .Maybe}}
        case x = <-dummy:
                panic("<-dummy x")
        {{end}}
        {{if .Maybe}}
        case **(**int)(nil) = <-dummy:
                panic("<-dummy (and didn't crash saving result!)")
        {{end}}
        {{if .Maybe}}
        case <-nilch:
                panic("<-nilch")
        {{end}}
        {{if .Maybe}}
        case x = <-nilch:
                panic("<-nilch x")
        {{end}}
        {{if .Maybe}}
        case **(**int)(nil) = <-nilch:
                panic("<-nilch (and didn't crash saving result!)")
        {{end}}
        {{if .MustDefault}}
        default:
        {{end}}
        }
        if x != n {
                die(x)
        }
        n++
`)

// Code for enumerating all possible paths through
// some logic.  The logic should call choose(n) when
// it wants to choose between n possibilities.
// On successive runs through the logic, choose(n)
// will return 0, 1, ..., n-1.  The helper maybe() is
// similar but returns true and then false.
//
// Given a function gen that generates an output
// using choose and maybe, code can generate all
// possible outputs using
//
//      for next() {
//              gen()
//      }

type choice struct {
        i, n int
}

var choices []choice
var cp int = -1

func maybe() bool {
        return choose(2) == 0
}

func choose(n int) int {
        if cp >= len(choices) {
                // never asked this before: start with 0.
                choices = append(choices, choice{0, n})
                cp = len(choices)
                return 0
        }
        // otherwise give recorded answer
        if n != choices[cp].n {
                panic("inconsistent choices")
        }
        i := choices[cp].i
        cp++
        return i
}

func next() bool {
        if cp < 0 {
                // start a new round
                cp = 0
                return true
        }

        // increment last choice sequence
        cp = len(choices) - 1
        for cp >= 0 && choices[cp].i == choices[cp].n-1 {
                cp--
        }
        if cp < 0 {
                choices = choices[:0]
                return false
        }
        choices[cp].i++
        choices = choices[:cp+1]
        cp = 0
        return true
}

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.