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
5package s390x
6
7import (
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.
30type 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.
42func 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.
61func (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.
68func (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).
76func (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.
84func (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.
113func (r RotateParams) InMerge(mask uint64) *RotateParams {
114	return r.OutMerge(bits.RotateLeft64(mask, int(r.Amount)))
115}
116
117func (RotateParams) CanBeAnSSAAux() {}
118