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() {} 118