gc.Thearch.MAXWIDTH = 1 << 50
gc.Thearch.Defframe = defframe
+ gc.Thearch.Ginsnop = ginsnop
gc.Thearch.Proginfo = proginfo
gc.Thearch.SSAMarkMoves = ssaMarkMoves
q.To.Type = obj.TYPE_REG
q.To.Reg = r
}
- case ssa.OpAMD64CALLstatic:
- if v.Aux.(*obj.LSym) == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an actual hardware NOP that will have the right line number.
- // This is different from obj.ANOP, which is a virtual no-op
- // that doesn't make it into the instruction stream.
- ginsnop()
- }
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = v.Aux.(*obj.LSym)
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpAMD64CALLclosure:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpAMD64CALLinter:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
+ case ssa.OpAMD64CALLstatic, ssa.OpAMD64CALLclosure, ssa.OpAMD64CALLinter:
+ s.Call(v)
case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL,
ssa.OpAMD64BSWAPQ, ssa.OpAMD64BSWAPL,
ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL:
gc.Thearch.MAXWIDTH = (1 << 32) - 1
gc.Thearch.Defframe = defframe
+ gc.Thearch.Ginsnop = ginsnop
gc.Thearch.Proginfo = proginfo
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
- case ssa.OpARMCALLstatic:
- if v.Aux.(*obj.LSym) == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an actual hardware NOP that will have the right line number.
- // This is different from obj.ANOP, which is a virtual no-op
- // that doesn't make it into the instruction stream.
- ginsnop()
- }
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = v.Aux.(*obj.LSym)
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpARMCALLclosure:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpARMCALLinter:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
+ case ssa.OpARMCALLstatic, ssa.OpARMCALLclosure, ssa.OpARMCALLinter:
+ s.Call(v)
case ssa.OpARMDUFFZERO:
p := gc.Prog(obj.ADUFFZERO)
p.To.Type = obj.TYPE_MEM
gc.Thearch.MAXWIDTH = 1 << 50
gc.Thearch.Defframe = defframe
+ gc.Thearch.Ginsnop = ginsnop
gc.Thearch.Proginfo = proginfo
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
p4 := gc.Prog(arm64.ABLE)
p4.To.Type = obj.TYPE_BRANCH
gc.Patch(p4, p)
- case ssa.OpARM64CALLstatic:
- if v.Aux.(*obj.LSym) == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an actual hardware NOP that will have the right line number.
- // This is different from obj.ANOP, which is a virtual no-op
- // that doesn't make it into the instruction stream.
- ginsnop()
- }
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = v.Aux.(*obj.LSym)
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpARM64CALLclosure:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpARM64CALLinter:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
+ case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter:
+ s.Call(v)
case ssa.OpARM64LoweredNilCheck:
// Issue a load which will fault if arg is nil.
p := gc.Prog(arm64.AMOVB)
REGSP int
MAXWIDTH int64
+ Use387 bool // should 386 backend use 387 FP instructions instead of sse2.
Defframe func(*obj.Prog)
+ Ginsnop func()
Proginfo func(*obj.Prog) ProgInfo
- Use387 bool // should 8g use 387 FP instructions instead of sse2.
// SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
SSAMarkMoves func(*SSAGenState, *ssa.Block)
a.Offset = s.ScratchFpMem.Xoffset
}
+func (s *SSAGenState) Call(v *ssa.Value) *obj.Prog {
+ if sym, _ := v.Aux.(*obj.LSym); sym == Deferreturn {
+ // Deferred calls will appear to be returning to
+ // the CALL deferreturn(SB) that we are about to emit.
+ // However, the stack trace code will show the line
+ // of the instruction byte before the return PC.
+ // To avoid that being an unrelated instruction,
+ // insert an actual hardware NOP that will have the right line number.
+ // This is different from obj.ANOP, which is a virtual no-op
+ // that doesn't make it into the instruction stream.
+ Thearch.Ginsnop()
+ }
+
+ p := Prog(obj.ACALL)
+ if sym, ok := v.Aux.(*obj.LSym); ok {
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = sym
+ } else {
+ // TODO(mdempsky): Can these differences be eliminated?
+ switch Thearch.LinkArch.Family {
+ case sys.AMD64, sys.I386, sys.PPC64, sys.S390X:
+ p.To.Type = obj.TYPE_REG
+ case sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64:
+ p.To.Type = obj.TYPE_MEM
+ default:
+ Fatalf("unknown indirect call family")
+ }
+ p.To.Reg = v.Args[0].Reg()
+ }
+ if Maxarg < v.AuxInt {
+ Maxarg = v.AuxInt
+ }
+ return p
+}
+
// fieldIdx finds the index of the field referred to by the ODOT node n.
func fieldIdx(n *Node) int {
t := n.Left.Type
gc.Thearch.REGSP = mips.REGSP
gc.Thearch.MAXWIDTH = (1 << 31) - 1
gc.Thearch.Defframe = defframe
+ gc.Thearch.Ginsnop = ginsnop
gc.Thearch.Proginfo = proginfo
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
gc.Thearch.SSAGenValue = ssaGenValue
p6.Reg = mips.REG_R1
p6.To.Type = obj.TYPE_BRANCH
gc.Patch(p6, p2)
- case ssa.OpMIPSCALLstatic:
- if v.Aux.(*obj.LSym) == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an actual hardware NOP that will have the right line number.
- // This is different from obj.ANOP, which is a virtual no-op
- // that doesn't make it into the instruction stream.
- ginsnop()
- }
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = v.Aux.(*obj.LSym)
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpMIPSCALLclosure:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpMIPSCALLinter:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
+ case ssa.OpMIPSCALLstatic, ssa.OpMIPSCALLclosure, ssa.OpMIPSCALLinter:
+ s.Call(v)
case ssa.OpMIPSLoweredAtomicLoad:
gc.Prog(mips.ASYNC)
gc.Thearch.MAXWIDTH = 1 << 50
gc.Thearch.Defframe = defframe
+ gc.Thearch.Ginsnop = ginsnop
gc.Thearch.Proginfo = proginfo
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
p6.Reg = mips.REG_R1
p6.To.Type = obj.TYPE_BRANCH
gc.Patch(p6, p2)
- case ssa.OpMIPS64CALLstatic:
- if v.Aux.(*obj.LSym) == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an actual hardware NOP that will have the right line number.
- // This is different from obj.ANOP, which is a virtual no-op
- // that doesn't make it into the instruction stream.
- ginsnop()
- }
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = v.Aux.(*obj.LSym)
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpMIPS64CALLclosure:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpMIPS64CALLinter:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
+ case ssa.OpMIPS64CALLstatic, ssa.OpMIPS64CALLclosure, ssa.OpMIPS64CALLinter:
+ s.Call(v)
case ssa.OpMIPS64LoweredNilCheck:
// Issue a load which will fault if arg is nil.
p := gc.Prog(mips.AMOVB)
gc.Thearch.MAXWIDTH = 1 << 50
gc.Thearch.Defframe = defframe
+ gc.Thearch.Ginsnop = ginsnop2
gc.Thearch.Proginfo = proginfo
gc.Thearch.SSAMarkMoves = ssaMarkMoves
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REG_R0
}
+
+func ginsnop2() {
+ // PPC64 is unusual because TWO nops are required
+ // (see gc/cgen.go, gc/plive.go -- copy of comment below)
+ //
+ // On ppc64, when compiling Go into position
+ // independent code on ppc64le we insert an
+ // instruction to reload the TOC pointer from the
+ // stack as well. See the long comment near
+ // jmpdefer in runtime/asm_ppc64.s for why.
+ // If the MOVD is not needed, insert a hardware NOP
+ // so that the same number of instructions are used
+ // on ppc64 in both shared and non-shared modes.
+
+ ginsnop()
+ if gc.Ctxt.Flag_shared {
+ p := gc.Prog(ppc64.AMOVD)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Offset = 24
+ p.From.Reg = ppc64.REGSP
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = ppc64.REG_R2
+ } else {
+ ginsnop()
+ }
+}
gc.Patch(p4, p)
case ssa.OpPPC64CALLstatic:
- if v.Aux.(*obj.LSym) == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert two actual hardware NOPs that will have the right line number.
- // This is different from obj.ANOP, which is a virtual no-op
- // that doesn't make it into the instruction stream.
- // PPC64 is unusual because TWO nops are required
- // (see gc/cgen.go, gc/plive.go -- copy of comment below)
- //
- // On ppc64, when compiling Go into position
- // independent code on ppc64le we insert an
- // instruction to reload the TOC pointer from the
- // stack as well. See the long comment near
- // jmpdefer in runtime/asm_ppc64.s for why.
- // If the MOVD is not needed, insert a hardware NOP
- // so that the same number of instructions are used
- // on ppc64 in both shared and non-shared modes.
- ginsnop()
- if gc.Ctxt.Flag_shared {
- p := gc.Prog(ppc64.AMOVD)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = 24
- p.From.Reg = ppc64.REGSP
- p.To.Type = obj.TYPE_REG
- p.To.Reg = ppc64.REG_R2
- } else {
- ginsnop()
- }
- }
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = v.Aux.(*obj.LSym)
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
+ s.Call(v)
case ssa.OpPPC64CALLclosure, ssa.OpPPC64CALLinter:
p := gc.Prog(ppc64.AMOVD)
q.To.Reg = ppc64.REG_R12
}
- pp := gc.Prog(obj.ACALL)
- pp.To.Type = obj.TYPE_REG
+ pp := s.Call(v)
pp.To.Reg = ppc64.REG_CTR
if gc.Ctxt.Flag_shared {
q.To.Reg = ppc64.REG_R2
}
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
-
case ssa.OpPPC64LoweredNilCheck:
// Issue a load which will fault if arg is nil.
p := gc.Prog(ppc64.AMOVBZ)
gc.Thearch.MAXWIDTH = 1 << 50
gc.Thearch.Defframe = defframe
+ gc.Thearch.Ginsnop = ginsnop
gc.Thearch.Proginfo = proginfo
gc.Thearch.SSAMarkMoves = ssaMarkMoves
p.From.Reg = s390x.REGG
p.To.Type = obj.TYPE_REG
p.To.Reg = r
- case ssa.OpS390XCALLstatic:
- if v.Aux.(*obj.LSym) == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an actual hardware NOP that will have the right line number.
- // This is different from obj.ANOP, which is a virtual no-op
- // that doesn't make it into the instruction stream.
- ginsnop()
- }
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = v.Aux.(*obj.LSym)
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpS390XCALLclosure:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.OpS390XCALLinter:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
+ case ssa.OpS390XCALLstatic, ssa.OpS390XCALLclosure, ssa.OpS390XCALLinter:
+ s.Call(v)
case ssa.OpS390XFLOGR, ssa.OpS390XNEG, ssa.OpS390XNEGW,
ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR:
p := gc.Prog(v.Op.Asm())
gc.Thearch.MAXWIDTH = (1 << 32) - 1
gc.Thearch.Defframe = defframe
+ gc.Thearch.Ginsnop = ginsnop
gc.Thearch.Proginfo = proginfo
gc.Thearch.SSAMarkMoves = ssaMarkMoves
q.To.Type = obj.TYPE_REG
q.To.Reg = r
}
- case ssa.Op386CALLstatic:
- if v.Aux.(*obj.LSym) == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an actual hardware NOP that will have the right line number.
- // This is different from obj.ANOP, which is a virtual no-op
- // that doesn't make it into the instruction stream.
- ginsnop()
- }
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = v.Aux.(*obj.LSym)
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.Op386CALLclosure:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
- case ssa.Op386CALLinter:
- p := gc.Prog(obj.ACALL)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Args[0].Reg()
- if gc.Maxarg < v.AuxInt {
- gc.Maxarg = v.AuxInt
- }
+ case ssa.Op386CALLstatic, ssa.Op386CALLclosure, ssa.Op386CALLinter:
+ s.Call(v)
case ssa.Op386NEGL,
ssa.Op386BSWAPL,
ssa.Op386NOTL: