...

Source file src/pkg/cmd/internal/obj/mips/obj0.go

     1	// cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
     2	//
     3	//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     4	//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     5	//	Portions Copyright © 1997-1999 Vita Nuova Limited
     6	//	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
     7	//	Portions Copyright © 2004,2006 Bruce Ellis
     8	//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
     9	//	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
    10	//	Portions Copyright © 2009 The Go Authors. All rights reserved.
    11	//
    12	// Permission is hereby granted, free of charge, to any person obtaining a copy
    13	// of this software and associated documentation files (the "Software"), to deal
    14	// in the Software without restriction, including without limitation the rights
    15	// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    16	// copies of the Software, and to permit persons to whom the Software is
    17	// furnished to do so, subject to the following conditions:
    18	//
    19	// The above copyright notice and this permission notice shall be included in
    20	// all copies or substantial portions of the Software.
    21	//
    22	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    23	// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    24	// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    25	// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    26	// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    27	// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    28	// THE SOFTWARE.
    29	
    30	package mips
    31	
    32	import (
    33		"cmd/internal/obj"
    34		"cmd/internal/objabi"
    35		"cmd/internal/sys"
    36		"encoding/binary"
    37		"fmt"
    38		"math"
    39	)
    40	
    41	func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    42		c := ctxt0{ctxt: ctxt, newprog: newprog}
    43	
    44		p.From.Class = 0
    45		p.To.Class = 0
    46	
    47		// Rewrite JMP/JAL to symbol as TYPE_BRANCH.
    48		switch p.As {
    49		case AJMP,
    50			AJAL,
    51			ARET,
    52			obj.ADUFFZERO,
    53			obj.ADUFFCOPY:
    54			if p.To.Sym != nil {
    55				p.To.Type = obj.TYPE_BRANCH
    56			}
    57		}
    58	
    59		// Rewrite float constants to values stored in memory.
    60		switch p.As {
    61		case AMOVF:
    62			if p.From.Type == obj.TYPE_FCONST {
    63				f32 := float32(p.From.Val.(float64))
    64				if math.Float32bits(f32) == 0 {
    65					p.As = AMOVW
    66					p.From.Type = obj.TYPE_REG
    67					p.From.Reg = REGZERO
    68					break
    69				}
    70				p.From.Type = obj.TYPE_MEM
    71				p.From.Sym = ctxt.Float32Sym(f32)
    72				p.From.Name = obj.NAME_EXTERN
    73				p.From.Offset = 0
    74			}
    75	
    76		case AMOVD:
    77			if p.From.Type == obj.TYPE_FCONST {
    78				f64 := p.From.Val.(float64)
    79				if math.Float64bits(f64) == 0 && c.ctxt.Arch.Family == sys.MIPS64 {
    80					p.As = AMOVV
    81					p.From.Type = obj.TYPE_REG
    82					p.From.Reg = REGZERO
    83					break
    84				}
    85				p.From.Type = obj.TYPE_MEM
    86				p.From.Sym = ctxt.Float64Sym(f64)
    87				p.From.Name = obj.NAME_EXTERN
    88				p.From.Offset = 0
    89			}
    90	
    91			// Put >32-bit constants in memory and load them
    92		case AMOVV:
    93			if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
    94				p.From.Type = obj.TYPE_MEM
    95				p.From.Sym = ctxt.Int64Sym(p.From.Offset)
    96				p.From.Name = obj.NAME_EXTERN
    97				p.From.Offset = 0
    98			}
    99		}
   100	
   101		// Rewrite SUB constants into ADD.
   102		switch p.As {
   103		case ASUB:
   104			if p.From.Type == obj.TYPE_CONST {
   105				p.From.Offset = -p.From.Offset
   106				p.As = AADD
   107			}
   108	
   109		case ASUBU:
   110			if p.From.Type == obj.TYPE_CONST {
   111				p.From.Offset = -p.From.Offset
   112				p.As = AADDU
   113			}
   114	
   115		case ASUBV:
   116			if p.From.Type == obj.TYPE_CONST {
   117				p.From.Offset = -p.From.Offset
   118				p.As = AADDV
   119			}
   120	
   121		case ASUBVU:
   122			if p.From.Type == obj.TYPE_CONST {
   123				p.From.Offset = -p.From.Offset
   124				p.As = AADDVU
   125			}
   126		}
   127	}
   128	
   129	func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   130		// TODO(minux): add morestack short-cuts with small fixed frame-size.
   131		c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym}
   132	
   133		// a switch for enabling/disabling instruction scheduling
   134		nosched := true
   135	
   136		if c.cursym.Func.Text == nil || c.cursym.Func.Text.Link == nil {
   137			return
   138		}
   139	
   140		p := c.cursym.Func.Text
   141		textstksiz := p.To.Offset
   142		if textstksiz == -ctxt.FixedFrameSize() {
   143			// Historical way to mark NOFRAME.
   144			p.From.Sym.Set(obj.AttrNoFrame, true)
   145			textstksiz = 0
   146		}
   147		if textstksiz < 0 {
   148			c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
   149		}
   150		if p.From.Sym.NoFrame() {
   151			if textstksiz != 0 {
   152				c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
   153			}
   154		}
   155	
   156		c.cursym.Func.Args = p.To.Val.(int32)
   157		c.cursym.Func.Locals = int32(textstksiz)
   158	
   159		/*
   160		 * find leaf subroutines
   161		 * strip NOPs
   162		 * expand RET
   163		 * expand BECOME pseudo
   164		 */
   165	
   166		var q *obj.Prog
   167		var q1 *obj.Prog
   168		for p := c.cursym.Func.Text; p != nil; p = p.Link {
   169			switch p.As {
   170			/* too hard, just leave alone */
   171			case obj.ATEXT:
   172				q = p
   173	
   174				p.Mark |= LABEL | LEAF | SYNC
   175				if p.Link != nil {
   176					p.Link.Mark |= LABEL
   177				}
   178	
   179			/* too hard, just leave alone */
   180			case AMOVW,
   181				AMOVV:
   182				q = p
   183				if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL {
   184					p.Mark |= LABEL | SYNC
   185					break
   186				}
   187				if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL {
   188					p.Mark |= LABEL | SYNC
   189				}
   190	
   191			/* too hard, just leave alone */
   192			case ASYSCALL,
   193				AWORD,
   194				ATLBWR,
   195				ATLBWI,
   196				ATLBP,
   197				ATLBR:
   198				q = p
   199				p.Mark |= LABEL | SYNC
   200	
   201			case ANOR:
   202				q = p
   203				if p.To.Type == obj.TYPE_REG {
   204					if p.To.Reg == REGZERO {
   205						p.Mark |= LABEL | SYNC
   206					}
   207				}
   208	
   209			case ABGEZAL,
   210				ABLTZAL,
   211				AJAL,
   212				obj.ADUFFZERO,
   213				obj.ADUFFCOPY:
   214				c.cursym.Func.Text.Mark &^= LEAF
   215				fallthrough
   216	
   217			case AJMP,
   218				ABEQ,
   219				ABGEZ,
   220				ABGTZ,
   221				ABLEZ,
   222				ABLTZ,
   223				ABNE,
   224				ABFPT, ABFPF:
   225				if p.As == ABFPT || p.As == ABFPF {
   226					// We don't treat ABFPT and ABFPF as branches here,
   227					// so that we will always fill nop (0x0) in their
   228					// delay slot during assembly.
   229					// This is to workaround a kernel FPU emulator bug
   230					// where it uses the user stack to simulate the
   231					// instruction in the delay slot if it's not 0x0,
   232					// and somehow that leads to SIGSEGV when the kernel
   233					// jump to the stack.
   234					p.Mark |= SYNC
   235				} else {
   236					p.Mark |= BRANCH
   237				}
   238				q = p
   239				q1 = p.Pcond
   240				if q1 != nil {
   241					for q1.As == obj.ANOP {
   242						q1 = q1.Link
   243						p.Pcond = q1
   244					}
   245	
   246					if q1.Mark&LEAF == 0 {
   247						q1.Mark |= LABEL
   248					}
   249				}
   250				//else {
   251				//	p.Mark |= LABEL
   252				//}
   253				q1 = p.Link
   254				if q1 != nil {
   255					q1.Mark |= LABEL
   256				}
   257				continue
   258	
   259			case ARET:
   260				q = p
   261				if p.Link != nil {
   262					p.Link.Mark |= LABEL
   263				}
   264				continue
   265	
   266			case obj.ANOP:
   267				q1 = p.Link
   268				q.Link = q1 /* q is non-nop */
   269				q1.Mark |= p.Mark
   270				continue
   271	
   272			default:
   273				q = p
   274				continue
   275			}
   276		}
   277	
   278		var mov, add obj.As
   279		if c.ctxt.Arch.Family == sys.MIPS64 {
   280			add = AADDV
   281			mov = AMOVV
   282		} else {
   283			add = AADDU
   284			mov = AMOVW
   285		}
   286	
   287		autosize := int32(0)
   288		var p1 *obj.Prog
   289		var p2 *obj.Prog
   290		for p := c.cursym.Func.Text; p != nil; p = p.Link {
   291			o := p.As
   292			switch o {
   293			case obj.ATEXT:
   294				autosize = int32(textstksiz)
   295	
   296				if p.Mark&LEAF != 0 && autosize == 0 {
   297					// A leaf function with no locals has no frame.
   298					p.From.Sym.Set(obj.AttrNoFrame, true)
   299				}
   300	
   301				if !p.From.Sym.NoFrame() {
   302					// If there is a stack frame at all, it includes
   303					// space to save the LR.
   304					autosize += int32(c.ctxt.FixedFrameSize())
   305				}
   306	
   307				if autosize&4 != 0 && c.ctxt.Arch.Family == sys.MIPS64 {
   308					autosize += 4
   309				}
   310	
   311				if autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
   312					if c.cursym.Func.Text.From.Sym.NoSplit() {
   313						if ctxt.Debugvlog {
   314							ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
   315						}
   316	
   317						c.cursym.Func.Text.Mark |= LEAF
   318					}
   319				}
   320	
   321				p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
   322	
   323				if c.cursym.Func.Text.Mark&LEAF != 0 {
   324					c.cursym.Set(obj.AttrLeaf, true)
   325					if p.From.Sym.NoFrame() {
   326						break
   327					}
   328				}
   329	
   330				if !p.From.Sym.NoSplit() {
   331					p = c.stacksplit(p, autosize) // emit split check
   332				}
   333	
   334				q = p
   335	
   336				if autosize != 0 {
   337					// Make sure to save link register for non-empty frame, even if
   338					// it is a leaf function, so that traceback works.
   339					// Store link register before decrement SP, so if a signal comes
   340					// during the execution of the function prologue, the traceback
   341					// code will not see a half-updated stack frame.
   342					q = obj.Appendp(q, newprog)
   343					q.As = mov
   344					q.Pos = p.Pos
   345					q.From.Type = obj.TYPE_REG
   346					q.From.Reg = REGLINK
   347					q.To.Type = obj.TYPE_MEM
   348					q.To.Offset = int64(-autosize)
   349					q.To.Reg = REGSP
   350	
   351					q = obj.Appendp(q, newprog)
   352					q.As = add
   353					q.Pos = p.Pos
   354					q.From.Type = obj.TYPE_CONST
   355					q.From.Offset = int64(-autosize)
   356					q.To.Type = obj.TYPE_REG
   357					q.To.Reg = REGSP
   358					q.Spadj = +autosize
   359				}
   360	
   361				if c.cursym.Func.Text.From.Sym.Wrapper() && c.cursym.Func.Text.Mark&LEAF == 0 {
   362					// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
   363					//
   364					//	MOV	g_panic(g), R1
   365					//	BEQ	R1, end
   366					//	MOV	panic_argp(R1), R2
   367					//	ADD	$(autosize+FIXED_FRAME), R29, R3
   368					//	BNE	R2, R3, end
   369					//	ADD	$FIXED_FRAME, R29, R2
   370					//	MOV	R2, panic_argp(R1)
   371					// end:
   372					//	NOP
   373					//
   374					// The NOP is needed to give the jumps somewhere to land.
   375					// It is a liblink NOP, not an mips NOP: it encodes to 0 instruction bytes.
   376					//
   377					// We don't generate this for leafs because that means the wrapped
   378					// function was inlined into the wrapper.
   379	
   380					q = obj.Appendp(q, newprog)
   381	
   382					q.As = mov
   383					q.From.Type = obj.TYPE_MEM
   384					q.From.Reg = REGG
   385					q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
   386					q.To.Type = obj.TYPE_REG
   387					q.To.Reg = REG_R1
   388	
   389					q = obj.Appendp(q, newprog)
   390					q.As = ABEQ
   391					q.From.Type = obj.TYPE_REG
   392					q.From.Reg = REG_R1
   393					q.To.Type = obj.TYPE_BRANCH
   394					q.Mark |= BRANCH
   395					p1 = q
   396	
   397					q = obj.Appendp(q, newprog)
   398					q.As = mov
   399					q.From.Type = obj.TYPE_MEM
   400					q.From.Reg = REG_R1
   401					q.From.Offset = 0 // Panic.argp
   402					q.To.Type = obj.TYPE_REG
   403					q.To.Reg = REG_R2
   404	
   405					q = obj.Appendp(q, newprog)
   406					q.As = add
   407					q.From.Type = obj.TYPE_CONST
   408					q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
   409					q.Reg = REGSP
   410					q.To.Type = obj.TYPE_REG
   411					q.To.Reg = REG_R3
   412	
   413					q = obj.Appendp(q, newprog)
   414					q.As = ABNE
   415					q.From.Type = obj.TYPE_REG
   416					q.From.Reg = REG_R2
   417					q.Reg = REG_R3
   418					q.To.Type = obj.TYPE_BRANCH
   419					q.Mark |= BRANCH
   420					p2 = q
   421	
   422					q = obj.Appendp(q, newprog)
   423					q.As = add
   424					q.From.Type = obj.TYPE_CONST
   425					q.From.Offset = ctxt.FixedFrameSize()
   426					q.Reg = REGSP
   427					q.To.Type = obj.TYPE_REG
   428					q.To.Reg = REG_R2
   429	
   430					q = obj.Appendp(q, newprog)
   431					q.As = mov
   432					q.From.Type = obj.TYPE_REG
   433					q.From.Reg = REG_R2
   434					q.To.Type = obj.TYPE_MEM
   435					q.To.Reg = REG_R1
   436					q.To.Offset = 0 // Panic.argp
   437	
   438					q = obj.Appendp(q, newprog)
   439	
   440					q.As = obj.ANOP
   441					p1.Pcond = q
   442					p2.Pcond = q
   443				}
   444	
   445			case ARET:
   446				if p.From.Type == obj.TYPE_CONST {
   447					ctxt.Diag("using BECOME (%v) is not supported!", p)
   448					break
   449				}
   450	
   451				retSym := p.To.Sym
   452				p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
   453				p.To.Sym = nil
   454	
   455				if c.cursym.Func.Text.Mark&LEAF != 0 {
   456					if autosize == 0 {
   457						p.As = AJMP
   458						p.From = obj.Addr{}
   459						if retSym != nil { // retjmp
   460							p.To.Type = obj.TYPE_BRANCH
   461							p.To.Name = obj.NAME_EXTERN
   462							p.To.Sym = retSym
   463						} else {
   464							p.To.Type = obj.TYPE_MEM
   465							p.To.Reg = REGLINK
   466							p.To.Offset = 0
   467						}
   468						p.Mark |= BRANCH
   469						break
   470					}
   471	
   472					p.As = add
   473					p.From.Type = obj.TYPE_CONST
   474					p.From.Offset = int64(autosize)
   475					p.To.Type = obj.TYPE_REG
   476					p.To.Reg = REGSP
   477					p.Spadj = -autosize
   478	
   479					q = c.newprog()
   480					q.As = AJMP
   481					q.Pos = p.Pos
   482					q.To.Type = obj.TYPE_MEM
   483					q.To.Offset = 0
   484					q.To.Reg = REGLINK
   485					q.Mark |= BRANCH
   486					q.Spadj = +autosize
   487	
   488					q.Link = p.Link
   489					p.Link = q
   490					break
   491				}
   492	
   493				p.As = mov
   494				p.From.Type = obj.TYPE_MEM
   495				p.From.Offset = 0
   496				p.From.Reg = REGSP
   497				p.To.Type = obj.TYPE_REG
   498				p.To.Reg = REGLINK
   499	
   500				if autosize != 0 {
   501					q = c.newprog()
   502					q.As = add
   503					q.Pos = p.Pos
   504					q.From.Type = obj.TYPE_CONST
   505					q.From.Offset = int64(autosize)
   506					q.To.Type = obj.TYPE_REG
   507					q.To.Reg = REGSP
   508					q.Spadj = -autosize
   509	
   510					q.Link = p.Link
   511					p.Link = q
   512				}
   513	
   514				q1 = c.newprog()
   515				q1.As = AJMP
   516				q1.Pos = p.Pos
   517				if retSym != nil { // retjmp
   518					q1.To.Type = obj.TYPE_BRANCH
   519					q1.To.Name = obj.NAME_EXTERN
   520					q1.To.Sym = retSym
   521				} else {
   522					q1.To.Type = obj.TYPE_MEM
   523					q1.To.Offset = 0
   524					q1.To.Reg = REGLINK
   525				}
   526				q1.Mark |= BRANCH
   527				q1.Spadj = +autosize
   528	
   529				q1.Link = q.Link
   530				q.Link = q1
   531	
   532			case AADD,
   533				AADDU,
   534				AADDV,
   535				AADDVU:
   536				if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   537					p.Spadj = int32(-p.From.Offset)
   538				}
   539	
   540			case obj.AGETCALLERPC:
   541				if cursym.Leaf() {
   542					/* MOV LR, Rd */
   543					p.As = mov
   544					p.From.Type = obj.TYPE_REG
   545					p.From.Reg = REGLINK
   546				} else {
   547					/* MOV (RSP), Rd */
   548					p.As = mov
   549					p.From.Type = obj.TYPE_MEM
   550					p.From.Reg = REGSP
   551				}
   552			}
   553		}
   554	
   555		if c.ctxt.Arch.Family == sys.MIPS {
   556			// rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
   557			for p = c.cursym.Func.Text; p != nil; p = p1 {
   558				p1 = p.Link
   559	
   560				if p.As != AMOVD {
   561					continue
   562				}
   563				if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM {
   564					continue
   565				}
   566	
   567				p.As = AMOVF
   568				q = c.newprog()
   569				*q = *p
   570				q.Link = p.Link
   571				p.Link = q
   572				p1 = q.Link
   573	
   574				var addrOff int64
   575				if c.ctxt.Arch.ByteOrder == binary.BigEndian {
   576					addrOff = 4 // swap load/save order
   577				}
   578				if p.From.Type == obj.TYPE_MEM {
   579					reg := REG_F0 + (p.To.Reg-REG_F0)&^1
   580					p.To.Reg = reg
   581					q.To.Reg = reg + 1
   582					p.From.Offset += addrOff
   583					q.From.Offset += 4 - addrOff
   584				} else if p.To.Type == obj.TYPE_MEM {
   585					reg := REG_F0 + (p.From.Reg-REG_F0)&^1
   586					p.From.Reg = reg
   587					q.From.Reg = reg + 1
   588					p.To.Offset += addrOff
   589					q.To.Offset += 4 - addrOff
   590				}
   591			}
   592		}
   593	
   594		if nosched {
   595			// if we don't do instruction scheduling, simply add
   596			// NOP after each branch instruction.
   597			for p = c.cursym.Func.Text; p != nil; p = p.Link {
   598				if p.Mark&BRANCH != 0 {
   599					c.addnop(p)
   600				}
   601			}
   602			return
   603		}
   604	
   605		// instruction scheduling
   606		q = nil                 // p - 1
   607		q1 = c.cursym.Func.Text // top of block
   608		o := 0                  // count of instructions
   609		for p = c.cursym.Func.Text; p != nil; p = p1 {
   610			p1 = p.Link
   611			o++
   612			if p.Mark&NOSCHED != 0 {
   613				if q1 != p {
   614					c.sched(q1, q)
   615				}
   616				for ; p != nil; p = p.Link {
   617					if p.Mark&NOSCHED == 0 {
   618						break
   619					}
   620					q = p
   621				}
   622				p1 = p
   623				q1 = p
   624				o = 0
   625				continue
   626			}
   627			if p.Mark&(LABEL|SYNC) != 0 {
   628				if q1 != p {
   629					c.sched(q1, q)
   630				}
   631				q1 = p
   632				o = 1
   633			}
   634			if p.Mark&(BRANCH|SYNC) != 0 {
   635				c.sched(q1, p)
   636				q1 = p1
   637				o = 0
   638			}
   639			if o >= NSCHED {
   640				c.sched(q1, p)
   641				q1 = p1
   642				o = 0
   643			}
   644			q = p
   645		}
   646	}
   647	
   648	func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
   649		var mov, add, sub obj.As
   650	
   651		if c.ctxt.Arch.Family == sys.MIPS64 {
   652			add = AADDV
   653			mov = AMOVV
   654			sub = ASUBVU
   655		} else {
   656			add = AADDU
   657			mov = AMOVW
   658			sub = ASUBU
   659		}
   660	
   661		// MOV	g_stackguard(g), R1
   662		p = obj.Appendp(p, c.newprog)
   663	
   664		p.As = mov
   665		p.From.Type = obj.TYPE_MEM
   666		p.From.Reg = REGG
   667		p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
   668		if c.cursym.CFunc() {
   669			p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
   670		}
   671		p.To.Type = obj.TYPE_REG
   672		p.To.Reg = REG_R1
   673	
   674		var q *obj.Prog
   675		if framesize <= objabi.StackSmall {
   676			// small stack: SP < stackguard
   677			//	AGTU	SP, stackguard, R1
   678			p = obj.Appendp(p, c.newprog)
   679	
   680			p.As = ASGTU
   681			p.From.Type = obj.TYPE_REG
   682			p.From.Reg = REGSP
   683			p.Reg = REG_R1
   684			p.To.Type = obj.TYPE_REG
   685			p.To.Reg = REG_R1
   686		} else if framesize <= objabi.StackBig {
   687			// large stack: SP-framesize < stackguard-StackSmall
   688			//	ADD	$-(framesize-StackSmall), SP, R2
   689			//	SGTU	R2, stackguard, R1
   690			p = obj.Appendp(p, c.newprog)
   691	
   692			p.As = add
   693			p.From.Type = obj.TYPE_CONST
   694			p.From.Offset = -(int64(framesize) - objabi.StackSmall)
   695			p.Reg = REGSP
   696			p.To.Type = obj.TYPE_REG
   697			p.To.Reg = REG_R2
   698	
   699			p = obj.Appendp(p, c.newprog)
   700			p.As = ASGTU
   701			p.From.Type = obj.TYPE_REG
   702			p.From.Reg = REG_R2
   703			p.Reg = REG_R1
   704			p.To.Type = obj.TYPE_REG
   705			p.To.Reg = REG_R1
   706		} else {
   707			// Such a large stack we need to protect against wraparound.
   708			// If SP is close to zero:
   709			//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   710			// The +StackGuard on both sides is required to keep the left side positive:
   711			// SP is allowed to be slightly below stackguard. See stack.h.
   712			//
   713			// Preemption sets stackguard to StackPreempt, a very large value.
   714			// That breaks the math above, so we have to check for that explicitly.
   715			//	// stackguard is R1
   716			//	MOV	$StackPreempt, R2
   717			//	BEQ	R1, R2, label-of-call-to-morestack
   718			//	ADD	$StackGuard, SP, R2
   719			//	SUB	R1, R2
   720			//	MOV	$(framesize+(StackGuard-StackSmall)), R1
   721			//	SGTU	R2, R1, R1
   722			p = obj.Appendp(p, c.newprog)
   723	
   724			p.As = mov
   725			p.From.Type = obj.TYPE_CONST
   726			p.From.Offset = objabi.StackPreempt
   727			p.To.Type = obj.TYPE_REG
   728			p.To.Reg = REG_R2
   729	
   730			p = obj.Appendp(p, c.newprog)
   731			q = p
   732			p.As = ABEQ
   733			p.From.Type = obj.TYPE_REG
   734			p.From.Reg = REG_R1
   735			p.Reg = REG_R2
   736			p.To.Type = obj.TYPE_BRANCH
   737			p.Mark |= BRANCH
   738	
   739			p = obj.Appendp(p, c.newprog)
   740			p.As = add
   741			p.From.Type = obj.TYPE_CONST
   742			p.From.Offset = int64(objabi.StackGuard)
   743			p.Reg = REGSP
   744			p.To.Type = obj.TYPE_REG
   745			p.To.Reg = REG_R2
   746	
   747			p = obj.Appendp(p, c.newprog)
   748			p.As = sub
   749			p.From.Type = obj.TYPE_REG
   750			p.From.Reg = REG_R1
   751			p.To.Type = obj.TYPE_REG
   752			p.To.Reg = REG_R2
   753	
   754			p = obj.Appendp(p, c.newprog)
   755			p.As = mov
   756			p.From.Type = obj.TYPE_CONST
   757			p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
   758			p.To.Type = obj.TYPE_REG
   759			p.To.Reg = REG_R1
   760	
   761			p = obj.Appendp(p, c.newprog)
   762			p.As = ASGTU
   763			p.From.Type = obj.TYPE_REG
   764			p.From.Reg = REG_R2
   765			p.Reg = REG_R1
   766			p.To.Type = obj.TYPE_REG
   767			p.To.Reg = REG_R1
   768		}
   769	
   770		// q1: BNE	R1, done
   771		p = obj.Appendp(p, c.newprog)
   772		q1 := p
   773	
   774		p.As = ABNE
   775		p.From.Type = obj.TYPE_REG
   776		p.From.Reg = REG_R1
   777		p.To.Type = obj.TYPE_BRANCH
   778		p.Mark |= BRANCH
   779	
   780		// MOV	LINK, R3
   781		p = obj.Appendp(p, c.newprog)
   782	
   783		p.As = mov
   784		p.From.Type = obj.TYPE_REG
   785		p.From.Reg = REGLINK
   786		p.To.Type = obj.TYPE_REG
   787		p.To.Reg = REG_R3
   788		if q != nil {
   789			q.Pcond = p
   790			p.Mark |= LABEL
   791		}
   792	
   793		p = c.ctxt.EmitEntryLiveness(c.cursym, p, c.newprog)
   794	
   795		// JAL	runtime.morestack(SB)
   796		p = obj.Appendp(p, c.newprog)
   797	
   798		p.As = AJAL
   799		p.To.Type = obj.TYPE_BRANCH
   800		if c.cursym.CFunc() {
   801			p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
   802		} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
   803			p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
   804		} else {
   805			p.To.Sym = c.ctxt.Lookup("runtime.morestack")
   806		}
   807		p.Mark |= BRANCH
   808	
   809		// JMP	start
   810		p = obj.Appendp(p, c.newprog)
   811	
   812		p.As = AJMP
   813		p.To.Type = obj.TYPE_BRANCH
   814		p.Pcond = c.cursym.Func.Text.Link
   815		p.Mark |= BRANCH
   816	
   817		// placeholder for q1's jump target
   818		p = obj.Appendp(p, c.newprog)
   819	
   820		p.As = obj.ANOP // zero-width place holder
   821		q1.Pcond = p
   822	
   823		return p
   824	}
   825	
   826	func (c *ctxt0) addnop(p *obj.Prog) {
   827		q := c.newprog()
   828		q.As = ANOOP
   829		q.Pos = p.Pos
   830		q.Link = p.Link
   831		p.Link = q
   832	}
   833	
   834	const (
   835		E_HILO  = 1 << 0
   836		E_FCR   = 1 << 1
   837		E_MCR   = 1 << 2
   838		E_MEM   = 1 << 3
   839		E_MEMSP = 1 << 4 /* uses offset and size */
   840		E_MEMSB = 1 << 5 /* uses offset and size */
   841		ANYMEM  = E_MEM | E_MEMSP | E_MEMSB
   842		//DELAY = LOAD|BRANCH|FCMP
   843		DELAY = BRANCH /* only schedule branch */
   844	)
   845	
   846	type Dep struct {
   847		ireg uint32
   848		freg uint32
   849		cc   uint32
   850	}
   851	
   852	type Sch struct {
   853		p       obj.Prog
   854		set     Dep
   855		used    Dep
   856		soffset int32
   857		size    uint8
   858		nop     uint8
   859		comp    bool
   860	}
   861	
   862	func (c *ctxt0) sched(p0, pe *obj.Prog) {
   863		var sch [NSCHED]Sch
   864	
   865		/*
   866		 * build side structure
   867		 */
   868		s := sch[:]
   869		for p := p0; ; p = p.Link {
   870			s[0].p = *p
   871			c.markregused(&s[0])
   872			if p == pe {
   873				break
   874			}
   875			s = s[1:]
   876		}
   877		se := s
   878	
   879		for i := cap(sch) - cap(se); i >= 0; i-- {
   880			s = sch[i:]
   881			if s[0].p.Mark&DELAY == 0 {
   882				continue
   883			}
   884			if -cap(s) < -cap(se) {
   885				if !conflict(&s[0], &s[1]) {
   886					continue
   887				}
   888			}
   889	
   890			var t []Sch
   891			var j int
   892			for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
   893				t = sch[j:]
   894				if t[0].comp {
   895					if s[0].p.Mark&BRANCH != 0 {
   896						continue
   897					}
   898				}
   899				if t[0].p.Mark&DELAY != 0 {
   900					if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
   901						continue
   902					}
   903				}
   904				for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
   905					if c.depend(&u[0], &t[0]) {
   906						continue
   907					}
   908				}
   909				goto out2
   910			}
   911	
   912			if s[0].p.Mark&BRANCH != 0 {
   913				s[0].nop = 1
   914			}
   915			continue
   916	
   917		out2:
   918			// t[0] is the instruction being moved to fill the delay
   919			stmp := t[0]
   920			copy(t[:i-j], t[1:i-j+1])
   921			s[0] = stmp
   922	
   923			if t[i-j-1].p.Mark&BRANCH != 0 {
   924				// t[i-j] is being put into a branch delay slot
   925				// combine its Spadj with the branch instruction
   926				t[i-j-1].p.Spadj += t[i-j].p.Spadj
   927				t[i-j].p.Spadj = 0
   928			}
   929	
   930			i--
   931		}
   932	
   933		/*
   934		 * put it all back
   935		 */
   936		var p *obj.Prog
   937		var q *obj.Prog
   938		for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
   939			q = p.Link
   940			if q != s[0].p.Link {
   941				*p = s[0].p
   942				p.Link = q
   943			}
   944			for s[0].nop != 0 {
   945				s[0].nop--
   946				c.addnop(p)
   947			}
   948		}
   949	}
   950	
   951	func (c *ctxt0) markregused(s *Sch) {
   952		p := &s.p
   953		s.comp = c.compound(p)
   954		s.nop = 0
   955		if s.comp {
   956			s.set.ireg |= 1 << (REGTMP - REG_R0)
   957			s.used.ireg |= 1 << (REGTMP - REG_R0)
   958		}
   959	
   960		ar := 0  /* dest is really reference */
   961		ad := 0  /* source/dest is really address */
   962		ld := 0  /* opcode is load instruction */
   963		sz := 20 /* size of load/store for overlap computation */
   964	
   965		/*
   966		 * flags based on opcode
   967		 */
   968		switch p.As {
   969		case obj.ATEXT:
   970			c.autosize = int32(p.To.Offset + 8)
   971			ad = 1
   972	
   973		case AJAL:
   974			r := p.Reg
   975			if r == 0 {
   976				r = REGLINK
   977			}
   978			s.set.ireg |= 1 << uint(r-REG_R0)
   979			ar = 1
   980			ad = 1
   981	
   982		case ABGEZAL,
   983			ABLTZAL:
   984			s.set.ireg |= 1 << (REGLINK - REG_R0)
   985			fallthrough
   986		case ABEQ,
   987			ABGEZ,
   988			ABGTZ,
   989			ABLEZ,
   990			ABLTZ,
   991			ABNE:
   992			ar = 1
   993			ad = 1
   994	
   995		case ABFPT,
   996			ABFPF:
   997			ad = 1
   998			s.used.cc |= E_FCR
   999	
  1000		case ACMPEQD,
  1001			ACMPEQF,
  1002			ACMPGED,
  1003			ACMPGEF,
  1004			ACMPGTD,
  1005			ACMPGTF:
  1006			ar = 1
  1007			s.set.cc |= E_FCR
  1008			p.Mark |= FCMP
  1009	
  1010		case AJMP:
  1011			ar = 1
  1012			ad = 1
  1013	
  1014		case AMOVB,
  1015			AMOVBU:
  1016			sz = 1
  1017			ld = 1
  1018	
  1019		case AMOVH,
  1020			AMOVHU:
  1021			sz = 2
  1022			ld = 1
  1023	
  1024		case AMOVF,
  1025			AMOVW,
  1026			AMOVWL,
  1027			AMOVWR:
  1028			sz = 4
  1029			ld = 1
  1030	
  1031		case AMOVD,
  1032			AMOVV,
  1033			AMOVVL,
  1034			AMOVVR:
  1035			sz = 8
  1036			ld = 1
  1037	
  1038		case ADIV,
  1039			ADIVU,
  1040			AMUL,
  1041			AMULU,
  1042			AREM,
  1043			AREMU,
  1044			ADIVV,
  1045			ADIVVU,
  1046			AMULV,
  1047			AMULVU,
  1048			AREMV,
  1049			AREMVU:
  1050			s.set.cc = E_HILO
  1051			fallthrough
  1052		case AADD,
  1053			AADDU,
  1054			AADDV,
  1055			AADDVU,
  1056			AAND,
  1057			ANOR,
  1058			AOR,
  1059			ASGT,
  1060			ASGTU,
  1061			ASLL,
  1062			ASRA,
  1063			ASRL,
  1064			ASLLV,
  1065			ASRAV,
  1066			ASRLV,
  1067			ASUB,
  1068			ASUBU,
  1069			ASUBV,
  1070			ASUBVU,
  1071			AXOR,
  1072	
  1073			AADDD,
  1074			AADDF,
  1075			AADDW,
  1076			ASUBD,
  1077			ASUBF,
  1078			ASUBW,
  1079			AMULF,
  1080			AMULD,
  1081			AMULW,
  1082			ADIVF,
  1083			ADIVD,
  1084			ADIVW:
  1085			if p.Reg == 0 {
  1086				if p.To.Type == obj.TYPE_REG {
  1087					p.Reg = p.To.Reg
  1088				}
  1089				//if(p->reg == NREG)
  1090				//	print("botch %P\n", p);
  1091			}
  1092		}
  1093	
  1094		/*
  1095		 * flags based on 'to' field
  1096		 */
  1097		cls := int(p.To.Class)
  1098		if cls == 0 {
  1099			cls = c.aclass(&p.To) + 1
  1100			p.To.Class = int8(cls)
  1101		}
  1102		cls--
  1103		switch cls {
  1104		default:
  1105			fmt.Printf("unknown class %d %v\n", cls, p)
  1106	
  1107		case C_ZCON,
  1108			C_SCON,
  1109			C_ADD0CON,
  1110			C_AND0CON,
  1111			C_ADDCON,
  1112			C_ANDCON,
  1113			C_UCON,
  1114			C_LCON,
  1115			C_NONE,
  1116			C_SBRA,
  1117			C_LBRA,
  1118			C_ADDR,
  1119			C_TEXTSIZE:
  1120			break
  1121	
  1122		case C_HI,
  1123			C_LO:
  1124			s.set.cc |= E_HILO
  1125	
  1126		case C_FCREG:
  1127			s.set.cc |= E_FCR
  1128	
  1129		case C_MREG:
  1130			s.set.cc |= E_MCR
  1131	
  1132		case C_ZOREG,
  1133			C_SOREG,
  1134			C_LOREG:
  1135			cls = int(p.To.Reg)
  1136			s.used.ireg |= 1 << uint(cls-REG_R0)
  1137			if ad != 0 {
  1138				break
  1139			}
  1140			s.size = uint8(sz)
  1141			s.soffset = c.regoff(&p.To)
  1142	
  1143			m := uint32(ANYMEM)
  1144			if cls == REGSB {
  1145				m = E_MEMSB
  1146			}
  1147			if cls == REGSP {
  1148				m = E_MEMSP
  1149			}
  1150	
  1151			if ar != 0 {
  1152				s.used.cc |= m
  1153			} else {
  1154				s.set.cc |= m
  1155			}
  1156	
  1157		case C_SACON,
  1158			C_LACON:
  1159			s.used.ireg |= 1 << (REGSP - REG_R0)
  1160	
  1161		case C_SECON,
  1162			C_LECON:
  1163			s.used.ireg |= 1 << (REGSB - REG_R0)
  1164	
  1165		case C_REG:
  1166			if ar != 0 {
  1167				s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
  1168			} else {
  1169				s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
  1170			}
  1171	
  1172		case C_FREG:
  1173			if ar != 0 {
  1174				s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
  1175			} else {
  1176				s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
  1177			}
  1178			if ld != 0 && p.From.Type == obj.TYPE_REG {
  1179				p.Mark |= LOAD
  1180			}
  1181	
  1182		case C_SAUTO,
  1183			C_LAUTO:
  1184			s.used.ireg |= 1 << (REGSP - REG_R0)
  1185			if ad != 0 {
  1186				break
  1187			}
  1188			s.size = uint8(sz)
  1189			s.soffset = c.regoff(&p.To)
  1190	
  1191			if ar != 0 {
  1192				s.used.cc |= E_MEMSP
  1193			} else {
  1194				s.set.cc |= E_MEMSP
  1195			}
  1196	
  1197		case C_SEXT,
  1198			C_LEXT:
  1199			s.used.ireg |= 1 << (REGSB - REG_R0)
  1200			if ad != 0 {
  1201				break
  1202			}
  1203			s.size = uint8(sz)
  1204			s.soffset = c.regoff(&p.To)
  1205	
  1206			if ar != 0 {
  1207				s.used.cc |= E_MEMSB
  1208			} else {
  1209				s.set.cc |= E_MEMSB
  1210			}
  1211		}
  1212	
  1213		/*
  1214		 * flags based on 'from' field
  1215		 */
  1216		cls = int(p.From.Class)
  1217		if cls == 0 {
  1218			cls = c.aclass(&p.From) + 1
  1219			p.From.Class = int8(cls)
  1220		}
  1221		cls--
  1222		switch cls {
  1223		default:
  1224			fmt.Printf("unknown class %d %v\n", cls, p)
  1225	
  1226		case C_ZCON,
  1227			C_SCON,
  1228			C_ADD0CON,
  1229			C_AND0CON,
  1230			C_ADDCON,
  1231			C_ANDCON,
  1232			C_UCON,
  1233			C_LCON,
  1234			C_NONE,
  1235			C_SBRA,
  1236			C_LBRA,
  1237			C_ADDR,
  1238			C_TEXTSIZE:
  1239			break
  1240	
  1241		case C_HI,
  1242			C_LO:
  1243			s.used.cc |= E_HILO
  1244	
  1245		case C_FCREG:
  1246			s.used.cc |= E_FCR
  1247	
  1248		case C_MREG:
  1249			s.used.cc |= E_MCR
  1250	
  1251		case C_ZOREG,
  1252			C_SOREG,
  1253			C_LOREG:
  1254			cls = int(p.From.Reg)
  1255			s.used.ireg |= 1 << uint(cls-REG_R0)
  1256			if ld != 0 {
  1257				p.Mark |= LOAD
  1258			}
  1259			s.size = uint8(sz)
  1260			s.soffset = c.regoff(&p.From)
  1261	
  1262			m := uint32(ANYMEM)
  1263			if cls == REGSB {
  1264				m = E_MEMSB
  1265			}
  1266			if cls == REGSP {
  1267				m = E_MEMSP
  1268			}
  1269	
  1270			s.used.cc |= m
  1271	
  1272		case C_SACON,
  1273			C_LACON:
  1274			cls = int(p.From.Reg)
  1275			if cls == 0 {
  1276				cls = REGSP
  1277			}
  1278			s.used.ireg |= 1 << uint(cls-REG_R0)
  1279	
  1280		case C_SECON,
  1281			C_LECON:
  1282			s.used.ireg |= 1 << (REGSB - REG_R0)
  1283	
  1284		case C_REG:
  1285			s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
  1286	
  1287		case C_FREG:
  1288			s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
  1289			if ld != 0 && p.To.Type == obj.TYPE_REG {
  1290				p.Mark |= LOAD
  1291			}
  1292	
  1293		case C_SAUTO,
  1294			C_LAUTO:
  1295			s.used.ireg |= 1 << (REGSP - REG_R0)
  1296			if ld != 0 {
  1297				p.Mark |= LOAD
  1298			}
  1299			if ad != 0 {
  1300				break
  1301			}
  1302			s.size = uint8(sz)
  1303			s.soffset = c.regoff(&p.From)
  1304	
  1305			s.used.cc |= E_MEMSP
  1306	
  1307		case C_SEXT:
  1308		case C_LEXT:
  1309			s.used.ireg |= 1 << (REGSB - REG_R0)
  1310			if ld != 0 {
  1311				p.Mark |= LOAD
  1312			}
  1313			if ad != 0 {
  1314				break
  1315			}
  1316			s.size = uint8(sz)
  1317			s.soffset = c.regoff(&p.From)
  1318	
  1319			s.used.cc |= E_MEMSB
  1320		}
  1321	
  1322		cls = int(p.Reg)
  1323		if cls != 0 {
  1324			if REG_F0 <= cls && cls <= REG_F31 {
  1325				s.used.freg |= 1 << uint(cls-REG_F0)
  1326			} else {
  1327				s.used.ireg |= 1 << uint(cls-REG_R0)
  1328			}
  1329		}
  1330		s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
  1331	}
  1332	
  1333	/*
  1334	 * test to see if two instructions can be
  1335	 * interchanged without changing semantics
  1336	 */
  1337	func (c *ctxt0) depend(sa, sb *Sch) bool {
  1338		if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
  1339			return true
  1340		}
  1341		if sb.set.ireg&sa.used.ireg != 0 {
  1342			return true
  1343		}
  1344	
  1345		if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
  1346			return true
  1347		}
  1348		if sb.set.freg&sa.used.freg != 0 {
  1349			return true
  1350		}
  1351	
  1352		/*
  1353		 * special case.
  1354		 * loads from same address cannot pass.
  1355		 * this is for hardware fifo's and the like
  1356		 */
  1357		if sa.used.cc&sb.used.cc&E_MEM != 0 {
  1358			if sa.p.Reg == sb.p.Reg {
  1359				if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
  1360					return true
  1361				}
  1362			}
  1363		}
  1364	
  1365		x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
  1366		if x != 0 {
  1367			/*
  1368			 * allow SB and SP to pass each other.
  1369			 * allow SB to pass SB iff doffsets are ok
  1370			 * anything else conflicts
  1371			 */
  1372			if x != E_MEMSP && x != E_MEMSB {
  1373				return true
  1374			}
  1375			x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
  1376			if x&E_MEM != 0 {
  1377				return true
  1378			}
  1379			if offoverlap(sa, sb) {
  1380				return true
  1381			}
  1382		}
  1383	
  1384		return false
  1385	}
  1386	
  1387	func offoverlap(sa, sb *Sch) bool {
  1388		if sa.soffset < sb.soffset {
  1389			if sa.soffset+int32(sa.size) > sb.soffset {
  1390				return true
  1391			}
  1392			return false
  1393		}
  1394		if sb.soffset+int32(sb.size) > sa.soffset {
  1395			return true
  1396		}
  1397		return false
  1398	}
  1399	
  1400	/*
  1401	 * test 2 adjacent instructions
  1402	 * and find out if inserted instructions
  1403	 * are desired to prevent stalls.
  1404	 */
  1405	func conflict(sa, sb *Sch) bool {
  1406		if sa.set.ireg&sb.used.ireg != 0 {
  1407			return true
  1408		}
  1409		if sa.set.freg&sb.used.freg != 0 {
  1410			return true
  1411		}
  1412		if sa.set.cc&sb.used.cc != 0 {
  1413			return true
  1414		}
  1415		return false
  1416	}
  1417	
  1418	func (c *ctxt0) compound(p *obj.Prog) bool {
  1419		o := c.oplook(p)
  1420		if o.size != 4 {
  1421			return true
  1422		}
  1423		if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
  1424			return true
  1425		}
  1426		return false
  1427	}
  1428	
  1429	var Linkmips64 = obj.LinkArch{
  1430		Arch:           sys.ArchMIPS64,
  1431		Init:           buildop,
  1432		Preprocess:     preprocess,
  1433		Assemble:       span0,
  1434		Progedit:       progedit,
  1435		DWARFRegisters: MIPSDWARFRegisters,
  1436	}
  1437	
  1438	var Linkmips64le = obj.LinkArch{
  1439		Arch:           sys.ArchMIPS64LE,
  1440		Init:           buildop,
  1441		Preprocess:     preprocess,
  1442		Assemble:       span0,
  1443		Progedit:       progedit,
  1444		DWARFRegisters: MIPSDWARFRegisters,
  1445	}
  1446	
  1447	var Linkmips = obj.LinkArch{
  1448		Arch:           sys.ArchMIPS,
  1449		Init:           buildop,
  1450		Preprocess:     preprocess,
  1451		Assemble:       span0,
  1452		Progedit:       progedit,
  1453		DWARFRegisters: MIPSDWARFRegisters,
  1454	}
  1455	
  1456	var Linkmipsle = obj.LinkArch{
  1457		Arch:           sys.ArchMIPSLE,
  1458		Init:           buildop,
  1459		Preprocess:     preprocess,
  1460		Assemble:       span0,
  1461		Progedit:       progedit,
  1462		DWARFRegisters: MIPSDWARFRegisters,
  1463	}
  1464	

View as plain text