| // Copyright 2026 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package sgutil |
| |
| import ( |
| "bytes" |
| "io" |
| "text/template" |
| ) |
| |
| type TforAsBits interface { |
| ElemBits() int |
| Name_() string |
| } |
| |
| const ( |
| ToBitsName = "ToBits" |
| ToIntsName = "BitsToInt{{.To.ElemBits}}" |
| ConvertToIntName = "ConvertToInt{{.To.ElemBits}}" |
| ConvertToUintName = "ConvertToUint{{.From.ElemBits}}" // backwards because done with ToInts |
| ToFloatsName = "BitsToFloat{{.To.ElemBits}}" |
| ReshapeName = "ReshapeToUint{{.To.ElemBits}}s" |
| ) |
| |
| func templateOf(name, text string) *template.Template { |
| return template.Must(template.New(name).Parse(text)) |
| } |
| |
| var ToBitsCall = templateOf("toBitsCall", "."+ToBitsName+"()") |
| var ToIntsCall = templateOf("toBitsCall", "."+ToIntsName+"()") |
| var ToFloatsCall = templateOf("toBitsCall", "."+ToFloatsName+"()") |
| var ReshapeCall = templateOf("toBitsCall", "."+ReshapeName+"()") |
| |
| var ToBitsDcl = templateOf("toBitsDcl", ` |
| // `+ToBitsName+` reinterprets the bits of a {{.From.Name_}} vector as a {{.To.Name_}} vector |
| func (x {{.From.Name_}}) `+ToBitsName+`() {{.To.Name_}} |
| `) |
| |
| // ToBitsIntrinsic is used in a uint -> T context, but reverse, so T is method receiver. |
| var ToBitsIntrinsic = templateOf("toBitsIntrin", `{{.To.Name_}}.`+ToBitsName) |
| |
| var ToIntsDcl = templateOf("toIntsDcl", ` |
| // `+ToIntsName+` reinterprets the bits of a {{.From.Name_}} vector as a {{.To.Name_}} vector |
| func (x {{.From.Name_}}) `+ToIntsName+`() {{.To.Name_}} |
| |
| // `+ConvertToIntName+` converts a {{.From.Name_}} vector to a {{.To.Name_}} vector |
| func (x {{.From.Name_}}) `+ConvertToIntName+`() {{.To.Name_}} |
| |
| // `+ConvertToUintName+` converts a {{.To.Name_}} vector to a {{.From.Name_}} vector |
| func (x {{.To.Name_}}) `+ConvertToUintName+`() {{.From.Name_}} |
| `) |
| |
| var ToIntsIntrinsic = templateOf("toIntsIntrin", `{{.From.Name_}}.`+ToIntsName) |
| var CvtToIntsIntrinsic = templateOf("cvtToIntIntrin", `{{.From.Name_}}.`+ConvertToIntName) |
| |
| // Also used in a to-from-reversed context. |
| var CvtToUintsIntrinsic = templateOf("cvtToUintIntrin", `{{.To.Name_}}.`+ConvertToUintName) |
| |
| var ToFloatsDcl = templateOf("toFloatsDcl", ` |
| // `+ToFloatsName+` reinterprets the bits of a {{.From.Name_}} vector as a {{.To.Name_}} vector |
| func (x {{.From.Name_}}) `+ToFloatsName+`() {{.To.Name_}} |
| `) |
| |
| var ToFloatsIntrinsic = templateOf("toFloatsIntrin", `{{.From.Name_}}.`+ToFloatsName) |
| |
| var ReshapeDcl = templateOf("reshapeDcl", ` |
| // `+ReshapeName+` reinterprets the bits of a {{.From.Name_}} vector as a {{.To.Name_}} vector |
| func (x {{.From.Name_}}) `+ReshapeName+`() {{.To.Name_}} |
| `) |
| |
| var ReshapeIntrinsic = templateOf("reshapeIntrinsic", `{{.From.Name_}}.`+ReshapeName) |
| |
| var AsOp = templateOf("asConversion", ` |
| // As{{.To.Name}} reinterprets the bits of a {{.From.Name}} vector as a {{.To.Name}} vector |
| // |
| // Deprecated: use combinations of ToBits, BitsTo{Int<N>,Float<N>}, ReshapeToUint<N> |
| // |
| //go:fix inline |
| func (x {{.From.Name}}) As{{.To.Name}}() {{.To.Name}} { |
| return x{{.AsTranslation}} |
| } |
| `) |
| |
| type AsConversion struct { |
| From, To TforAsBits |
| } |
| |
| func Conversion(from, to TforAsBits) *AsConversion { |
| return &AsConversion{from, to} |
| } |
| |
| type TypeDotMethod struct { |
| TypeDotMethod string |
| } |
| |
| func (c *AsConversion) TypeDotMethod(t *template.Template) *TypeDotMethod { |
| var b bytes.Buffer |
| t.Execute(&b, c) |
| return &TypeDotMethod{b.String()} |
| } |
| |
| // ExecuteIntrinsicTemplateOfTypeDotMethod executes the template t on a |
| // variety of TypeDotMethod inputs with template parameter TypeDotMethod |
| func (c *AsConversion) ExecuteIntrinsicTemplateOfTypeDotMethod(w io.Writer, t *template.Template) { |
| from, to := c.From, c.To |
| switch to.Name_()[0] { |
| case 'F': // U -> F |
| t.Execute(w, c.TypeDotMethod(ToFloatsIntrinsic)) |
| t.Execute(w, c.TypeDotMethod(ToBitsIntrinsic)) |
| case 'I': // U -> I |
| t.Execute(w, c.TypeDotMethod(ToIntsIntrinsic)) |
| t.Execute(w, c.TypeDotMethod(CvtToIntsIntrinsic)) |
| t.Execute(w, c.TypeDotMethod(CvtToUintsIntrinsic)) |
| t.Execute(w, c.TypeDotMethod(ToBitsIntrinsic)) |
| case 'U': // U -> U |
| if from.Name_()[0] == 'U' { |
| t.Execute(w, c.TypeDotMethod(ReshapeIntrinsic)) |
| } |
| } |
| } |
| |
| func (a *AsConversion) AsTranslation() string { |
| var b bytes.Buffer |
| if a.From.Name_()[0] != 'U' { |
| ToBitsCall.Execute(&b, a) |
| } |
| if a.From.ElemBits() != a.To.ElemBits() { |
| ReshapeCall.Execute(&b, a) |
| } |
| if a.To.Name_()[0] == 'F' { |
| ToFloatsCall.Execute(&b, a) |
| } |
| if a.To.Name_()[0] == 'I' { |
| ToIntsCall.Execute(&b, a) |
| } |
| return b.String() |
| } |