...

Source file src/cmd/compile/internal/mips/ssa.go

     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 mips
     6	
     7	import (
     8		"math"
     9	
    10		"cmd/compile/internal/gc"
    11		"cmd/compile/internal/ssa"
    12		"cmd/compile/internal/types"
    13		"cmd/internal/obj"
    14		"cmd/internal/obj/mips"
    15	)
    16	
    17	// isFPreg reports whether r is an FP register
    18	func isFPreg(r int16) bool {
    19		return mips.REG_F0 <= r && r <= mips.REG_F31
    20	}
    21	
    22	// isHILO reports whether r is HI or LO register
    23	func isHILO(r int16) bool {
    24		return r == mips.REG_HI || r == mips.REG_LO
    25	}
    26	
    27	// loadByType returns the load instruction of the given type.
    28	func loadByType(t *types.Type, r int16) obj.As {
    29		if isFPreg(r) {
    30			if t.Size() == 4 { // float32 or int32
    31				return mips.AMOVF
    32			} else { // float64 or int64
    33				return mips.AMOVD
    34			}
    35		} else {
    36			switch t.Size() {
    37			case 1:
    38				if t.IsSigned() {
    39					return mips.AMOVB
    40				} else {
    41					return mips.AMOVBU
    42				}
    43			case 2:
    44				if t.IsSigned() {
    45					return mips.AMOVH
    46				} else {
    47					return mips.AMOVHU
    48				}
    49			case 4:
    50				return mips.AMOVW
    51			}
    52		}
    53		panic("bad load type")
    54	}
    55	
    56	// storeByType returns the store instruction of the given type.
    57	func storeByType(t *types.Type, r int16) obj.As {
    58		if isFPreg(r) {
    59			if t.Size() == 4 { // float32 or int32
    60				return mips.AMOVF
    61			} else { // float64 or int64
    62				return mips.AMOVD
    63			}
    64		} else {
    65			switch t.Size() {
    66			case 1:
    67				return mips.AMOVB
    68			case 2:
    69				return mips.AMOVH
    70			case 4:
    71				return mips.AMOVW
    72			}
    73		}
    74		panic("bad store type")
    75	}
    76	
    77	func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
    78		switch v.Op {
    79		case ssa.OpCopy, ssa.OpMIPSMOVWreg:
    80			t := v.Type
    81			if t.IsMemory() {
    82				return
    83			}
    84			x := v.Args[0].Reg()
    85			y := v.Reg()
    86			if x == y {
    87				return
    88			}
    89			as := mips.AMOVW
    90			if isFPreg(x) && isFPreg(y) {
    91				as = mips.AMOVF
    92				if t.Size() == 8 {
    93					as = mips.AMOVD
    94				}
    95			}
    96	
    97			p := s.Prog(as)
    98			p.From.Type = obj.TYPE_REG
    99			p.From.Reg = x
   100			p.To.Type = obj.TYPE_REG
   101			p.To.Reg = y
   102			if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) {
   103				// cannot move between special registers, use TMP as intermediate
   104				p.To.Reg = mips.REGTMP
   105				p = s.Prog(mips.AMOVW)
   106				p.From.Type = obj.TYPE_REG
   107				p.From.Reg = mips.REGTMP
   108				p.To.Type = obj.TYPE_REG
   109				p.To.Reg = y
   110			}
   111		case ssa.OpMIPSMOVWnop:
   112			if v.Reg() != v.Args[0].Reg() {
   113				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   114			}
   115			// nothing to do
   116		case ssa.OpLoadReg:
   117			if v.Type.IsFlags() {
   118				v.Fatalf("load flags not implemented: %v", v.LongString())
   119				return
   120			}
   121			r := v.Reg()
   122			p := s.Prog(loadByType(v.Type, r))
   123			gc.AddrAuto(&p.From, v.Args[0])
   124			p.To.Type = obj.TYPE_REG
   125			p.To.Reg = r
   126			if isHILO(r) {
   127				// cannot directly load, load to TMP and move
   128				p.To.Reg = mips.REGTMP
   129				p = s.Prog(mips.AMOVW)
   130				p.From.Type = obj.TYPE_REG
   131				p.From.Reg = mips.REGTMP
   132				p.To.Type = obj.TYPE_REG
   133				p.To.Reg = r
   134			}
   135		case ssa.OpStoreReg:
   136			if v.Type.IsFlags() {
   137				v.Fatalf("store flags not implemented: %v", v.LongString())
   138				return
   139			}
   140			r := v.Args[0].Reg()
   141			if isHILO(r) {
   142				// cannot directly store, move to TMP and store
   143				p := s.Prog(mips.AMOVW)
   144				p.From.Type = obj.TYPE_REG
   145				p.From.Reg = r
   146				p.To.Type = obj.TYPE_REG
   147				p.To.Reg = mips.REGTMP
   148				r = mips.REGTMP
   149			}
   150			p := s.Prog(storeByType(v.Type, r))
   151			p.From.Type = obj.TYPE_REG
   152			p.From.Reg = r
   153			gc.AddrAuto(&p.To, v)
   154		case ssa.OpMIPSADD,
   155			ssa.OpMIPSSUB,
   156			ssa.OpMIPSAND,
   157			ssa.OpMIPSOR,
   158			ssa.OpMIPSXOR,
   159			ssa.OpMIPSNOR,
   160			ssa.OpMIPSSLL,
   161			ssa.OpMIPSSRL,
   162			ssa.OpMIPSSRA,
   163			ssa.OpMIPSADDF,
   164			ssa.OpMIPSADDD,
   165			ssa.OpMIPSSUBF,
   166			ssa.OpMIPSSUBD,
   167			ssa.OpMIPSMULF,
   168			ssa.OpMIPSMULD,
   169			ssa.OpMIPSDIVF,
   170			ssa.OpMIPSDIVD,
   171			ssa.OpMIPSMUL:
   172			p := s.Prog(v.Op.Asm())
   173			p.From.Type = obj.TYPE_REG
   174			p.From.Reg = v.Args[1].Reg()
   175			p.Reg = v.Args[0].Reg()
   176			p.To.Type = obj.TYPE_REG
   177			p.To.Reg = v.Reg()
   178		case ssa.OpMIPSSGT,
   179			ssa.OpMIPSSGTU:
   180			p := s.Prog(v.Op.Asm())
   181			p.From.Type = obj.TYPE_REG
   182			p.From.Reg = v.Args[0].Reg()
   183			p.Reg = v.Args[1].Reg()
   184			p.To.Type = obj.TYPE_REG
   185			p.To.Reg = v.Reg()
   186		case ssa.OpMIPSSGTzero,
   187			ssa.OpMIPSSGTUzero:
   188			p := s.Prog(v.Op.Asm())
   189			p.From.Type = obj.TYPE_REG
   190			p.From.Reg = v.Args[0].Reg()
   191			p.Reg = mips.REGZERO
   192			p.To.Type = obj.TYPE_REG
   193			p.To.Reg = v.Reg()
   194		case ssa.OpMIPSADDconst,
   195			ssa.OpMIPSSUBconst,
   196			ssa.OpMIPSANDconst,
   197			ssa.OpMIPSORconst,
   198			ssa.OpMIPSXORconst,
   199			ssa.OpMIPSNORconst,
   200			ssa.OpMIPSSLLconst,
   201			ssa.OpMIPSSRLconst,
   202			ssa.OpMIPSSRAconst,
   203			ssa.OpMIPSSGTconst,
   204			ssa.OpMIPSSGTUconst:
   205			p := s.Prog(v.Op.Asm())
   206			p.From.Type = obj.TYPE_CONST
   207			p.From.Offset = v.AuxInt
   208			p.Reg = v.Args[0].Reg()
   209			p.To.Type = obj.TYPE_REG
   210			p.To.Reg = v.Reg()
   211		case ssa.OpMIPSMULT,
   212			ssa.OpMIPSMULTU,
   213			ssa.OpMIPSDIV,
   214			ssa.OpMIPSDIVU:
   215			// result in hi,lo
   216			p := s.Prog(v.Op.Asm())
   217			p.From.Type = obj.TYPE_REG
   218			p.From.Reg = v.Args[1].Reg()
   219			p.Reg = v.Args[0].Reg()
   220		case ssa.OpMIPSMOVWconst:
   221			r := v.Reg()
   222			p := s.Prog(v.Op.Asm())
   223			p.From.Type = obj.TYPE_CONST
   224			p.From.Offset = v.AuxInt
   225			p.To.Type = obj.TYPE_REG
   226			p.To.Reg = r
   227			if isFPreg(r) || isHILO(r) {
   228				// cannot move into FP or special registers, use TMP as intermediate
   229				p.To.Reg = mips.REGTMP
   230				p = s.Prog(mips.AMOVW)
   231				p.From.Type = obj.TYPE_REG
   232				p.From.Reg = mips.REGTMP
   233				p.To.Type = obj.TYPE_REG
   234				p.To.Reg = r
   235			}
   236		case ssa.OpMIPSMOVFconst,
   237			ssa.OpMIPSMOVDconst:
   238			p := s.Prog(v.Op.Asm())
   239			p.From.Type = obj.TYPE_FCONST
   240			p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   241			p.To.Type = obj.TYPE_REG
   242			p.To.Reg = v.Reg()
   243		case ssa.OpMIPSCMOVZ:
   244			if v.Reg() != v.Args[0].Reg() {
   245				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   246			}
   247			p := s.Prog(v.Op.Asm())
   248			p.From.Type = obj.TYPE_REG
   249			p.From.Reg = v.Args[2].Reg()
   250			p.Reg = v.Args[1].Reg()
   251			p.To.Type = obj.TYPE_REG
   252			p.To.Reg = v.Reg()
   253		case ssa.OpMIPSCMOVZzero:
   254			if v.Reg() != v.Args[0].Reg() {
   255				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   256			}
   257			p := s.Prog(v.Op.Asm())
   258			p.From.Type = obj.TYPE_REG
   259			p.From.Reg = v.Args[1].Reg()
   260			p.Reg = mips.REGZERO
   261			p.To.Type = obj.TYPE_REG
   262			p.To.Reg = v.Reg()
   263		case ssa.OpMIPSCMPEQF,
   264			ssa.OpMIPSCMPEQD,
   265			ssa.OpMIPSCMPGEF,
   266			ssa.OpMIPSCMPGED,
   267			ssa.OpMIPSCMPGTF,
   268			ssa.OpMIPSCMPGTD:
   269			p := s.Prog(v.Op.Asm())
   270			p.From.Type = obj.TYPE_REG
   271			p.From.Reg = v.Args[0].Reg()
   272			p.Reg = v.Args[1].Reg()
   273		case ssa.OpMIPSMOVWaddr:
   274			p := s.Prog(mips.AMOVW)
   275			p.From.Type = obj.TYPE_ADDR
   276			p.From.Reg = v.Args[0].Reg()
   277			var wantreg string
   278			// MOVW $sym+off(base), R
   279			// the assembler expands it as the following:
   280			// - base is SP: add constant offset to SP (R29)
   281			//               when constant is large, tmp register (R23) may be used
   282			// - base is SB: load external address with relocation
   283			switch v.Aux.(type) {
   284			default:
   285				v.Fatalf("aux is of unknown type %T", v.Aux)
   286			case *obj.LSym:
   287				wantreg = "SB"
   288				gc.AddAux(&p.From, v)
   289			case *gc.Node:
   290				wantreg = "SP"
   291				gc.AddAux(&p.From, v)
   292			case nil:
   293				// No sym, just MOVW $off(SP), R
   294				wantreg = "SP"
   295				p.From.Offset = v.AuxInt
   296			}
   297			if reg := v.Args[0].RegName(); reg != wantreg {
   298				v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   299			}
   300			p.To.Type = obj.TYPE_REG
   301			p.To.Reg = v.Reg()
   302		case ssa.OpMIPSMOVBload,
   303			ssa.OpMIPSMOVBUload,
   304			ssa.OpMIPSMOVHload,
   305			ssa.OpMIPSMOVHUload,
   306			ssa.OpMIPSMOVWload,
   307			ssa.OpMIPSMOVFload,
   308			ssa.OpMIPSMOVDload:
   309			p := s.Prog(v.Op.Asm())
   310			p.From.Type = obj.TYPE_MEM
   311			p.From.Reg = v.Args[0].Reg()
   312			gc.AddAux(&p.From, v)
   313			p.To.Type = obj.TYPE_REG
   314			p.To.Reg = v.Reg()
   315		case ssa.OpMIPSMOVBstore,
   316			ssa.OpMIPSMOVHstore,
   317			ssa.OpMIPSMOVWstore,
   318			ssa.OpMIPSMOVFstore,
   319			ssa.OpMIPSMOVDstore:
   320			p := s.Prog(v.Op.Asm())
   321			p.From.Type = obj.TYPE_REG
   322			p.From.Reg = v.Args[1].Reg()
   323			p.To.Type = obj.TYPE_MEM
   324			p.To.Reg = v.Args[0].Reg()
   325			gc.AddAux(&p.To, v)
   326		case ssa.OpMIPSMOVBstorezero,
   327			ssa.OpMIPSMOVHstorezero,
   328			ssa.OpMIPSMOVWstorezero:
   329			p := s.Prog(v.Op.Asm())
   330			p.From.Type = obj.TYPE_REG
   331			p.From.Reg = mips.REGZERO
   332			p.To.Type = obj.TYPE_MEM
   333			p.To.Reg = v.Args[0].Reg()
   334			gc.AddAux(&p.To, v)
   335		case ssa.OpMIPSMOVBreg,
   336			ssa.OpMIPSMOVBUreg,
   337			ssa.OpMIPSMOVHreg,
   338			ssa.OpMIPSMOVHUreg:
   339			a := v.Args[0]
   340			for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPSMOVWreg || a.Op == ssa.OpMIPSMOVWnop {
   341				a = a.Args[0]
   342			}
   343			if a.Op == ssa.OpLoadReg {
   344				t := a.Type
   345				switch {
   346				case v.Op == ssa.OpMIPSMOVBreg && t.Size() == 1 && t.IsSigned(),
   347					v.Op == ssa.OpMIPSMOVBUreg && t.Size() == 1 && !t.IsSigned(),
   348					v.Op == ssa.OpMIPSMOVHreg && t.Size() == 2 && t.IsSigned(),
   349					v.Op == ssa.OpMIPSMOVHUreg && t.Size() == 2 && !t.IsSigned():
   350					// arg is a proper-typed load, already zero/sign-extended, don't extend again
   351					if v.Reg() == v.Args[0].Reg() {
   352						return
   353					}
   354					p := s.Prog(mips.AMOVW)
   355					p.From.Type = obj.TYPE_REG
   356					p.From.Reg = v.Args[0].Reg()
   357					p.To.Type = obj.TYPE_REG
   358					p.To.Reg = v.Reg()
   359					return
   360				default:
   361				}
   362			}
   363			fallthrough
   364		case ssa.OpMIPSMOVWF,
   365			ssa.OpMIPSMOVWD,
   366			ssa.OpMIPSTRUNCFW,
   367			ssa.OpMIPSTRUNCDW,
   368			ssa.OpMIPSMOVFD,
   369			ssa.OpMIPSMOVDF,
   370			ssa.OpMIPSNEGF,
   371			ssa.OpMIPSNEGD,
   372			ssa.OpMIPSSQRTD,
   373			ssa.OpMIPSCLZ:
   374			p := s.Prog(v.Op.Asm())
   375			p.From.Type = obj.TYPE_REG
   376			p.From.Reg = v.Args[0].Reg()
   377			p.To.Type = obj.TYPE_REG
   378			p.To.Reg = v.Reg()
   379		case ssa.OpMIPSNEG:
   380			// SUB from REGZERO
   381			p := s.Prog(mips.ASUBU)
   382			p.From.Type = obj.TYPE_REG
   383			p.From.Reg = v.Args[0].Reg()
   384			p.Reg = mips.REGZERO
   385			p.To.Type = obj.TYPE_REG
   386			p.To.Reg = v.Reg()
   387		case ssa.OpMIPSLoweredZero:
   388			// SUBU	$4, R1
   389			// MOVW	R0, 4(R1)
   390			// ADDU	$4, R1
   391			// BNE	Rarg1, R1, -2(PC)
   392			// arg1 is the address of the last element to zero
   393			var sz int64
   394			var mov obj.As
   395			switch {
   396			case v.AuxInt%4 == 0:
   397				sz = 4
   398				mov = mips.AMOVW
   399			case v.AuxInt%2 == 0:
   400				sz = 2
   401				mov = mips.AMOVH
   402			default:
   403				sz = 1
   404				mov = mips.AMOVB
   405			}
   406			p := s.Prog(mips.ASUBU)
   407			p.From.Type = obj.TYPE_CONST
   408			p.From.Offset = sz
   409			p.To.Type = obj.TYPE_REG
   410			p.To.Reg = mips.REG_R1
   411			p2 := s.Prog(mov)
   412			p2.From.Type = obj.TYPE_REG
   413			p2.From.Reg = mips.REGZERO
   414			p2.To.Type = obj.TYPE_MEM
   415			p2.To.Reg = mips.REG_R1
   416			p2.To.Offset = sz
   417			p3 := s.Prog(mips.AADDU)
   418			p3.From.Type = obj.TYPE_CONST
   419			p3.From.Offset = sz
   420			p3.To.Type = obj.TYPE_REG
   421			p3.To.Reg = mips.REG_R1
   422			p4 := s.Prog(mips.ABNE)
   423			p4.From.Type = obj.TYPE_REG
   424			p4.From.Reg = v.Args[1].Reg()
   425			p4.Reg = mips.REG_R1
   426			p4.To.Type = obj.TYPE_BRANCH
   427			gc.Patch(p4, p2)
   428		case ssa.OpMIPSLoweredMove:
   429			// SUBU	$4, R1
   430			// MOVW	4(R1), Rtmp
   431			// MOVW	Rtmp, (R2)
   432			// ADDU	$4, R1
   433			// ADDU	$4, R2
   434			// BNE	Rarg2, R1, -4(PC)
   435			// arg2 is the address of the last element of src
   436			var sz int64
   437			var mov obj.As
   438			switch {
   439			case v.AuxInt%4 == 0:
   440				sz = 4
   441				mov = mips.AMOVW
   442			case v.AuxInt%2 == 0:
   443				sz = 2
   444				mov = mips.AMOVH
   445			default:
   446				sz = 1
   447				mov = mips.AMOVB
   448			}
   449			p := s.Prog(mips.ASUBU)
   450			p.From.Type = obj.TYPE_CONST
   451			p.From.Offset = sz
   452			p.To.Type = obj.TYPE_REG
   453			p.To.Reg = mips.REG_R1
   454			p2 := s.Prog(mov)
   455			p2.From.Type = obj.TYPE_MEM
   456			p2.From.Reg = mips.REG_R1
   457			p2.From.Offset = sz
   458			p2.To.Type = obj.TYPE_REG
   459			p2.To.Reg = mips.REGTMP
   460			p3 := s.Prog(mov)
   461			p3.From.Type = obj.TYPE_REG
   462			p3.From.Reg = mips.REGTMP
   463			p3.To.Type = obj.TYPE_MEM
   464			p3.To.Reg = mips.REG_R2
   465			p4 := s.Prog(mips.AADDU)
   466			p4.From.Type = obj.TYPE_CONST
   467			p4.From.Offset = sz
   468			p4.To.Type = obj.TYPE_REG
   469			p4.To.Reg = mips.REG_R1
   470			p5 := s.Prog(mips.AADDU)
   471			p5.From.Type = obj.TYPE_CONST
   472			p5.From.Offset = sz
   473			p5.To.Type = obj.TYPE_REG
   474			p5.To.Reg = mips.REG_R2
   475			p6 := s.Prog(mips.ABNE)
   476			p6.From.Type = obj.TYPE_REG
   477			p6.From.Reg = v.Args[2].Reg()
   478			p6.Reg = mips.REG_R1
   479			p6.To.Type = obj.TYPE_BRANCH
   480			gc.Patch(p6, p2)
   481		case ssa.OpMIPSCALLstatic, ssa.OpMIPSCALLclosure, ssa.OpMIPSCALLinter:
   482			s.Call(v)
   483		case ssa.OpMIPSLoweredWB:
   484			p := s.Prog(obj.ACALL)
   485			p.To.Type = obj.TYPE_MEM
   486			p.To.Name = obj.NAME_EXTERN
   487			p.To.Sym = v.Aux.(*obj.LSym)
   488		case ssa.OpMIPSLoweredPanicBoundsA, ssa.OpMIPSLoweredPanicBoundsB, ssa.OpMIPSLoweredPanicBoundsC:
   489			p := s.Prog(obj.ACALL)
   490			p.To.Type = obj.TYPE_MEM
   491			p.To.Name = obj.NAME_EXTERN
   492			p.To.Sym = gc.BoundsCheckFunc[v.AuxInt]
   493			s.UseArgs(8) // space used in callee args area by assembly stubs
   494		case ssa.OpMIPSLoweredPanicExtendA, ssa.OpMIPSLoweredPanicExtendB, ssa.OpMIPSLoweredPanicExtendC:
   495			p := s.Prog(obj.ACALL)
   496			p.To.Type = obj.TYPE_MEM
   497			p.To.Name = obj.NAME_EXTERN
   498			p.To.Sym = gc.ExtendCheckFunc[v.AuxInt]
   499			s.UseArgs(12) // space used in callee args area by assembly stubs
   500		case ssa.OpMIPSLoweredAtomicLoad:
   501			s.Prog(mips.ASYNC)
   502	
   503			p := s.Prog(mips.AMOVW)
   504			p.From.Type = obj.TYPE_MEM
   505			p.From.Reg = v.Args[0].Reg()
   506			p.To.Type = obj.TYPE_REG
   507			p.To.Reg = v.Reg0()
   508	
   509			s.Prog(mips.ASYNC)
   510		case ssa.OpMIPSLoweredAtomicStore:
   511			s.Prog(mips.ASYNC)
   512	
   513			p := s.Prog(mips.AMOVW)
   514			p.From.Type = obj.TYPE_REG
   515			p.From.Reg = v.Args[1].Reg()
   516			p.To.Type = obj.TYPE_MEM
   517			p.To.Reg = v.Args[0].Reg()
   518	
   519			s.Prog(mips.ASYNC)
   520		case ssa.OpMIPSLoweredAtomicStorezero:
   521			s.Prog(mips.ASYNC)
   522	
   523			p := s.Prog(mips.AMOVW)
   524			p.From.Type = obj.TYPE_REG
   525			p.From.Reg = mips.REGZERO
   526			p.To.Type = obj.TYPE_MEM
   527			p.To.Reg = v.Args[0].Reg()
   528	
   529			s.Prog(mips.ASYNC)
   530		case ssa.OpMIPSLoweredAtomicExchange:
   531			// SYNC
   532			// MOVW Rarg1, Rtmp
   533			// LL	(Rarg0), Rout
   534			// SC	Rtmp, (Rarg0)
   535			// BEQ	Rtmp, -3(PC)
   536			// SYNC
   537			s.Prog(mips.ASYNC)
   538	
   539			p := s.Prog(mips.AMOVW)
   540			p.From.Type = obj.TYPE_REG
   541			p.From.Reg = v.Args[1].Reg()
   542			p.To.Type = obj.TYPE_REG
   543			p.To.Reg = mips.REGTMP
   544	
   545			p1 := s.Prog(mips.ALL)
   546			p1.From.Type = obj.TYPE_MEM
   547			p1.From.Reg = v.Args[0].Reg()
   548			p1.To.Type = obj.TYPE_REG
   549			p1.To.Reg = v.Reg0()
   550	
   551			p2 := s.Prog(mips.ASC)
   552			p2.From.Type = obj.TYPE_REG
   553			p2.From.Reg = mips.REGTMP
   554			p2.To.Type = obj.TYPE_MEM
   555			p2.To.Reg = v.Args[0].Reg()
   556	
   557			p3 := s.Prog(mips.ABEQ)
   558			p3.From.Type = obj.TYPE_REG
   559			p3.From.Reg = mips.REGTMP
   560			p3.To.Type = obj.TYPE_BRANCH
   561			gc.Patch(p3, p)
   562	
   563			s.Prog(mips.ASYNC)
   564		case ssa.OpMIPSLoweredAtomicAdd:
   565			// SYNC
   566			// LL	(Rarg0), Rout
   567			// ADDU Rarg1, Rout, Rtmp
   568			// SC	Rtmp, (Rarg0)
   569			// BEQ	Rtmp, -3(PC)
   570			// SYNC
   571			// ADDU Rarg1, Rout
   572			s.Prog(mips.ASYNC)
   573	
   574			p := s.Prog(mips.ALL)
   575			p.From.Type = obj.TYPE_MEM
   576			p.From.Reg = v.Args[0].Reg()
   577			p.To.Type = obj.TYPE_REG
   578			p.To.Reg = v.Reg0()
   579	
   580			p1 := s.Prog(mips.AADDU)
   581			p1.From.Type = obj.TYPE_REG
   582			p1.From.Reg = v.Args[1].Reg()
   583			p1.Reg = v.Reg0()
   584			p1.To.Type = obj.TYPE_REG
   585			p1.To.Reg = mips.REGTMP
   586	
   587			p2 := s.Prog(mips.ASC)
   588			p2.From.Type = obj.TYPE_REG
   589			p2.From.Reg = mips.REGTMP
   590			p2.To.Type = obj.TYPE_MEM
   591			p2.To.Reg = v.Args[0].Reg()
   592	
   593			p3 := s.Prog(mips.ABEQ)
   594			p3.From.Type = obj.TYPE_REG
   595			p3.From.Reg = mips.REGTMP
   596			p3.To.Type = obj.TYPE_BRANCH
   597			gc.Patch(p3, p)
   598	
   599			s.Prog(mips.ASYNC)
   600	
   601			p4 := s.Prog(mips.AADDU)
   602			p4.From.Type = obj.TYPE_REG
   603			p4.From.Reg = v.Args[1].Reg()
   604			p4.Reg = v.Reg0()
   605			p4.To.Type = obj.TYPE_REG
   606			p4.To.Reg = v.Reg0()
   607	
   608		case ssa.OpMIPSLoweredAtomicAddconst:
   609			// SYNC
   610			// LL	(Rarg0), Rout
   611			// ADDU $auxInt, Rout, Rtmp
   612			// SC	Rtmp, (Rarg0)
   613			// BEQ	Rtmp, -3(PC)
   614			// SYNC
   615			// ADDU $auxInt, Rout
   616			s.Prog(mips.ASYNC)
   617	
   618			p := s.Prog(mips.ALL)
   619			p.From.Type = obj.TYPE_MEM
   620			p.From.Reg = v.Args[0].Reg()
   621			p.To.Type = obj.TYPE_REG
   622			p.To.Reg = v.Reg0()
   623	
   624			p1 := s.Prog(mips.AADDU)
   625			p1.From.Type = obj.TYPE_CONST
   626			p1.From.Offset = v.AuxInt
   627			p1.Reg = v.Reg0()
   628			p1.To.Type = obj.TYPE_REG
   629			p1.To.Reg = mips.REGTMP
   630	
   631			p2 := s.Prog(mips.ASC)
   632			p2.From.Type = obj.TYPE_REG
   633			p2.From.Reg = mips.REGTMP
   634			p2.To.Type = obj.TYPE_MEM
   635			p2.To.Reg = v.Args[0].Reg()
   636	
   637			p3 := s.Prog(mips.ABEQ)
   638			p3.From.Type = obj.TYPE_REG
   639			p3.From.Reg = mips.REGTMP
   640			p3.To.Type = obj.TYPE_BRANCH
   641			gc.Patch(p3, p)
   642	
   643			s.Prog(mips.ASYNC)
   644	
   645			p4 := s.Prog(mips.AADDU)
   646			p4.From.Type = obj.TYPE_CONST
   647			p4.From.Offset = v.AuxInt
   648			p4.Reg = v.Reg0()
   649			p4.To.Type = obj.TYPE_REG
   650			p4.To.Reg = v.Reg0()
   651	
   652		case ssa.OpMIPSLoweredAtomicAnd,
   653			ssa.OpMIPSLoweredAtomicOr:
   654			// SYNC
   655			// LL	(Rarg0), Rtmp
   656			// AND/OR	Rarg1, Rtmp
   657			// SC	Rtmp, (Rarg0)
   658			// BEQ	Rtmp, -3(PC)
   659			// SYNC
   660			s.Prog(mips.ASYNC)
   661	
   662			p := s.Prog(mips.ALL)
   663			p.From.Type = obj.TYPE_MEM
   664			p.From.Reg = v.Args[0].Reg()
   665			p.To.Type = obj.TYPE_REG
   666			p.To.Reg = mips.REGTMP
   667	
   668			p1 := s.Prog(v.Op.Asm())
   669			p1.From.Type = obj.TYPE_REG
   670			p1.From.Reg = v.Args[1].Reg()
   671			p1.Reg = mips.REGTMP
   672			p1.To.Type = obj.TYPE_REG
   673			p1.To.Reg = mips.REGTMP
   674	
   675			p2 := s.Prog(mips.ASC)
   676			p2.From.Type = obj.TYPE_REG
   677			p2.From.Reg = mips.REGTMP
   678			p2.To.Type = obj.TYPE_MEM
   679			p2.To.Reg = v.Args[0].Reg()
   680	
   681			p3 := s.Prog(mips.ABEQ)
   682			p3.From.Type = obj.TYPE_REG
   683			p3.From.Reg = mips.REGTMP
   684			p3.To.Type = obj.TYPE_BRANCH
   685			gc.Patch(p3, p)
   686	
   687			s.Prog(mips.ASYNC)
   688	
   689		case ssa.OpMIPSLoweredAtomicCas:
   690			// MOVW $0, Rout
   691			// SYNC
   692			// LL	(Rarg0), Rtmp
   693			// BNE	Rtmp, Rarg1, 4(PC)
   694			// MOVW Rarg2, Rout
   695			// SC	Rout, (Rarg0)
   696			// BEQ	Rout, -4(PC)
   697			// SYNC
   698			p := s.Prog(mips.AMOVW)
   699			p.From.Type = obj.TYPE_REG
   700			p.From.Reg = mips.REGZERO
   701			p.To.Type = obj.TYPE_REG
   702			p.To.Reg = v.Reg0()
   703	
   704			s.Prog(mips.ASYNC)
   705	
   706			p1 := s.Prog(mips.ALL)
   707			p1.From.Type = obj.TYPE_MEM
   708			p1.From.Reg = v.Args[0].Reg()
   709			p1.To.Type = obj.TYPE_REG
   710			p1.To.Reg = mips.REGTMP
   711	
   712			p2 := s.Prog(mips.ABNE)
   713			p2.From.Type = obj.TYPE_REG
   714			p2.From.Reg = v.Args[1].Reg()
   715			p2.Reg = mips.REGTMP
   716			p2.To.Type = obj.TYPE_BRANCH
   717	
   718			p3 := s.Prog(mips.AMOVW)
   719			p3.From.Type = obj.TYPE_REG
   720			p3.From.Reg = v.Args[2].Reg()
   721			p3.To.Type = obj.TYPE_REG
   722			p3.To.Reg = v.Reg0()
   723	
   724			p4 := s.Prog(mips.ASC)
   725			p4.From.Type = obj.TYPE_REG
   726			p4.From.Reg = v.Reg0()
   727			p4.To.Type = obj.TYPE_MEM
   728			p4.To.Reg = v.Args[0].Reg()
   729	
   730			p5 := s.Prog(mips.ABEQ)
   731			p5.From.Type = obj.TYPE_REG
   732			p5.From.Reg = v.Reg0()
   733			p5.To.Type = obj.TYPE_BRANCH
   734			gc.Patch(p5, p1)
   735	
   736			s.Prog(mips.ASYNC)
   737	
   738			p6 := s.Prog(obj.ANOP)
   739			gc.Patch(p2, p6)
   740	
   741		case ssa.OpMIPSLoweredNilCheck:
   742			// Issue a load which will fault if arg is nil.
   743			p := s.Prog(mips.AMOVB)
   744			p.From.Type = obj.TYPE_MEM
   745			p.From.Reg = v.Args[0].Reg()
   746			gc.AddAux(&p.From, v)
   747			p.To.Type = obj.TYPE_REG
   748			p.To.Reg = mips.REGTMP
   749			if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
   750				gc.Warnl(v.Pos, "generated nil check")
   751			}
   752		case ssa.OpMIPSFPFlagTrue,
   753			ssa.OpMIPSFPFlagFalse:
   754			// MOVW		$1, r
   755			// CMOVF	R0, r
   756	
   757			cmov := mips.ACMOVF
   758			if v.Op == ssa.OpMIPSFPFlagFalse {
   759				cmov = mips.ACMOVT
   760			}
   761			p := s.Prog(mips.AMOVW)
   762			p.From.Type = obj.TYPE_CONST
   763			p.From.Offset = 1
   764			p.To.Type = obj.TYPE_REG
   765			p.To.Reg = v.Reg()
   766			p1 := s.Prog(cmov)
   767			p1.From.Type = obj.TYPE_REG
   768			p1.From.Reg = mips.REGZERO
   769			p1.To.Type = obj.TYPE_REG
   770			p1.To.Reg = v.Reg()
   771	
   772		case ssa.OpMIPSLoweredGetClosurePtr:
   773			// Closure pointer is R22 (mips.REGCTXT).
   774			gc.CheckLoweredGetClosurePtr(v)
   775		case ssa.OpMIPSLoweredGetCallerSP:
   776			// caller's SP is FixedFrameSize below the address of the first arg
   777			p := s.Prog(mips.AMOVW)
   778			p.From.Type = obj.TYPE_ADDR
   779			p.From.Offset = -gc.Ctxt.FixedFrameSize()
   780			p.From.Name = obj.NAME_PARAM
   781			p.To.Type = obj.TYPE_REG
   782			p.To.Reg = v.Reg()
   783		case ssa.OpMIPSLoweredGetCallerPC:
   784			p := s.Prog(obj.AGETCALLERPC)
   785			p.To.Type = obj.TYPE_REG
   786			p.To.Reg = v.Reg()
   787		case ssa.OpClobber:
   788			// TODO: implement for clobberdead experiment. Nop is ok for now.
   789		default:
   790			v.Fatalf("genValue not implemented: %s", v.LongString())
   791		}
   792	}
   793	
   794	var blockJump = map[ssa.BlockKind]struct {
   795		asm, invasm obj.As
   796	}{
   797		ssa.BlockMIPSEQ:  {mips.ABEQ, mips.ABNE},
   798		ssa.BlockMIPSNE:  {mips.ABNE, mips.ABEQ},
   799		ssa.BlockMIPSLTZ: {mips.ABLTZ, mips.ABGEZ},
   800		ssa.BlockMIPSGEZ: {mips.ABGEZ, mips.ABLTZ},
   801		ssa.BlockMIPSLEZ: {mips.ABLEZ, mips.ABGTZ},
   802		ssa.BlockMIPSGTZ: {mips.ABGTZ, mips.ABLEZ},
   803		ssa.BlockMIPSFPT: {mips.ABFPT, mips.ABFPF},
   804		ssa.BlockMIPSFPF: {mips.ABFPF, mips.ABFPT},
   805	}
   806	
   807	func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   808		switch b.Kind {
   809		case ssa.BlockPlain:
   810			if b.Succs[0].Block() != next {
   811				p := s.Prog(obj.AJMP)
   812				p.To.Type = obj.TYPE_BRANCH
   813				s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   814			}
   815		case ssa.BlockDefer:
   816			// defer returns in R1:
   817			// 0 if we should continue executing
   818			// 1 if we should jump to deferreturn call
   819			p := s.Prog(mips.ABNE)
   820			p.From.Type = obj.TYPE_REG
   821			p.From.Reg = mips.REGZERO
   822			p.Reg = mips.REG_R1
   823			p.To.Type = obj.TYPE_BRANCH
   824			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   825			if b.Succs[0].Block() != next {
   826				p := s.Prog(obj.AJMP)
   827				p.To.Type = obj.TYPE_BRANCH
   828				s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   829			}
   830		case ssa.BlockExit:
   831		case ssa.BlockRet:
   832			s.Prog(obj.ARET)
   833		case ssa.BlockRetJmp:
   834			p := s.Prog(obj.ARET)
   835			p.To.Type = obj.TYPE_MEM
   836			p.To.Name = obj.NAME_EXTERN
   837			p.To.Sym = b.Aux.(*obj.LSym)
   838		case ssa.BlockMIPSEQ, ssa.BlockMIPSNE,
   839			ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ,
   840			ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ,
   841			ssa.BlockMIPSFPT, ssa.BlockMIPSFPF:
   842			jmp := blockJump[b.Kind]
   843			var p *obj.Prog
   844			switch next {
   845			case b.Succs[0].Block():
   846				p = s.Br(jmp.invasm, b.Succs[1].Block())
   847			case b.Succs[1].Block():
   848				p = s.Br(jmp.asm, b.Succs[0].Block())
   849			default:
   850				if b.Likely != ssa.BranchUnlikely {
   851					p = s.Br(jmp.asm, b.Succs[0].Block())
   852					s.Br(obj.AJMP, b.Succs[1].Block())
   853				} else {
   854					p = s.Br(jmp.invasm, b.Succs[1].Block())
   855					s.Br(obj.AJMP, b.Succs[0].Block())
   856				}
   857			}
   858			if !b.Control.Type.IsFlags() {
   859				p.From.Type = obj.TYPE_REG
   860				p.From.Reg = b.Control.Reg()
   861			}
   862		default:
   863			b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
   864		}
   865	}
   866	

View as plain text