github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/x86/387.go (about)

     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  }