copilot-swe-agent[bot] d936a45bfd Fix SSE specification compliance - add space after colon in all SSE fields
Co-authored-by: appleboy <21979+appleboy@users.noreply.github.com>
2025-11-15 15:22:08 +00:00

220 lines
5.8 KiB
Go

/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jit
import (
`fmt`
`sync`
_ `unsafe`
`github.com/bytedance/sonic/internal/rt`
`github.com/bytedance/sonic/loader`
`github.com/twitchyliquid64/golang-asm/asm/arch`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
`github.com/twitchyliquid64/golang-asm/objabi`
)
type Backend struct {
Ctxt *obj.Link
Arch *arch.Arch
Head *obj.Prog
Tail *obj.Prog
Prog []*obj.Prog
}
var (
_progPool sync.Pool
)
func newProg() *obj.Prog {
if val := _progPool.Get(); val == nil {
return new(obj.Prog)
} else {
return remProg(val.(*obj.Prog))
}
}
func remProg(p *obj.Prog) *obj.Prog {
*p = obj.Prog{}
return p
}
func newBackend(name string) (ret *Backend) {
ret = new(Backend)
ret.Arch = arch.Set(name)
ret.Ctxt = newLinkContext(ret.Arch.LinkArch)
ret.Arch.Init(ret.Ctxt)
return
}
func newLinkContext(arch *obj.LinkArch) (ret *obj.Link) {
ret = obj.Linknew(arch)
ret.Headtype = objabi.Hlinux
ret.DiagFunc = diagLinkContext
return
}
func diagLinkContext(str string, args ...interface{}) {
rt.Throw(fmt.Sprintf(str, args...))
}
func (self *Backend) New() (ret *obj.Prog) {
ret = newProg()
ret.Ctxt = self.Ctxt
self.Prog = append(self.Prog, ret)
return
}
func (self *Backend) Append(p *obj.Prog) {
if self.Head == nil {
self.Head = p
self.Tail = p
} else {
self.Tail.Link = p
self.Tail = p
}
}
func (self *Backend) Release() {
self.Arch = nil
self.Ctxt = nil
/* return all the progs into pool */
for _, p := range self.Prog {
_progPool.Put(p)
}
/* clear all the references */
self.Head = nil
self.Tail = nil
self.Prog = nil
}
func (self *Backend) Assemble() ([]byte, loader.Pcdata) {
var sym obj.LSym
var fnv obj.FuncInfo
/* construct the function */
sym.Func = &fnv
fnv.Text = self.Head
/* call the assembler */
self.Arch.Assemble(self.Ctxt, &sym, self.New)
pcdata := self.GetPcspTable(self.Ctxt, &sym, self.New)
return sym.P, pcdata
}
func max(a, b int32) int32 {
if a > b {
return a
}
return b
}
func nextPc(p *obj.Prog) uint32 {
if p.Link != nil && p.Pc + int64(p.Isize) != p.Link.Pc {
panic("p.PC + p.Isize != p.Link.PC")
}
return uint32(p.Pc + int64(p.Isize))
}
// NOTE: copied from https://github.com/twitchyliquid64/golang-asm/blob/8d7f1f783b11f9a00f5bcdfcae17f5ac8f22512e/obj/x86/obj6.go#L811.
// we add two instructions such as subq/addq %rsp, $imm to the table.
func (self *Backend) GetPcspTable(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) loader.Pcdata {
pcdata := loader.Pcdata{}
var deltasp int32
var maxdepth int32
foundRet := false
p := cursym.Func.Text
for ; p != nil; p = p.Link {
if foundRet {
break
}
switch p.As {
default: continue
case x86.APUSHL, x86.APUSHFL:
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp += 4
maxdepth = max(maxdepth, deltasp)
continue
case x86.APUSHQ, x86.APUSHFQ:
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp += 8
maxdepth = max(maxdepth, deltasp)
continue
case x86.APUSHW, x86.APUSHFW:
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp += 2
maxdepth = max(maxdepth, deltasp)
continue
case x86.APOPL, x86.APOPFL:
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp -= 4
continue
case x86.APOPQ, x86.APOPFQ:
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp -= 8
continue
case x86.APOPW, x86.APOPFW:
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp -= 2
continue
case x86.AADJSP:
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp += int32(p.From.Offset)
maxdepth = max(maxdepth, deltasp)
continue
case x86.ASUBQ:
// subq %rsp, $imm
if p.To.Reg == x86.REG_SP && p.To.Type == obj.TYPE_REG {
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp += int32(p.From.Offset)
maxdepth = max(maxdepth, deltasp)
}
continue
case x86.AADDQ:
// addq %rsp, $imm
if p.To.Reg == x86.REG_SP && p.To.Type == obj.TYPE_REG {
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
deltasp -= int32(p.From.Offset)
}
continue
case obj.ARET:
if deltasp != 0 {
panic("unbalanced PUSH/POP")
}
pcdata = append(pcdata, loader.Pcvalue{PC: nextPc(p), Val: int32(deltasp)})
foundRet = true
}
}
// the instructions after the RET instruction
if p != nil {
pcdata = append(pcdata, loader.Pcvalue{PC: uint32(cursym.Size), Val: int32(maxdepth)})
}
return pcdata
}