Joint hacking with josharian. Hints from matloob and Todd Neal.
Now with tests, and OROR.
Change-Id: Iff8826fde475691fb72a3eea7396a640b6274af9
Reviewed-on: https://go-review.googlesource.com/12041
Reviewed-by: Keith Randall <khr@golang.org>
a := s.expr(n.Left)
b := s.expr(n.Right)
return s.newValue2(binOpToSSA[n.Op], a.Type, a, b)
+ case OANDAND, OOROR:
+ // To implement OANDAND (and OOROR), we introduce a
+ // new temporary variable to hold the result. The
+ // variable is associated with the OANDAND node in the
+ // s.vars table (normally variables are only
+ // associated with ONAME nodes). We convert
+ // A && B
+ // to
+ // var = A
+ // if var {
+ // var = B
+ // }
+ // Using var in the subsequent block introduces the
+ // necessary phi variable.
+ el := s.expr(n.Left)
+ s.vars[n] = el
+
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.Control = el
+
+ bRight := s.f.NewBlock(ssa.BlockPlain)
+ bResult := s.f.NewBlock(ssa.BlockPlain)
+ if n.Op == OANDAND {
+ addEdge(b, bRight)
+ addEdge(b, bResult)
+ } else if n.Op == OOROR {
+ addEdge(b, bResult)
+ addEdge(b, bRight)
+ }
+
+ s.startBlock(bRight)
+ er := s.expr(n.Right)
+ s.vars[n] = er
+
+ b = s.endBlock()
+ addEdge(b, bResult)
+
+ s.startBlock(bResult)
+ return s.variable(n, n.Type)
// unary ops
case ONOT:
--- /dev/null
+// Copyright 2015 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.
+
+package gc
+
+import (
+ "bytes"
+ "internal/testenv"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func TestShortCircuit(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ var stdout, stderr bytes.Buffer
+ cmd := exec.Command("go", "run", "testdata/short_ssa.go")
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+ if err := cmd.Run(); err != nil {
+ t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr)
+ }
+ if s := stdout.String(); s != "" {
+ t.Errorf("Stdout = %s\nWant empty", s)
+ }
+ if s := stderr.String(); strings.Contains(s, "SSA unimplemented") {
+ t.Errorf("Unimplemented message found in stderr:\n%s", s)
+ }
+}
--- /dev/null
+// compile
+
+// Copyright 2015 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.
+
+// Tests short circuiting.
+
+package main
+
+func and_ssa(arg1, arg2 bool) bool {
+ return arg1 && rightCall(arg2)
+}
+
+func or_ssa(arg1, arg2 bool) bool {
+ return arg1 || rightCall(arg2)
+}
+
+var rightCalled bool
+
+func rightCall(v bool) bool {
+ rightCalled = true
+ return v
+ select {} // hack to prevent inlining
+ panic("unreached")
+}
+
+func testAnd(arg1, arg2, wantRes bool) { testShortCircuit("AND", arg1, arg2, and_ssa, arg1, wantRes) }
+func testOr(arg1, arg2, wantRes bool) { testShortCircuit("OR", arg1, arg2, or_ssa, !arg1, wantRes) }
+
+func testShortCircuit(opName string, arg1, arg2 bool, fn func(bool, bool) bool, wantRightCall, wantRes bool) {
+ rightCalled = false
+ got := fn(arg1, arg2)
+ if rightCalled != wantRightCall {
+ println("failed for", arg1, opName, arg2, "; rightCalled=", rightCalled, "want=", wantRightCall)
+ failed = true
+ }
+ if wantRes != got {
+ println("failed for", arg1, opName, arg2, "; res=", got, "want=", wantRes)
+ failed = true
+ }
+}
+
+var failed = false
+
+func main() {
+ testAnd(false, false, false)
+ testAnd(false, true, false)
+ testAnd(true, false, false)
+ testAnd(true, true, true)
+
+ testOr(false, false, false)
+ testOr(false, true, true)
+ testOr(true, false, true)
+ testOr(true, true, true)
+
+ if failed {
+ panic("failed")
+ }
+}
(MOVBstore ptr (MOVBQSX x) mem) -> (MOVBstore ptr x mem)
(Convert <t> x) && t.IsInteger() && x.Type.IsInteger() -> (Copy x)
+(ConvNop <t> x) && t == x.Type -> (Copy x)
// Lowering shifts
// Note: unsigned shifts need to return 0 if shift amount is >= 64.
fmt.Fprintln(w, f.Type)
printed := make([]bool, f.NumValues())
for _, b := range f.Blocks {
- fmt.Fprintf(w, " b%d:\n", b.ID)
+ fmt.Fprintf(w, " b%d:", b.ID)
+ if len(b.Preds) > 0 {
+ io.WriteString(w, " <-")
+ for _, pred := range b.Preds {
+ fmt.Fprintf(w, " b%d", pred.ID)
+ }
+ }
+ io.WriteString(w, "\n")
n := 0
// print phis first since all value cycles contain a phi
goto end4c8bfe9df26fc5aa2bd76b211792732a
end4c8bfe9df26fc5aa2bd76b211792732a:
;
+ case OpConvNop:
+ // match: (ConvNop <t> x)
+ // cond: t == x.Type
+ // result: (Copy x)
+ {
+ t := v.Type
+ x := v.Args[0]
+ if !(t == x.Type) {
+ goto end6c588ed8aedc7dca8c06b4ada77e3ddd
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.AddArg(x)
+ return true
+ }
+ goto end6c588ed8aedc7dca8c06b4ada77e3ddd
+ end6c588ed8aedc7dca8c06b4ada77e3ddd:
+ ;
case OpConvert:
// match: (Convert <t> x)
// cond: t.IsInteger() && x.Type.IsInteger()