Source file src/cmd/compile/internal/ssarewrite/rewritearm64/arm64_helpers.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 rewritearm64
     6  
     7  import (
     8  	"math/bits"
     9  
    10  	"cmd/compile/internal/ssa"
    11  	"cmd/compile/internal/ssa/ssaop"
    12  )
    13  
    14  // returns the bitfield width of mask >> rshift for arm64 bitfield ops.
    15  func arm64BFWidth(mask, rshift int64) int64 {
    16  	shiftedMask := int64(uint64(mask) >> uint64(rshift))
    17  	if shiftedMask == 0 {
    18  		panic("ARM64 BF mask is zero")
    19  	}
    20  	return nto(shiftedMask)
    21  }
    22  
    23  // arm64Invert evaluates (InvertFlags op), which
    24  // is the same as altering the condition codes such
    25  // that the same result would be produced if the arguments
    26  // to the flag-generating instruction were reversed, e.g.
    27  // (InvertFlags (CMP x y)) -> (CMP y x)
    28  func arm64Invert(op ssaop.Op) ssaop.Op {
    29  	switch op {
    30  	case ssaop.OpARM64LessThan:
    31  		return ssaop.OpARM64GreaterThan
    32  	case ssaop.OpARM64LessThanU:
    33  		return ssaop.OpARM64GreaterThanU
    34  	case ssaop.OpARM64GreaterThan:
    35  		return ssaop.OpARM64LessThan
    36  	case ssaop.OpARM64GreaterThanU:
    37  		return ssaop.OpARM64LessThanU
    38  	case ssaop.OpARM64LessEqual:
    39  		return ssaop.OpARM64GreaterEqual
    40  	case ssaop.OpARM64LessEqualU:
    41  		return ssaop.OpARM64GreaterEqualU
    42  	case ssaop.OpARM64GreaterEqual:
    43  		return ssaop.OpARM64LessEqual
    44  	case ssaop.OpARM64GreaterEqualU:
    45  		return ssaop.OpARM64LessEqualU
    46  	case ssaop.OpARM64Equal, ssaop.OpARM64NotEqual:
    47  		return op
    48  	case ssaop.OpARM64LessThanF:
    49  		return ssaop.OpARM64GreaterThanF
    50  	case ssaop.OpARM64GreaterThanF:
    51  		return ssaop.OpARM64LessThanF
    52  	case ssaop.OpARM64LessEqualF:
    53  		return ssaop.OpARM64GreaterEqualF
    54  	case ssaop.OpARM64GreaterEqualF:
    55  		return ssaop.OpARM64LessEqualF
    56  	case ssaop.OpARM64NotLessThanF:
    57  		return ssaop.OpARM64NotGreaterThanF
    58  	case ssaop.OpARM64NotGreaterThanF:
    59  		return ssaop.OpARM64NotLessThanF
    60  	case ssaop.OpARM64NotLessEqualF:
    61  		return ssaop.OpARM64NotGreaterEqualF
    62  	case ssaop.OpARM64NotGreaterEqualF:
    63  		return ssaop.OpARM64NotLessEqualF
    64  	default:
    65  		panic("unreachable")
    66  	}
    67  }
    68  
    69  // arm64Negate finds the complement to an ARM64 condition code,
    70  // for example !Equal -> NotEqual or !LessThan -> GreaterEqual
    71  //
    72  // For floating point, it's more subtle because NaN is unordered. We do
    73  // !LessThanF -> NotLessThanF, the latter takes care of NaNs.
    74  func arm64Negate(op ssaop.Op) ssaop.Op {
    75  	switch op {
    76  	case ssaop.OpARM64LessThan:
    77  		return ssaop.OpARM64GreaterEqual
    78  	case ssaop.OpARM64LessThanU:
    79  		return ssaop.OpARM64GreaterEqualU
    80  	case ssaop.OpARM64GreaterThan:
    81  		return ssaop.OpARM64LessEqual
    82  	case ssaop.OpARM64GreaterThanU:
    83  		return ssaop.OpARM64LessEqualU
    84  	case ssaop.OpARM64LessEqual:
    85  		return ssaop.OpARM64GreaterThan
    86  	case ssaop.OpARM64LessEqualU:
    87  		return ssaop.OpARM64GreaterThanU
    88  	case ssaop.OpARM64GreaterEqual:
    89  		return ssaop.OpARM64LessThan
    90  	case ssaop.OpARM64GreaterEqualU:
    91  		return ssaop.OpARM64LessThanU
    92  	case ssaop.OpARM64Equal:
    93  		return ssaop.OpARM64NotEqual
    94  	case ssaop.OpARM64NotEqual:
    95  		return ssaop.OpARM64Equal
    96  	case ssaop.OpARM64LessThanF:
    97  		return ssaop.OpARM64NotLessThanF
    98  	case ssaop.OpARM64NotLessThanF:
    99  		return ssaop.OpARM64LessThanF
   100  	case ssaop.OpARM64LessEqualF:
   101  		return ssaop.OpARM64NotLessEqualF
   102  	case ssaop.OpARM64NotLessEqualF:
   103  		return ssaop.OpARM64LessEqualF
   104  	case ssaop.OpARM64GreaterThanF:
   105  		return ssaop.OpARM64NotGreaterThanF
   106  	case ssaop.OpARM64NotGreaterThanF:
   107  		return ssaop.OpARM64GreaterThanF
   108  	case ssaop.OpARM64GreaterEqualF:
   109  		return ssaop.OpARM64NotGreaterEqualF
   110  	case ssaop.OpARM64NotGreaterEqualF:
   111  		return ssaop.OpARM64GreaterEqualF
   112  	default:
   113  		panic("unreachable")
   114  	}
   115  }
   116  
   117  // evaluate an ARM64 op against a flags value
   118  // that is potentially constant; return 1 for true,
   119  // -1 for false, and 0 for not constant.
   120  func ccARM64Eval(op ssaop.Op, flags *ssa.Value) int {
   121  	fop := flags.Op
   122  	if fop == ssaop.OpARM64InvertFlags {
   123  		return -ccARM64Eval(op, flags.Args[0])
   124  	}
   125  	if fop != ssaop.OpARM64FlagConstant {
   126  		return 0
   127  	}
   128  	fc := ssa.FlagConstant(flags.AuxInt)
   129  	b2i := func(b bool) int {
   130  		if b {
   131  			return 1
   132  		}
   133  		return -1
   134  	}
   135  	switch op {
   136  	case ssaop.OpARM64Equal:
   137  		return b2i(fc.Eq())
   138  	case ssaop.OpARM64NotEqual:
   139  		return b2i(fc.Ne())
   140  	case ssaop.OpARM64LessThan:
   141  		return b2i(fc.Lt())
   142  	case ssaop.OpARM64LessThanU:
   143  		return b2i(fc.Ult())
   144  	case ssaop.OpARM64GreaterThan:
   145  		return b2i(fc.Gt())
   146  	case ssaop.OpARM64GreaterThanU:
   147  		return b2i(fc.Ugt())
   148  	case ssaop.OpARM64LessEqual:
   149  		return b2i(fc.Le())
   150  	case ssaop.OpARM64LessEqualU:
   151  		return b2i(fc.Ule())
   152  	case ssaop.OpARM64GreaterEqual:
   153  		return b2i(fc.Ge())
   154  	case ssaop.OpARM64GreaterEqualU:
   155  		return b2i(fc.Uge())
   156  	}
   157  	return 0
   158  }
   159  
   160  // checks if mask >> rshift applied at lsb is a valid arm64 bitfield op mask.
   161  func isARM64BFMask(lsb, mask, rshift int64) bool {
   162  	shiftedMask := int64(uint64(mask) >> uint64(rshift))
   163  	return shiftedMask != 0 && ssa.IsPowerOfTwo(shiftedMask+1) && nto(shiftedMask)+lsb < 64
   164  }
   165  
   166  // nto returns the number of trailing ones.
   167  func nto(x int64) int64 {
   168  	return int64(ssa.Ntz64(^x))
   169  }
   170  
   171  func rotateRight64(v, rotate int64) int64 {
   172  	return int64(bits.RotateLeft64(uint64(v), int(-rotate)))
   173  }
   174  

View as plain text