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

View as plain text