1
2
3
4
5 package main
6
7 import (
8 "fmt"
9 "simd/archsimd/_gen/sgutil"
10 "text/template"
11 )
12
13
14
15 type narrowConversion struct {
16 Base string
17 EWidth int
18 Vwidth int
19 OBase string
20 OEWidth int
21 CPU string
22 }
23
24
25 func (c narrowConversion) VType() string {
26 return fmt.Sprintf("%s%dx%d", c.Base, c.EWidth, c.Count())
27 }
28
29
30 func (c narrowConversion) Count() int {
31 return c.Vwidth / c.EWidth
32 }
33
34
35 func (c narrowConversion) OVType() string {
36 return fmt.Sprintf("%s%dx%d", c.OBase, c.OEWidth, c.Vwidth/c.OEWidth)
37 }
38
39
40
41
42
43 func (c narrowConversion) Pack() string {
44 if c.OEWidth == 8 {
45 return fmt.Sprintf("concatSaturateTo%s8", c.OBase)
46 }
47 return fmt.Sprintf("ConcatSaturateTo%s%d", c.OBase, c.OEWidth)
48 }
49
50
51
52
53
54 var truncTemplate = sgutil.TemplateNamed("truncTemplate", `
55 // Emulated, CPU Feature: {{.CPU}}
56 func (x {{.VType}}) TruncTo{{.OBase}}{{.OEWidth}}() (z {{.OVType}}) {
57 {{- if eq .Base "Int"}}
58 return x.ToBits().TruncToUint{{.OEWidth}}().BitsToInt{{.OEWidth}}()
59 {{- else if eq .Vwidth 128}}
60 {{- if eq .EWidth 64}}
61 var zero Uint32x4
62 return x.ReshapeToUint32s().ConcatPermuteScalars(0, 2, 4, 4, zero)
63 {{- else}}
64 return x.ReshapeToUint8s().LookupModOrZero(LoadInt8x16Array(&trunc{{.EWidth}}To{{.OEWidth}}Idx)){{if ne .OEWidth 8}}.ReshapeToUint{{.OEWidth}}s(){{end}}
65 {{- end}}
66 {{- else}}
67 if X86.AVX512() {
68 return x.truncToUint{{.OEWidth}}()
69 }
70 {{- if eq .EWidth 64}}
71 var zero Uint32x8
72 g := x.ReshapeToUint32s().ConcatPermuteScalarsGrouped(0, 2, 4, 4, zero)
73 {{- else}}
74 g := x.ReshapeToUint8s().LookupModOrZeroGrouped(LoadInt8x32Array(&trunc{{.EWidth}}To{{.OEWidth}}GroupedIdx))
75 {{- end}}
76 return gatherLo64(g.ReshapeToUint64s()).ReshapeToUint{{.OEWidth}}s()
77 {{- end}}
78 }
79 `)
80
81
82
83 var saturateTemplate = sgutil.TemplateNamed("saturateTemplate", `
84 // Emulated, CPU Feature: {{.CPU}}
85 func (x {{.VType}}) SaturateTo{{.OBase}}{{.OEWidth}}() (z {{.OVType}}) {
86 {{- if eq .Base "Uint"}}
87 if X86.AVX512() {
88 return x.saturateToUint{{.OEWidth}}()
89 }
90 {{- if eq .EWidth 64}}
91 // x fits in a uint32 if its high 32 bits are zero.
92 var zero {{.VType}}
93 hi := LoadInt64x{{.Count}}Array(&maxUint32x{{.Count}}).ToBits()
94 return x.IfElse(x.ShiftAllRight(32).Equal(zero), hi).TruncToUint32()
95 {{- else}}
96 // After the Min, x is non-negative as an int{{.EWidth}}, so the signed-to-unsigned
97 // saturation doesn't change it.
98 x = x.Min(Load{{.VType}}Array(&maxUint{{.OEWidth}}x{{.Count}}))
99 return x.BitsToInt{{.EWidth}}().SaturateToUint{{.OEWidth}}()
100 {{- end}}
101 {{- else if and (eq .EWidth 64) (eq .OBase "Int")}}
102 if X86.AVX512() {
103 return x.saturateToInt32()
104 }
105 hi, lo := Load{{.VType}}Array(&maxInt32x{{.Count}}), Load{{.VType}}Array(&minInt32x{{.Count}})
106 x = hi.IfElse(x.Greater(hi), x)
107 x = lo.IfElse(x.Less(lo), x)
108 return x.TruncToInt32()
109 {{- else if eq .EWidth 64}}
110 var zero {{.VType}}
111 if X86.AVX512() {
112 return x.Max(zero).ToBits().saturateToUint32()
113 }
114 hi := Load{{.VType}}Array(&maxUint32x{{.Count}})
115 x = x.Masked(x.Greater(zero))
116 x = hi.IfElse(x.Greater(hi), x)
117 return x.ToBits().TruncToUint32()
118 {{- else if eq .Vwidth 128}}
119 var zero {{.VType}}
120 return x.{{.Pack}}(zero)
121 {{- else if eq .OBase "Int"}}
122 if X86.AVX512() {
123 return x.saturateToInt{{.OEWidth}}()
124 }
125 var zero {{.VType}}
126 g := x.{{.Pack}}Grouped(zero)
127 return gatherLo64(g.ToBits().ReshapeToUint64s()).ReshapeToUint{{.OEWidth}}s().BitsToInt{{.OEWidth}}()
128 {{- else}}
129 var zero {{.VType}}
130 g := x.{{.Pack}}Grouped(zero)
131 return gatherLo64(g.ReshapeToUint64s()).ReshapeToUint{{.OEWidth}}s()
132 {{- end}}
133 }
134 `)
135
136
137
138
139
140 var saturateSignedToUnsignedTemplate = sgutil.TemplateNamed("saturateSignedToUnsignedTemplate", `
141 // Emulated, CPU Feature: {{.CPU}}
142 func (x {{.VType}}) SaturateToUint{{.OEWidth}}() (z {{.OVType}}) {
143 var zero {{.VType}}
144 return x.Max(zero).ToBits().SaturateToUint{{.OEWidth}}()
145 }
146 `)
147
148
149
150 func narrowConversions(filename string) {
151 buf := files.NewGoFile(filename)
152 prologue("tmplgen", "amd64", buf)
153 exec := func(t *template.Template, c narrowConversion) {
154 if err := t.Execute(buf, c); err != nil {
155 panic(fmt.Errorf("template execute failed, %v", err))
156 }
157 }
158 cpu := map[int]string{128: "AVX", 256: "AVX2"}
159 for _, vw := range []int{128, 256} {
160 for _, w := range []int{16, 32, 64} {
161 for _, base := range []string{"Int", "Uint"} {
162 exec(truncTemplate, narrowConversion{base, w, vw, base, w / 2, cpu[vw]})
163 }
164 }
165 }
166 for _, vw := range []int{128, 256} {
167 for _, w := range []int{16, 32, 64} {
168 exec(saturateTemplate, narrowConversion{"Int", w, vw, "Int", w / 2, cpu[vw]})
169 exec(saturateTemplate, narrowConversion{"Int", w, vw, "Uint", w / 2, cpu[vw]})
170 exec(saturateTemplate, narrowConversion{"Uint", w, vw, "Uint", w / 2, cpu[vw]})
171 }
172 }
173 for _, ow := range []int{8, 16, 32} {
174 for _, w := range []int{16, 32, 64} {
175 for _, vw := range []int{128, 256, 512} {
176 if w <= ow || (w == 2*ow && vw < 512) {
177
178 continue
179 }
180 exec(saturateSignedToUnsignedTemplate, narrowConversion{"Int", w, vw, "Uint", ow, "AVX512"})
181 }
182 }
183 }
184 }
185
View as plain text