// Copyright 2017 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 ssa

import (
	"cmd/compile/internal/types"
	"cmd/internal/src"
	"testing"
)

func TestLoopConditionS390X(t *testing.T) {
	// Test that a simple loop condition does not generate a conditional
	// move (issue #19227).
	//
	// MOVDLT is generated when Less64 is lowered but should be
	// optimized into an LT branch.
	//
	// For example, compiling the following loop:
	//
	//   for i := 0; i < N; i++ {
	//     sum += 3
	//   }
	//
	// should generate assembly similar to:
	//   loop:
	//     CMP    R0, R1
	//     BGE    done
	//     ADD    $3, R4
	//     ADD    $1, R1
	//     BR     loop
	//   done:
	//
	// rather than:
	// loop:
	//     MOVD   $0, R2
	//     MOVD   $1, R3
	//     CMP    R0, R1
	//     MOVDLT R2, R3
	//     CMPW   R2, $0
	//     BNE    done
	//     ADD    $3, R4
	//     ADD    $1, R1
	//     BR     loop
	//   done:
	//
	c := testConfigS390X(t)
	fun := c.Fun("entry",
		Bloc("entry",
			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
			Valu("SP", OpSP, c.config.Types.UInt64, 0, nil),
			Valu("ret", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "SP"),
			Valu("N", OpArg, c.config.Types.Int64, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)),
			Valu("starti", OpConst64, c.config.Types.Int64, 0, nil),
			Valu("startsum", OpConst64, c.config.Types.Int64, 0, nil),
			Goto("b1")),
		Bloc("b1",
			Valu("phii", OpPhi, c.config.Types.Int64, 0, nil, "starti", "i"),
			Valu("phisum", OpPhi, c.config.Types.Int64, 0, nil, "startsum", "sum"),
			Valu("cmp1", OpLess64, c.config.Types.Bool, 0, nil, "phii", "N"),
			If("cmp1", "b2", "b3")),
		Bloc("b2",
			Valu("c1", OpConst64, c.config.Types.Int64, 1, nil),
			Valu("i", OpAdd64, c.config.Types.Int64, 0, nil, "phii", "c1"),
			Valu("c3", OpConst64, c.config.Types.Int64, 3, nil),
			Valu("sum", OpAdd64, c.config.Types.Int64, 0, nil, "phisum", "c3"),
			Goto("b1")),
		Bloc("b3",
			Valu("retdef", OpVarDef, types.TypeMem, 0, nil, "mem"),
			Valu("store", OpStore, types.TypeMem, 0, c.config.Types.Int64, "ret", "phisum", "retdef"),
			Exit("store")))
	CheckFunc(fun.f)
	Compile(fun.f)
	CheckFunc(fun.f)

	checkOpcodeCounts(t, fun.f, map[Op]int{
		OpS390XMOVDLT:    0,
		OpS390XMOVDGT:    0,
		OpS390XMOVDLE:    0,
		OpS390XMOVDGE:    0,
		OpS390XMOVDEQ:    0,
		OpS390XMOVDNE:    0,
		OpS390XCMP:       1,
		OpS390XCMPWconst: 0,
	})
}
