Home | History | Annotate | Download | only in ssa
      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.UInt64, 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.UInt64, 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