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

View as plain text