github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/obj/s390x/rotate.go (about)

     1  // Copyright 2019 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 s390x
     6  
     7  import (
     8  	"math/bits"
     9  )
    10  
    11  // RotateParams represents the immediates required for a "rotate
    12  // then ... selected bits instruction".
    13  //
    14  // The Start and End values are the indexes that represent
    15  // the masked region. They are inclusive and are in big-
    16  // endian order (bit 0 is the MSB, bit 63 is the LSB). They
    17  // may wrap around.
    18  //
    19  // Some examples:
    20  //
    21  // Masked region             | Start | End
    22  // --------------------------+-------+----
    23  // 0x00_00_00_00_00_00_00_0f | 60    | 63
    24  // 0xf0_00_00_00_00_00_00_00 | 0     | 3
    25  // 0xf0_00_00_00_00_00_00_0f | 60    | 3
    26  //
    27  // The Amount value represents the amount to rotate the
    28  // input left by. Note that this rotation is performed
    29  // before the masked region is used.
    30  type RotateParams struct {
    31  	Start  uint8 // big-endian start bit index [0..63]
    32  	End    uint8 // big-endian end bit index [0..63]
    33  	Amount uint8 // amount to rotate left
    34  }
    35  
    36  // NewRotateParams creates a set of parameters representing a
    37  // rotation left by the amount provided and a selection of the bits
    38  // between the provided start and end indexes (inclusive).
    39  //
    40  // The start and end indexes and the rotation amount must all
    41  // be in the range 0-63 inclusive or this function will panic.
    42  func NewRotateParams(start, end, amount uint8) RotateParams {
    43  	if start&^63 != 0 {
    44  		panic("start out of bounds")
    45  	}
    46  	if end&^63 != 0 {
    47  		panic("end out of bounds")
    48  	}
    49  	if amount&^63 != 0 {
    50  		panic("amount out of bounds")
    51  	}
    52  	return RotateParams{
    53  		Start:  start,
    54  		End:    end,
    55  		Amount: amount,
    56  	}
    57  }
    58  
    59  // RotateLeft generates a new set of parameters with the rotation amount
    60  // increased by the given value. The selected bits are left unchanged.
    61  func (r RotateParams) RotateLeft(amount uint8) RotateParams {
    62  	r.Amount += amount
    63  	r.Amount &= 63
    64  	return r
    65  }
    66  
    67  // OutMask provides a mask representing the selected bits.
    68  func (r RotateParams) OutMask() uint64 {
    69  	// Note: z must be unsigned for bootstrap compiler
    70  	z := uint8(63-r.End+r.Start) & 63 // number of zero bits in mask
    71  	return bits.RotateLeft64(^uint64(0)<<z, -int(r.Start))
    72  }
    73  
    74  // InMask provides a mask representing the selected bits relative
    75  // to the source value (i.e. pre-rotation).
    76  func (r RotateParams) InMask() uint64 {
    77  	return bits.RotateLeft64(r.OutMask(), -int(r.Amount))
    78  }
    79  
    80  // OutMerge tries to generate a new set of parameters representing
    81  // the intersection between the selected bits and the provided mask.
    82  // If the intersection is unrepresentable (0 or not contiguous) nil
    83  // will be returned.
    84  func (r RotateParams) OutMerge(mask uint64) *RotateParams {
    85  	mask &= r.OutMask()
    86  	if mask == 0 {
    87  		return nil
    88  	}
    89  
    90  	// normalize the mask so that the set bits are left aligned
    91  	o := bits.LeadingZeros64(^mask)
    92  	mask = bits.RotateLeft64(mask, o)
    93  	z := bits.LeadingZeros64(mask)
    94  	mask = bits.RotateLeft64(mask, z)
    95  
    96  	// check that the normalized mask is contiguous
    97  	l := bits.LeadingZeros64(^mask)
    98  	if l+bits.TrailingZeros64(mask) != 64 {
    99  		return nil
   100  	}
   101  
   102  	// update start and end positions (rotation amount remains the same)
   103  	r.Start = uint8(o+z) & 63
   104  	r.End = (r.Start + uint8(l) - 1) & 63
   105  	return &r
   106  }
   107  
   108  // InMerge tries to generate a new set of parameters representing
   109  // the intersection between the selected bits and the provided mask
   110  // as applied to the source value (i.e. pre-rotation).
   111  // If the intersection is unrepresentable (0 or not contiguous) nil
   112  // will be returned.
   113  func (r RotateParams) InMerge(mask uint64) *RotateParams {
   114  	return r.OutMerge(bits.RotateLeft64(mask, int(r.Amount)))
   115  }
   116  
   117  func (RotateParams) CanBeAnSSAAux() {}