gen.go 11.2 KB
Newer Older
zhangweiwei's avatar
init  
zhangweiwei committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
// Copyright 2016 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.

// +build ignore

package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"strings"
	"text/template"
)

const (
	copyright = "" +
		"// Copyright 2016 The Go Authors. All rights reserved.\n" +
		"// Use of this source code is governed by a BSD-style\n" +
		"// license that can be found in the LICENSE file.\n"

	doNotEdit = "// generated by go run gen.go; DO NOT EDIT\n"

	dashDashDash = "// --------"
)

func main() {
	tmpl, err := ioutil.ReadFile("gen_acc_amd64.s.tmpl")
	if err != nil {
		log.Fatalf("ReadFile: %v", err)
	}
	if !bytes.HasPrefix(tmpl, []byte(copyright)) {
		log.Fatal("source template did not start with the copyright header")
	}
	tmpl = tmpl[len(copyright):]

	preamble := []byte(nil)
	if i := bytes.Index(tmpl, []byte(dashDashDash)); i < 0 {
		log.Fatalf("source template did not contain %q", dashDashDash)
	} else {
		preamble, tmpl = tmpl[:i], tmpl[i:]
	}

	t, err := template.New("").Parse(string(tmpl))
	if err != nil {
		log.Fatalf("Parse: %v", err)
	}

	out := bytes.NewBuffer(nil)
	out.WriteString(doNotEdit)
	out.Write(preamble)

	for i, v := range instances {
		if i != 0 {
			out.WriteString("\n")
		}
		if strings.Contains(v.LoadArgs, "{{.ShortName}}") {
			v.LoadArgs = strings.Replace(v.LoadArgs, "{{.ShortName}}", v.ShortName, -1)
		}
		if err := t.Execute(out, v); err != nil {
			log.Fatalf("Execute(%q): %v", v.ShortName, err)
		}
	}

	if err := ioutil.WriteFile("acc_amd64.s", out.Bytes(), 0666); err != nil {
		log.Fatalf("WriteFile: %v", err)
	}
}

var instances = []struct {
	LongName       string
	ShortName      string
	FrameSize      string
	ArgsSize       string
	Args           string
	DstElemSize1   int
	DstElemSize4   int
	XMM3           string
	XMM4           string
	XMM5           string
	XMM6           string
	XMM8           string
	XMM9           string
	XMM10          string
	LoadArgs       string
	Setup          string
	LoadXMMRegs    string
	Add            string
	ClampAndScale  string
	ConvertToInt32 string
	Store4         string
	Store1         string
}{{
	LongName:       "fixedAccumulateOpOver",
	ShortName:      "fxAccOpOver",
	FrameSize:      fxFrameSize,
	ArgsSize:       twoArgArgsSize,
	Args:           "dst []uint8, src []uint32",
	DstElemSize1:   1 * sizeOfUint8,
	DstElemSize4:   4 * sizeOfUint8,
	XMM3:           fxXMM3,
	XMM4:           fxXMM4,
	XMM5:           fxXMM5,
	XMM6:           opOverXMM6,
	XMM8:           opOverXMM8,
	XMM9:           opOverXMM9,
	XMM10:          opOverXMM10,
	LoadArgs:       twoArgLoadArgs,
	Setup:          fxSetup,
	LoadXMMRegs:    fxLoadXMMRegs + "\n" + opOverLoadXMMRegs,
	Add:            fxAdd,
	ClampAndScale:  fxClampAndScale,
	ConvertToInt32: fxConvertToInt32,
	Store4:         opOverStore4,
	Store1:         opOverStore1,
}, {
	LongName:       "fixedAccumulateOpSrc",
	ShortName:      "fxAccOpSrc",
	FrameSize:      fxFrameSize,
	ArgsSize:       twoArgArgsSize,
	Args:           "dst []uint8, src []uint32",
	DstElemSize1:   1 * sizeOfUint8,
	DstElemSize4:   4 * sizeOfUint8,
	XMM3:           fxXMM3,
	XMM4:           fxXMM4,
	XMM5:           fxXMM5,
	XMM6:           opSrcXMM6,
	XMM8:           opSrcXMM8,
	XMM9:           opSrcXMM9,
	XMM10:          opSrcXMM10,
	LoadArgs:       twoArgLoadArgs,
	Setup:          fxSetup,
	LoadXMMRegs:    fxLoadXMMRegs + "\n" + opSrcLoadXMMRegs,
	Add:            fxAdd,
	ClampAndScale:  fxClampAndScale,
	ConvertToInt32: fxConvertToInt32,
	Store4:         opSrcStore4,
	Store1:         opSrcStore1,
}, {
	LongName:       "fixedAccumulateMask",
	ShortName:      "fxAccMask",
	FrameSize:      fxFrameSize,
	ArgsSize:       oneArgArgsSize,
	Args:           "buf []uint32",
	DstElemSize1:   1 * sizeOfUint32,
	DstElemSize4:   4 * sizeOfUint32,
	XMM3:           fxXMM3,
	XMM4:           fxXMM4,
	XMM5:           fxXMM5,
	XMM6:           maskXMM6,
	XMM8:           maskXMM8,
	XMM9:           maskXMM9,
	XMM10:          maskXMM10,
	LoadArgs:       oneArgLoadArgs,
	Setup:          fxSetup,
	LoadXMMRegs:    fxLoadXMMRegs + "\n" + maskLoadXMMRegs,
	Add:            fxAdd,
	ClampAndScale:  fxClampAndScale,
	ConvertToInt32: fxConvertToInt32,
	Store4:         maskStore4,
	Store1:         maskStore1,
}, {
	LongName:       "floatingAccumulateOpOver",
	ShortName:      "flAccOpOver",
	FrameSize:      flFrameSize,
	ArgsSize:       twoArgArgsSize,
	Args:           "dst []uint8, src []float32",
	DstElemSize1:   1 * sizeOfUint8,
	DstElemSize4:   4 * sizeOfUint8,
	XMM3:           flXMM3,
	XMM4:           flXMM4,
	XMM5:           flXMM5,
	XMM6:           opOverXMM6,
	XMM8:           opOverXMM8,
	XMM9:           opOverXMM9,
	XMM10:          opOverXMM10,
	LoadArgs:       twoArgLoadArgs,
	Setup:          flSetup,
	LoadXMMRegs:    flLoadXMMRegs + "\n" + opOverLoadXMMRegs,
	Add:            flAdd,
	ClampAndScale:  flClampAndScale,
	ConvertToInt32: flConvertToInt32,
	Store4:         opOverStore4,
	Store1:         opOverStore1,
}, {
	LongName:       "floatingAccumulateOpSrc",
	ShortName:      "flAccOpSrc",
	FrameSize:      flFrameSize,
	ArgsSize:       twoArgArgsSize,
	Args:           "dst []uint8, src []float32",
	DstElemSize1:   1 * sizeOfUint8,
	DstElemSize4:   4 * sizeOfUint8,
	XMM3:           flXMM3,
	XMM4:           flXMM4,
	XMM5:           flXMM5,
	XMM6:           opSrcXMM6,
	XMM8:           opSrcXMM8,
	XMM9:           opSrcXMM9,
	XMM10:          opSrcXMM10,
	LoadArgs:       twoArgLoadArgs,
	Setup:          flSetup,
	LoadXMMRegs:    flLoadXMMRegs + "\n" + opSrcLoadXMMRegs,
	Add:            flAdd,
	ClampAndScale:  flClampAndScale,
	ConvertToInt32: flConvertToInt32,
	Store4:         opSrcStore4,
	Store1:         opSrcStore1,
}, {
	LongName:       "floatingAccumulateMask",
	ShortName:      "flAccMask",
	FrameSize:      flFrameSize,
	ArgsSize:       twoArgArgsSize,
	Args:           "dst []uint32, src []float32",
	DstElemSize1:   1 * sizeOfUint32,
	DstElemSize4:   4 * sizeOfUint32,
	XMM3:           flXMM3,
	XMM4:           flXMM4,
	XMM5:           flXMM5,
	XMM6:           maskXMM6,
	XMM8:           maskXMM8,
	XMM9:           maskXMM9,
	XMM10:          maskXMM10,
	LoadArgs:       twoArgLoadArgs,
	Setup:          flSetup,
	LoadXMMRegs:    flLoadXMMRegs + "\n" + maskLoadXMMRegs,
	Add:            flAdd,
	ClampAndScale:  flClampAndScale,
	ConvertToInt32: flConvertToInt32,
	Store4:         maskStore4,
	Store1:         maskStore1,
}}

const (
	fxFrameSize = `0`
	flFrameSize = `8`

	oneArgArgsSize = `24`
	twoArgArgsSize = `48`

	sizeOfUint8  = 1
	sizeOfUint32 = 4

	fxXMM3 = `-`
	flXMM3 = `flSignMask`

	fxXMM4 = `-`
	flXMM4 = `flOne`

	fxXMM5 = `fxAlmost65536`
	flXMM5 = `flAlmost65536`

	oneArgLoadArgs = `
		MOVQ buf_base+0(FP), DI
		MOVQ buf_len+8(FP), BX
		MOVQ buf_base+0(FP), SI
		MOVQ buf_len+8(FP), R10
		`
	twoArgLoadArgs = `
		MOVQ dst_base+0(FP), DI
		MOVQ dst_len+8(FP), BX
		MOVQ src_base+24(FP), SI
		MOVQ src_len+32(FP), R10
		// Sanity check that len(dst) >= len(src).
		CMPQ BX, R10
		JLT  {{.ShortName}}End
		`

	fxSetup = ``
	flSetup = `
		// Prepare to set MXCSR bits 13 and 14, so that the CVTPS2PL below is
		// "Round To Zero".
		STMXCSR mxcsrOrig-8(SP)
		MOVL    mxcsrOrig-8(SP), AX
		ORL     $0x6000, AX
		MOVL    AX, mxcsrNew-4(SP)
		`

	fxLoadXMMRegs = `
		// fxAlmost65536 := XMM(0x0000ffff repeated four times) // Maximum of an uint16.
		MOVOU fxAlmost65536<>(SB), X5
		`
	flLoadXMMRegs = `
		// flSignMask    := XMM(0x7fffffff repeated four times) // All but the sign bit of a float32.
		// flOne         := XMM(0x3f800000 repeated four times) // 1 as a float32.
		// flAlmost65536 := XMM(0x477fffff repeated four times) // 255.99998 * 256 as a float32.
		MOVOU flSignMask<>(SB), X3
		MOVOU flOne<>(SB), X4
		MOVOU flAlmost65536<>(SB), X5
		`

	fxAdd = `PADDD`
	flAdd = `ADDPS`

	fxClampAndScale = `
		// y = abs(x)
		// y >>= 2 // Shift by 2*ϕ - 16.
		// y = min(y, fxAlmost65536)
		PABSD  X1, X2
		PSRLL  $2, X2
		PMINUD X5, X2
		`
	flClampAndScale = `
		// y = x & flSignMask
		// y = min(y, flOne)
		// y = mul(y, flAlmost65536)
		MOVOU X3, X2
		ANDPS X1, X2
		MINPS X4, X2
		MULPS X5, X2
		`

	fxConvertToInt32 = `
		// z = convertToInt32(y)
		// No-op.
		`
	flConvertToInt32 = `
		// z = convertToInt32(y)
		LDMXCSR  mxcsrNew-4(SP)
		CVTPS2PL X2, X2
		LDMXCSR  mxcsrOrig-8(SP)
		`

	opOverStore4 = `
		// Blend over the dst's prior value. SIMD for i in 0..3:
		//
		// dstA := uint32(dst[i]) * 0x101
		// maskA := z@i
		// outA := dstA*(0xffff-maskA)/0xffff + maskA
		// dst[i] = uint8(outA >> 8)
		//
		// First, set X0 to dstA*(0xfff-maskA).
		MOVL   (DI), X0
		PSHUFB X8, X0
		MOVOU  X9, X11
		PSUBL  X2, X11
		PMULLD X11, X0
		// We implement uint32 division by 0xffff as multiplication by a magic
		// constant (0x800080001) and then a shift by a magic constant (47).
		// See TestDivideByFFFF for a justification.
		//
		// That multiplication widens from uint32 to uint64, so we have to
		// duplicate and shift our four uint32s from one XMM register (X0) to
		// two XMM registers (X0 and X11).
		//
		// Move the second and fourth uint32s in X0 to be the first and third
		// uint32s in X11.
		MOVOU X0, X11
		PSRLQ $32, X11
		// Multiply by magic, shift by magic.
		PMULULQ X10, X0
		PMULULQ X10, X11
		PSRLQ   $47, X0
		PSRLQ   $47, X11
		// Merge the two registers back to one, X11, and add maskA.
		PSLLQ $32, X11
		XORPS X0, X11
		PADDD X11, X2
		// As per opSrcStore4, shuffle and copy the 4 second-lowest bytes.
		PSHUFB X6, X2
		MOVL   X2, (DI)
		`
	opSrcStore4 = `
		// z = shuffleTheSecondLowestBytesOfEach4ByteElement(z)
		// copy(dst[:4], low4BytesOf(z))
		PSHUFB X6, X2
		MOVL   X2, (DI)
		`
	maskStore4 = `
		// copy(dst[:4], z)
		MOVOU X2, (DI)
		`

	opOverStore1 = `
		// Blend over the dst's prior value.
		//
		// dstA := uint32(dst[0]) * 0x101
		// maskA := z
		// outA := dstA*(0xffff-maskA)/0xffff + maskA
		// dst[0] = uint8(outA >> 8)
		MOVBLZX (DI), R12
		IMULL   $0x101, R12
		MOVL    X2, R13
		MOVL    $0xffff, AX
		SUBL    R13, AX
		MULL    R12             // MULL's implicit arg is AX, and the result is stored in DX:AX.
		MOVL    $0x80008001, BX // Divide by 0xffff is to first multiply by a magic constant...
		MULL    BX              // MULL's implicit arg is AX, and the result is stored in DX:AX.
		SHRL    $15, DX         // ...and then shift by another magic constant (47 - 32 = 15).
		ADDL    DX, R13
		SHRL    $8, R13
		MOVB    R13, (DI)
		`
	opSrcStore1 = `
		// dst[0] = uint8(z>>8)
		MOVL X2, BX
		SHRL $8, BX
		MOVB BX, (DI)
		`
	maskStore1 = `
		// dst[0] = uint32(z)
		MOVL X2, (DI)
		`

	opOverXMM6 = `gather`
	opSrcXMM6  = `gather`
	maskXMM6   = `-`

	opOverXMM8 = `scatterAndMulBy0x101`
	opSrcXMM8  = `-`
	maskXMM8   = `-`

	opOverXMM9 = `fxAlmost65536`
	opSrcXMM9  = `-`
	maskXMM9   = `-`

	opOverXMM10 = `inverseFFFF`
	opSrcXMM10  = `-`
	maskXMM10   = `-`

	opOverLoadXMMRegs = `
		// gather               := XMM(see above)                      // PSHUFB shuffle mask.
		// scatterAndMulBy0x101 := XMM(see above)                      // PSHUFB shuffle mask.
		// fxAlmost65536        := XMM(0x0000ffff repeated four times) // 0xffff.
		// inverseFFFF          := XMM(0x80008001 repeated four times) // Magic constant for dividing by 0xffff.
		MOVOU gather<>(SB), X6
		MOVOU scatterAndMulBy0x101<>(SB), X8
		MOVOU fxAlmost65536<>(SB), X9
		MOVOU inverseFFFF<>(SB), X10
		`
	opSrcLoadXMMRegs = `
		// gather := XMM(see above) // PSHUFB shuffle mask.
		MOVOU gather<>(SB), X6
		`
	maskLoadXMMRegs = ``
)