Source file src/cmd/compile/internal/ssacompile/shift_test.go

     1  // Copyright 2015 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 ssacompile
     6  
     7  import (
     8  	"testing"
     9  
    10  	"cmd/compile/internal/ssa"
    11  	"cmd/compile/internal/ssa/ssahtml"
    12  	"cmd/compile/internal/ssa/ssaop"
    13  	"cmd/compile/internal/types"
    14  )
    15  
    16  func TestShiftConstAMD64(t *testing.T) {
    17  	c := testConfig(t)
    18  	fun := makeConstShiftFunc(c, 18, ssaop.OpLsh64x64, c.config.Types.UInt64)
    19  	checkOpcodeCounts(t, fun.f, map[ssaop.Op]int{ssaop.OpAMD64SHLQconst: 1, ssaop.OpAMD64CMPQconst: 0, ssaop.OpAMD64ANDQconst: 0})
    20  
    21  	fun = makeConstShiftFunc(c, 66, ssaop.OpLsh64x64, c.config.Types.UInt64)
    22  	checkOpcodeCounts(t, fun.f, map[ssaop.Op]int{ssaop.OpAMD64SHLQconst: 0, ssaop.OpAMD64CMPQconst: 0, ssaop.OpAMD64ANDQconst: 0})
    23  
    24  	fun = makeConstShiftFunc(c, 18, ssaop.OpRsh64Ux64, c.config.Types.UInt64)
    25  	checkOpcodeCounts(t, fun.f, map[ssaop.Op]int{ssaop.OpAMD64SHRQconst: 1, ssaop.OpAMD64CMPQconst: 0, ssaop.OpAMD64ANDQconst: 0})
    26  
    27  	fun = makeConstShiftFunc(c, 66, ssaop.OpRsh64Ux64, c.config.Types.UInt64)
    28  	checkOpcodeCounts(t, fun.f, map[ssaop.Op]int{ssaop.OpAMD64SHRQconst: 0, ssaop.OpAMD64CMPQconst: 0, ssaop.OpAMD64ANDQconst: 0})
    29  
    30  	fun = makeConstShiftFunc(c, 18, ssaop.OpRsh64x64, c.config.Types.Int64)
    31  	checkOpcodeCounts(t, fun.f, map[ssaop.Op]int{ssaop.OpAMD64SARQconst: 1, ssaop.OpAMD64CMPQconst: 0})
    32  
    33  	fun = makeConstShiftFunc(c, 66, ssaop.OpRsh64x64, c.config.Types.Int64)
    34  	checkOpcodeCounts(t, fun.f, map[ssaop.Op]int{ssaop.OpAMD64SARQconst: 1, ssaop.OpAMD64CMPQconst: 0})
    35  }
    36  
    37  func makeConstShiftFunc(c *Conf, amount int64, op ssaop.Op, typ *types.Type) fun {
    38  	ptyp := c.config.Types.BytePtr
    39  	fun := c.Fun("entry",
    40  		Bloc("entry",
    41  			Valu("mem", ssaop.OpInitMem, types.TypeMem, 0, nil),
    42  			Valu("SP", ssaop.OpSP, c.config.Types.Uintptr, 0, nil),
    43  			Valu("argptr", ssaop.OpOffPtr, ptyp, 8, nil, "SP"),
    44  			Valu("resptr", ssaop.OpOffPtr, ptyp, 16, nil, "SP"),
    45  			Valu("load", ssaop.OpLoad, typ, 0, nil, "argptr", "mem"),
    46  			Valu("c", ssaop.OpConst64, c.config.Types.UInt64, amount, nil),
    47  			Valu("shift", op, typ, 0, nil, "load", "c"),
    48  			Valu("store", ssaop.OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "shift", "mem"),
    49  			Exit("store")))
    50  	runPasses(fun.f)
    51  	return fun
    52  }
    53  
    54  func TestShiftToExtensionAMD64(t *testing.T) {
    55  	c := testConfig(t)
    56  	// Test that eligible pairs of constant shifts are converted to extensions.
    57  	// For example:
    58  	//   (uint64(x) << 32) >> 32 -> uint64(uint32(x))
    59  	ops := map[ssaop.Op]int{
    60  		ssaop.OpAMD64SHLQconst: 0, ssaop.OpAMD64SHLLconst: 0,
    61  		ssaop.OpAMD64SHRQconst: 0, ssaop.OpAMD64SHRLconst: 0,
    62  		ssaop.OpAMD64SARQconst: 0, ssaop.OpAMD64SARLconst: 0,
    63  	}
    64  	tests := [...]struct {
    65  		amount      int64
    66  		left, right ssaop.Op
    67  		typ         *types.Type
    68  	}{
    69  		// unsigned
    70  		{56, ssaop.OpLsh64x64, ssaop.OpRsh64Ux64, c.config.Types.UInt64},
    71  		{48, ssaop.OpLsh64x64, ssaop.OpRsh64Ux64, c.config.Types.UInt64},
    72  		{32, ssaop.OpLsh64x64, ssaop.OpRsh64Ux64, c.config.Types.UInt64},
    73  		{24, ssaop.OpLsh32x64, ssaop.OpRsh32Ux64, c.config.Types.UInt32},
    74  		{16, ssaop.OpLsh32x64, ssaop.OpRsh32Ux64, c.config.Types.UInt32},
    75  		{8, ssaop.OpLsh16x64, ssaop.OpRsh16Ux64, c.config.Types.UInt16},
    76  		// signed
    77  		{56, ssaop.OpLsh64x64, ssaop.OpRsh64x64, c.config.Types.Int64},
    78  		{48, ssaop.OpLsh64x64, ssaop.OpRsh64x64, c.config.Types.Int64},
    79  		{32, ssaop.OpLsh64x64, ssaop.OpRsh64x64, c.config.Types.Int64},
    80  		{24, ssaop.OpLsh32x64, ssaop.OpRsh32x64, c.config.Types.Int32},
    81  		{16, ssaop.OpLsh32x64, ssaop.OpRsh32x64, c.config.Types.Int32},
    82  		{8, ssaop.OpLsh16x64, ssaop.OpRsh16x64, c.config.Types.Int16},
    83  	}
    84  	for _, tc := range tests {
    85  		fun := makeShiftExtensionFunc(c, tc.amount, tc.left, tc.right, tc.typ)
    86  		checkOpcodeCounts(t, fun.f, ops)
    87  	}
    88  }
    89  
    90  // makeShiftExtensionFunc generates a function containing:
    91  //
    92  //	(rshift (lshift (Const64 [amount])) (Const64 [amount]))
    93  //
    94  // This may be equivalent to a sign or zero extension.
    95  func makeShiftExtensionFunc(c *Conf, amount int64, lshift, rshift ssaop.Op, typ *types.Type) fun {
    96  	ptyp := c.config.Types.BytePtr
    97  	fun := c.Fun("entry",
    98  		Bloc("entry",
    99  			Valu("mem", ssaop.OpInitMem, types.TypeMem, 0, nil),
   100  			Valu("SP", ssaop.OpSP, c.config.Types.Uintptr, 0, nil),
   101  			Valu("argptr", ssaop.OpOffPtr, ptyp, 8, nil, "SP"),
   102  			Valu("resptr", ssaop.OpOffPtr, ptyp, 16, nil, "SP"),
   103  			Valu("load", ssaop.OpLoad, typ, 0, nil, "argptr", "mem"),
   104  			Valu("c", ssaop.OpConst64, c.config.Types.UInt64, amount, nil),
   105  			Valu("lshift", lshift, typ, 0, nil, "load", "c"),
   106  			Valu("rshift", rshift, typ, 0, nil, "lshift", "c"),
   107  			Valu("store", ssaop.OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "rshift", "mem"),
   108  			Exit("store")))
   109  	runPasses(fun.f)
   110  	return fun
   111  }
   112  
   113  // runPasses is a simplified version of Compile that runs the passes
   114  // for the tests in this file.
   115  func runPasses(f *ssa.Func) {
   116  	for i := range passes {
   117  		p := &passes[i]
   118  		if !f.Config.Optimize && !p.Required || p.Disabled {
   119  			continue
   120  		}
   121  		f.Pass = p
   122  		f.HTMLWriter = (*ssahtml.HTMLWriter)(nil)
   123  		p.Fn(f)
   124  	}
   125  }
   126  

View as plain text