"Fossies" - the Fresh Open Source Software Archive

Member "go/src/cmd/compile/internal/x86/387.go" (9 Sep 2020, 9462 Bytes) of package /windows/misc/go1.14.9.windows-386.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "387.go": 1.14.7_vs_1.15.

    1 // Copyright 2016 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 
    5 package x86
    6 
    7 import (
    8     "cmd/compile/internal/gc"
    9     "cmd/compile/internal/ssa"
   10     "cmd/compile/internal/types"
   11     "cmd/internal/obj"
   12     "cmd/internal/obj/x86"
   13     "math"
   14 )
   15 
   16 // Generates code for v using 387 instructions.
   17 func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
   18     // The SSA compiler pretends that it has an SSE backend.
   19     // If we don't have one of those, we need to translate
   20     // all the SSE ops to equivalent 387 ops. That's what this
   21     // function does.
   22 
   23     switch v.Op {
   24     case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst:
   25         iv := uint64(v.AuxInt)
   26         if iv == 0x0000000000000000 { // +0.0
   27             s.Prog(x86.AFLDZ)
   28         } else if iv == 0x3ff0000000000000 { // +1.0
   29             s.Prog(x86.AFLD1)
   30         } else if iv == 0x8000000000000000 { // -0.0
   31             s.Prog(x86.AFLDZ)
   32             s.Prog(x86.AFCHS)
   33         } else if iv == 0xbff0000000000000 { // -1.0
   34             s.Prog(x86.AFLD1)
   35             s.Prog(x86.AFCHS)
   36         } else if iv == 0x400921fb54442d18 { // +pi
   37             s.Prog(x86.AFLDPI)
   38         } else if iv == 0xc00921fb54442d18 { // -pi
   39             s.Prog(x86.AFLDPI)
   40             s.Prog(x86.AFCHS)
   41         } else { // others
   42             p := s.Prog(loadPush(v.Type))
   43             p.From.Type = obj.TYPE_FCONST
   44             p.From.Val = math.Float64frombits(iv)
   45             p.To.Type = obj.TYPE_REG
   46             p.To.Reg = x86.REG_F0
   47         }
   48         popAndSave(s, v)
   49 
   50     case ssa.Op386MOVSSconst2, ssa.Op386MOVSDconst2:
   51         p := s.Prog(loadPush(v.Type))
   52         p.From.Type = obj.TYPE_MEM
   53         p.From.Reg = v.Args[0].Reg()
   54         p.To.Type = obj.TYPE_REG
   55         p.To.Reg = x86.REG_F0
   56         popAndSave(s, v)
   57 
   58     case ssa.Op386MOVSSload, ssa.Op386MOVSDload, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1, ssa.Op386MOVSSloadidx4, ssa.Op386MOVSDloadidx8:
   59         p := s.Prog(loadPush(v.Type))
   60         p.From.Type = obj.TYPE_MEM
   61         p.From.Reg = v.Args[0].Reg()
   62         gc.AddAux(&p.From, v)
   63         switch v.Op {
   64         case ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1:
   65             p.From.Scale = 1
   66             p.From.Index = v.Args[1].Reg()
   67             if p.From.Index == x86.REG_SP {
   68                 p.From.Reg, p.From.Index = p.From.Index, p.From.Reg
   69             }
   70         case ssa.Op386MOVSSloadidx4:
   71             p.From.Scale = 4
   72             p.From.Index = v.Args[1].Reg()
   73         case ssa.Op386MOVSDloadidx8:
   74             p.From.Scale = 8
   75             p.From.Index = v.Args[1].Reg()
   76         }
   77         p.To.Type = obj.TYPE_REG
   78         p.To.Reg = x86.REG_F0
   79         popAndSave(s, v)
   80 
   81     case ssa.Op386MOVSSstore, ssa.Op386MOVSDstore:
   82         // Push to-be-stored value on top of stack.
   83         push(s, v.Args[1])
   84 
   85         // Pop and store value.
   86         var op obj.As
   87         switch v.Op {
   88         case ssa.Op386MOVSSstore:
   89             op = x86.AFMOVFP
   90         case ssa.Op386MOVSDstore:
   91             op = x86.AFMOVDP
   92         }
   93         p := s.Prog(op)
   94         p.From.Type = obj.TYPE_REG
   95         p.From.Reg = x86.REG_F0
   96         p.To.Type = obj.TYPE_MEM
   97         p.To.Reg = v.Args[0].Reg()
   98         gc.AddAux(&p.To, v)
   99 
  100     case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1, ssa.Op386MOVSSstoreidx4, ssa.Op386MOVSDstoreidx8:
  101         push(s, v.Args[2])
  102         var op obj.As
  103         switch v.Op {
  104         case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSSstoreidx4:
  105             op = x86.AFMOVFP
  106         case ssa.Op386MOVSDstoreidx1, ssa.Op386MOVSDstoreidx8:
  107             op = x86.AFMOVDP
  108         }
  109         p := s.Prog(op)
  110         p.From.Type = obj.TYPE_REG
  111         p.From.Reg = x86.REG_F0
  112         p.To.Type = obj.TYPE_MEM
  113         p.To.Reg = v.Args[0].Reg()
  114         gc.AddAux(&p.To, v)
  115         switch v.Op {
  116         case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1:
  117             p.To.Scale = 1
  118             p.To.Index = v.Args[1].Reg()
  119             if p.To.Index == x86.REG_SP {
  120                 p.To.Reg, p.To.Index = p.To.Index, p.To.Reg
  121             }
  122         case ssa.Op386MOVSSstoreidx4:
  123             p.To.Scale = 4
  124             p.To.Index = v.Args[1].Reg()
  125         case ssa.Op386MOVSDstoreidx8:
  126             p.To.Scale = 8
  127             p.To.Index = v.Args[1].Reg()
  128         }
  129 
  130     case ssa.Op386ADDSS, ssa.Op386ADDSD, ssa.Op386SUBSS, ssa.Op386SUBSD,
  131         ssa.Op386MULSS, ssa.Op386MULSD, ssa.Op386DIVSS, ssa.Op386DIVSD:
  132         if v.Reg() != v.Args[0].Reg() {
  133             v.Fatalf("input[0] and output not in same register %s", v.LongString())
  134         }
  135 
  136         // Push arg1 on top of stack
  137         push(s, v.Args[1])
  138 
  139         // Set precision if needed.  64 bits is the default.
  140         switch v.Op {
  141         case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
  142             p := s.Prog(x86.AFSTCW)
  143             s.AddrScratch(&p.To)
  144             p = s.Prog(x86.AFLDCW)
  145             p.From.Type = obj.TYPE_MEM
  146             p.From.Name = obj.NAME_EXTERN
  147             p.From.Sym = gc.ControlWord32
  148         }
  149 
  150         var op obj.As
  151         switch v.Op {
  152         case ssa.Op386ADDSS, ssa.Op386ADDSD:
  153             op = x86.AFADDDP
  154         case ssa.Op386SUBSS, ssa.Op386SUBSD:
  155             op = x86.AFSUBDP
  156         case ssa.Op386MULSS, ssa.Op386MULSD:
  157             op = x86.AFMULDP
  158         case ssa.Op386DIVSS, ssa.Op386DIVSD:
  159             op = x86.AFDIVDP
  160         }
  161         p := s.Prog(op)
  162         p.From.Type = obj.TYPE_REG
  163         p.From.Reg = x86.REG_F0
  164         p.To.Type = obj.TYPE_REG
  165         p.To.Reg = s.SSEto387[v.Reg()] + 1
  166 
  167         // Restore precision if needed.
  168         switch v.Op {
  169         case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
  170             p := s.Prog(x86.AFLDCW)
  171             s.AddrScratch(&p.From)
  172         }
  173 
  174     case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
  175         push(s, v.Args[0])
  176 
  177         // Compare.
  178         p := s.Prog(x86.AFUCOMP)
  179         p.From.Type = obj.TYPE_REG
  180         p.From.Reg = x86.REG_F0
  181         p.To.Type = obj.TYPE_REG
  182         p.To.Reg = s.SSEto387[v.Args[1].Reg()] + 1
  183 
  184         // Save AX.
  185         p = s.Prog(x86.AMOVL)
  186         p.From.Type = obj.TYPE_REG
  187         p.From.Reg = x86.REG_AX
  188         s.AddrScratch(&p.To)
  189 
  190         // Move status word into AX.
  191         p = s.Prog(x86.AFSTSW)
  192         p.To.Type = obj.TYPE_REG
  193         p.To.Reg = x86.REG_AX
  194 
  195         // Then move the flags we need to the integer flags.
  196         s.Prog(x86.ASAHF)
  197 
  198         // Restore AX.
  199         p = s.Prog(x86.AMOVL)
  200         s.AddrScratch(&p.From)
  201         p.To.Type = obj.TYPE_REG
  202         p.To.Reg = x86.REG_AX
  203 
  204     case ssa.Op386SQRTSD:
  205         push(s, v.Args[0])
  206         s.Prog(x86.AFSQRT)
  207         popAndSave(s, v)
  208 
  209     case ssa.Op386FCHS:
  210         push(s, v.Args[0])
  211         s.Prog(x86.AFCHS)
  212         popAndSave(s, v)
  213 
  214     case ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD:
  215         p := s.Prog(x86.AMOVL)
  216         p.From.Type = obj.TYPE_REG
  217         p.From.Reg = v.Args[0].Reg()
  218         s.AddrScratch(&p.To)
  219         p = s.Prog(x86.AFMOVL)
  220         s.AddrScratch(&p.From)
  221         p.To.Type = obj.TYPE_REG
  222         p.To.Reg = x86.REG_F0
  223         popAndSave(s, v)
  224 
  225     case ssa.Op386CVTTSD2SL, ssa.Op386CVTTSS2SL:
  226         push(s, v.Args[0])
  227 
  228         // Save control word.
  229         p := s.Prog(x86.AFSTCW)
  230         s.AddrScratch(&p.To)
  231         p.To.Offset += 4
  232 
  233         // Load control word which truncates (rounds towards zero).
  234         p = s.Prog(x86.AFLDCW)
  235         p.From.Type = obj.TYPE_MEM
  236         p.From.Name = obj.NAME_EXTERN
  237         p.From.Sym = gc.ControlWord64trunc
  238 
  239         // Now do the conversion.
  240         p = s.Prog(x86.AFMOVLP)
  241         p.From.Type = obj.TYPE_REG
  242         p.From.Reg = x86.REG_F0
  243         s.AddrScratch(&p.To)
  244         p = s.Prog(x86.AMOVL)
  245         s.AddrScratch(&p.From)
  246         p.To.Type = obj.TYPE_REG
  247         p.To.Reg = v.Reg()
  248 
  249         // Restore control word.
  250         p = s.Prog(x86.AFLDCW)
  251         s.AddrScratch(&p.From)
  252         p.From.Offset += 4
  253 
  254     case ssa.Op386CVTSS2SD:
  255         // float32 -> float64 is a nop
  256         push(s, v.Args[0])
  257         popAndSave(s, v)
  258 
  259     case ssa.Op386CVTSD2SS:
  260         // Round to nearest float32.
  261         push(s, v.Args[0])
  262         p := s.Prog(x86.AFMOVFP)
  263         p.From.Type = obj.TYPE_REG
  264         p.From.Reg = x86.REG_F0
  265         s.AddrScratch(&p.To)
  266         p = s.Prog(x86.AFMOVF)
  267         s.AddrScratch(&p.From)
  268         p.To.Type = obj.TYPE_REG
  269         p.To.Reg = x86.REG_F0
  270         popAndSave(s, v)
  271 
  272     case ssa.OpLoadReg:
  273         if !v.Type.IsFloat() {
  274             ssaGenValue(s, v)
  275             return
  276         }
  277         // Load+push the value we need.
  278         p := s.Prog(loadPush(v.Type))
  279         gc.AddrAuto(&p.From, v.Args[0])
  280         p.To.Type = obj.TYPE_REG
  281         p.To.Reg = x86.REG_F0
  282         // Move the value to its assigned register.
  283         popAndSave(s, v)
  284 
  285     case ssa.OpStoreReg:
  286         if !v.Type.IsFloat() {
  287             ssaGenValue(s, v)
  288             return
  289         }
  290         push(s, v.Args[0])
  291         var op obj.As
  292         switch v.Type.Size() {
  293         case 4:
  294             op = x86.AFMOVFP
  295         case 8:
  296             op = x86.AFMOVDP
  297         }
  298         p := s.Prog(op)
  299         p.From.Type = obj.TYPE_REG
  300         p.From.Reg = x86.REG_F0
  301         gc.AddrAuto(&p.To, v)
  302 
  303     case ssa.OpCopy:
  304         if !v.Type.IsFloat() {
  305             ssaGenValue(s, v)
  306             return
  307         }
  308         push(s, v.Args[0])
  309         popAndSave(s, v)
  310 
  311     case ssa.Op386CALLstatic, ssa.Op386CALLclosure, ssa.Op386CALLinter:
  312         flush387(s) // Calls must empty the FP stack.
  313         fallthrough // then issue the call as normal
  314     default:
  315         ssaGenValue(s, v)
  316     }
  317 }
  318 
  319 // push pushes v onto the floating-point stack.  v must be in a register.
  320 func push(s *gc.SSAGenState, v *ssa.Value) {
  321     p := s.Prog(x86.AFMOVD)
  322     p.From.Type = obj.TYPE_REG
  323     p.From.Reg = s.SSEto387[v.Reg()]
  324     p.To.Type = obj.TYPE_REG
  325     p.To.Reg = x86.REG_F0
  326 }
  327 
  328 // popAndSave pops a value off of the floating-point stack and stores
  329 // it in the reigster assigned to v.
  330 func popAndSave(s *gc.SSAGenState, v *ssa.Value) {
  331     r := v.Reg()
  332     if _, ok := s.SSEto387[r]; ok {
  333         // Pop value, write to correct register.
  334         p := s.Prog(x86.AFMOVDP)
  335         p.From.Type = obj.TYPE_REG
  336         p.From.Reg = x86.REG_F0
  337         p.To.Type = obj.TYPE_REG
  338         p.To.Reg = s.SSEto387[v.Reg()] + 1
  339     } else {
  340         // Don't actually pop value. This 387 register is now the
  341         // new home for the not-yet-assigned-a-home SSE register.
  342         // Increase the register mapping of all other registers by one.
  343         for rSSE, r387 := range s.SSEto387 {
  344             s.SSEto387[rSSE] = r387 + 1
  345         }
  346         s.SSEto387[r] = x86.REG_F0
  347     }
  348 }
  349 
  350 // loadPush returns the opcode for load+push of the given type.
  351 func loadPush(t *types.Type) obj.As {
  352     if t.Size() == 4 {
  353         return x86.AFMOVF
  354     }
  355     return x86.AFMOVD
  356 }
  357 
  358 // flush387 removes all entries from the 387 floating-point stack.
  359 func flush387(s *gc.SSAGenState) {
  360     for k := range s.SSEto387 {
  361         p := s.Prog(x86.AFMOVDP)
  362         p.From.Type = obj.TYPE_REG
  363         p.From.Reg = x86.REG_F0
  364         p.To.Type = obj.TYPE_REG
  365         p.To.Reg = x86.REG_F0
  366         delete(s.SSEto387, k)
  367     }
  368 }
  369 
  370 func ssaGenBlock387(s *gc.SSAGenState, b, next *ssa.Block) {
  371     // Empty the 387's FP stack before the block ends.
  372     flush387(s)
  373 
  374     ssaGenBlock(s, b, next)
  375 }