p.From.Name = obj.NAME_PARAM
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ case ssa.OpARMLoweredGetCallerPC:
+ p := s.Prog(obj.AGETCALLERPC)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
case ssa.OpARMFlagEQ,
ssa.OpARMFlagLT_ULT,
ssa.OpARMFlagLT_UGT,
},
all...)
- addF("runtime", "getcallerpc",
+ add("runtime", "getcallerpc",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
return s.newValue0(ssa.OpGetCallerPC, s.f.Config.Types.Uintptr)
- }, sys.AMD64, sys.I386, sys.ARM64)
+ },
+ all...)
add("runtime", "getcallersp",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
p.From.Name = obj.NAME_PARAM
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ case ssa.OpMIPSLoweredGetCallerPC:
+ p := s.Prog(obj.AGETCALLERPC)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
case ssa.OpClobber:
// TODO: implement for clobberdead experiment. Nop is ok for now.
default:
p.From.Name = obj.NAME_PARAM
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ case ssa.OpMIPS64LoweredGetCallerPC:
+ p := s.Prog(obj.AGETCALLERPC)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
case ssa.OpClobber:
// TODO: implement for clobberdead experiment. Nop is ok for now.
default:
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ case ssa.OpPPC64LoweredGetCallerPC:
+ p := s.Prog(obj.AGETCALLERPC)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+
case ssa.OpPPC64LoweredRound32F, ssa.OpPPC64LoweredRound64F:
// input is already rounded
p.From.Name = obj.NAME_PARAM
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ case ssa.OpS390XLoweredGetCallerPC:
+ p := s.Prog(obj.AGETCALLERPC)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
case ssa.OpS390XCALLstatic, ssa.OpS390XCALLclosure, ssa.OpS390XCALLinter:
s.Call(v)
case ssa.OpS390XLoweredWB:
// pseudo-ops
(GetClosurePtr) -> (LoweredGetClosurePtr)
(GetCallerSP) -> (LoweredGetCallerSP)
+(GetCallerPC) -> (LoweredGetCallerPC)
// Absorb pseudo-ops into blocks.
(If (Equal cc) yes no) -> (EQ cc yes no)
// LoweredGetCallerSP returns the SP of the caller of the current function.
{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
+ // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
+ // I.e., if f calls g "calls" getcallerpc,
+ // the result should be the PC within f that g will return to.
+ // See runtime/stubs.go for a more detailed discussion.
+ {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
+
// Constant flag values. For any comparison, there are 5 possible
// outcomes: the three from the signed total order (<,==,>) and the
// three from the unsigned total order. The == cases overlap.
// pseudo-ops
(GetClosurePtr) -> (LoweredGetClosurePtr)
(GetCallerSP) -> (LoweredGetCallerSP)
+(GetCallerPC) -> (LoweredGetCallerPC)
(If cond yes no) -> (NE cond yes no)
// pseudo-ops
(GetClosurePtr) -> (LoweredGetClosurePtr)
(GetCallerSP) -> (LoweredGetCallerSP)
+(GetCallerPC) -> (LoweredGetCallerPC)
(If cond yes no) -> (NE cond yes no)
// LoweredGetCallerSP returns the SP of the caller of the current function.
{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
+ // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
+ // I.e., if f calls g "calls" getcallerpc,
+ // the result should be the PC within f that g will return to.
+ // See runtime/stubs.go for a more detailed discussion.
+ {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
+
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
// It saves all GP registers if necessary,
// but clobbers R31 (LR) because it's a call
// LoweredGetCallerSP returns the SP of the caller of the current function.
{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
+ // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
+ // I.e., if f calls g "calls" getcallerpc,
+ // the result should be the PC within f that g will return to.
+ // See runtime/stubs.go for a more detailed discussion.
+ {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
+
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
// It saves all GP registers if necessary,
// but clobbers R31 (LR) because it's a call
// Miscellaneous
(GetClosurePtr) -> (LoweredGetClosurePtr)
(GetCallerSP) -> (LoweredGetCallerSP)
+(GetCallerPC) -> (LoweredGetCallerPC)
(IsNonNil ptr) -> (NotEqual (CMPconst [0] ptr))
(IsInBounds idx len) -> (LessThan (CMPU idx len))
(IsSliceInBounds idx len) -> (LessEqual (CMPU idx len))
// LoweredGetCallerSP returns the SP of the caller of the current function.
{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
+ // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
+ // I.e., if f calls g "calls" getcallerpc,
+ // the result should be the PC within f that g will return to.
+ // See runtime/stubs.go for a more detailed discussion.
+ {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
+
//arg0=ptr,arg1=mem, returns void. Faults if ptr is nil.
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
// Round ops to block fused-multiply-add extraction.
(GetG mem) -> (LoweredGetG mem)
(GetClosurePtr) -> (LoweredGetClosurePtr)
(GetCallerSP) -> (LoweredGetCallerSP)
+(GetCallerPC) -> (LoweredGetCallerPC)
(Addr {sym} base) -> (MOVDaddr {sym} base)
(ITab (Load ptr mem)) -> (MOVDload ptr mem)
// arg0=ptr,arg1=mem, returns void. Faults if ptr is nil.
// LoweredGetCallerSP returns the SP of the caller of the current function.
{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
+ // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
+ // I.e., if f calls g "calls" getcallerpc,
+ // the result should be the PC within f that g will return to.
+ // See runtime/stubs.go for a more detailed discussion.
+ {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{ptrsp}}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
// Round ops to block fused-multiply-add extraction.
{name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},
OpARMLoweredMove
OpARMLoweredGetClosurePtr
OpARMLoweredGetCallerSP
+ OpARMLoweredGetCallerPC
OpARMFlagEQ
OpARMFlagLT_ULT
OpARMFlagLT_UGT
OpMIPSFPFlagFalse
OpMIPSLoweredGetClosurePtr
OpMIPSLoweredGetCallerSP
+ OpMIPSLoweredGetCallerPC
OpMIPSLoweredWB
OpMIPS64ADDV
OpMIPS64FPFlagFalse
OpMIPS64LoweredGetClosurePtr
OpMIPS64LoweredGetCallerSP
+ OpMIPS64LoweredGetCallerPC
OpMIPS64LoweredWB
OpPPC64ADD
OpPPC64FGreaterEqual
OpPPC64LoweredGetClosurePtr
OpPPC64LoweredGetCallerSP
+ OpPPC64LoweredGetCallerPC
OpPPC64LoweredNilCheck
OpPPC64LoweredRound32F
OpPPC64LoweredRound64F
OpS390XLoweredGetG
OpS390XLoweredGetClosurePtr
OpS390XLoweredGetCallerSP
+ OpS390XLoweredGetCallerPC
OpS390XLoweredNilCheck
OpS390XLoweredRound32F
OpS390XLoweredRound64F
},
},
},
+ {
+ name: "LoweredGetCallerPC",
+ argLen: 0,
+ rematerializeable: true,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
{
name: "FlagEQ",
argLen: 0,
},
},
},
+ {
+ name: "LoweredGetCallerPC",
+ argLen: 0,
+ rematerializeable: true,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 335544318}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 R31
+ },
+ },
+ },
{
name: "LoweredWB",
auxType: auxSym,
},
},
},
+ {
+ name: "LoweredGetCallerPC",
+ argLen: 0,
+ rematerializeable: true,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
{
name: "LoweredWB",
auxType: auxSym,
},
},
},
+ {
+ name: "LoweredGetCallerPC",
+ argLen: 0,
+ rematerializeable: true,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
{
name: "LoweredNilCheck",
argLen: 2,
},
},
},
+ {
+ name: "LoweredGetCallerPC",
+ argLen: 0,
+ rematerializeable: true,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
{
name: "LoweredNilCheck",
argLen: 2,
return rewriteValueARM_OpGeq8_0(v)
case OpGeq8U:
return rewriteValueARM_OpGeq8U_0(v)
+ case OpGetCallerPC:
+ return rewriteValueARM_OpGetCallerPC_0(v)
case OpGetCallerSP:
return rewriteValueARM_OpGetCallerSP_0(v)
case OpGetClosurePtr:
return true
}
}
+func rewriteValueARM_OpGetCallerPC_0(v *Value) bool {
+ // match: (GetCallerPC)
+ // cond:
+ // result: (LoweredGetCallerPC)
+ for {
+ v.reset(OpARMLoweredGetCallerPC)
+ return true
+ }
+}
func rewriteValueARM_OpGetCallerSP_0(v *Value) bool {
// match: (GetCallerSP)
// cond:
return rewriteValueMIPS_OpGeq8_0(v)
case OpGeq8U:
return rewriteValueMIPS_OpGeq8U_0(v)
+ case OpGetCallerPC:
+ return rewriteValueMIPS_OpGetCallerPC_0(v)
case OpGetCallerSP:
return rewriteValueMIPS_OpGetCallerSP_0(v)
case OpGetClosurePtr:
return true
}
}
+func rewriteValueMIPS_OpGetCallerPC_0(v *Value) bool {
+ // match: (GetCallerPC)
+ // cond:
+ // result: (LoweredGetCallerPC)
+ for {
+ v.reset(OpMIPSLoweredGetCallerPC)
+ return true
+ }
+}
func rewriteValueMIPS_OpGetCallerSP_0(v *Value) bool {
// match: (GetCallerSP)
// cond:
return rewriteValueMIPS64_OpGeq8_0(v)
case OpGeq8U:
return rewriteValueMIPS64_OpGeq8U_0(v)
+ case OpGetCallerPC:
+ return rewriteValueMIPS64_OpGetCallerPC_0(v)
case OpGetCallerSP:
return rewriteValueMIPS64_OpGetCallerSP_0(v)
case OpGetClosurePtr:
return true
}
}
+func rewriteValueMIPS64_OpGetCallerPC_0(v *Value) bool {
+ // match: (GetCallerPC)
+ // cond:
+ // result: (LoweredGetCallerPC)
+ for {
+ v.reset(OpMIPS64LoweredGetCallerPC)
+ return true
+ }
+}
func rewriteValueMIPS64_OpGetCallerSP_0(v *Value) bool {
// match: (GetCallerSP)
// cond:
return rewriteValuePPC64_OpGeq8_0(v)
case OpGeq8U:
return rewriteValuePPC64_OpGeq8U_0(v)
+ case OpGetCallerPC:
+ return rewriteValuePPC64_OpGetCallerPC_0(v)
case OpGetCallerSP:
return rewriteValuePPC64_OpGetCallerSP_0(v)
case OpGetClosurePtr:
return true
}
}
+func rewriteValuePPC64_OpGetCallerPC_0(v *Value) bool {
+ // match: (GetCallerPC)
+ // cond:
+ // result: (LoweredGetCallerPC)
+ for {
+ v.reset(OpPPC64LoweredGetCallerPC)
+ return true
+ }
+}
func rewriteValuePPC64_OpGetCallerSP_0(v *Value) bool {
// match: (GetCallerSP)
// cond:
return rewriteValueS390X_OpGeq8_0(v)
case OpGeq8U:
return rewriteValueS390X_OpGeq8U_0(v)
+ case OpGetCallerPC:
+ return rewriteValueS390X_OpGetCallerPC_0(v)
case OpGetCallerSP:
return rewriteValueS390X_OpGetCallerSP_0(v)
case OpGetClosurePtr:
return true
}
}
+func rewriteValueS390X_OpGetCallerPC_0(v *Value) bool {
+ // match: (GetCallerPC)
+ // cond:
+ // result: (LoweredGetCallerPC)
+ for {
+ v.reset(OpS390XLoweredGetCallerPC)
+ return true
+ }
+}
func rewriteValueS390X_OpGetCallerSP_0(v *Value) bool {
// match: (GetCallerSP)
// cond:
if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
p.Spadj = int32(-p.From.Offset)
}
+
+ case obj.AGETCALLERPC:
+ if cursym.Leaf() {
+ /* MOVW LR, Rd */
+ p.As = AMOVW
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = REGLINK
+ } else {
+ /* MOVW (RSP), Rd */
+ p.As = AMOVW
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = REGSP
+ }
}
}
}
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
p.Spadj = int32(-p.From.Offset)
}
+
+ case obj.AGETCALLERPC:
+ if cursym.Leaf() {
+ /* MOV LR, Rd */
+ p.As = mov
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = REGLINK
+ } else {
+ /* MOV (RSP), Rd */
+ p.As = mov
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = REGSP
+ }
}
}
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
p.Spadj = int32(-p.From.Offset)
}
+ case obj.AGETCALLERPC:
+ if cursym.Leaf() {
+ /* MOVD LR, Rd */
+ p.As = AMOVD
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = REG_LR
+ } else {
+ /* MOVD (RSP), Rd */
+ p.As = AMOVD
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = REGSP
+ }
}
}
}
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
p.Spadj = int32(-p.From.Offset)
}
+
+ case obj.AGETCALLERPC:
+ if cursym.Leaf() {
+ /* MOVD LR, Rd */
+ p.As = AMOVD
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = REG_LR
+ } else {
+ /* MOVD (RSP), Rd */
+ p.As = AMOVD
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = REGSP
+ }
}
}
if wasSplit {
MOVW g, R0
RET
-TEXT runtime·getcallerpc(SB),NOSPLIT|NOFRAME,$0-4
- MOVW 0(R13), R0 // LR saved by caller
- MOVW R0, ret+0(FP)
- RET
-
TEXT runtime·emptyfunc(SB),0,$0-0
RET
JAL runtime·save_g(SB)
RET
-TEXT runtime·getcallerpc(SB),NOSPLIT|NOFRAME,$0-8
- MOVV 0(R29), R1 // LR saved by caller
- MOVV R1, ret+0(FP)
- RET
-
TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
MOVW (R0), R0
UNDEF
JAL runtime·save_g(SB)
RET
-TEXT runtime·getcallerpc(SB),NOSPLIT|NOFRAME,$0-4
- MOVW 0(R29), R1 // LR saved by caller
- MOVW R1, ret+0(FP)
- RET
-
TEXT runtime·abort(SB),NOSPLIT,$0-0
UNDEF
MOVD R4, LR
RET
-TEXT runtime·getcallerpc(SB),NOSPLIT|NOFRAME,$0-8
- MOVD 0(R1), R3 // LR saved by caller
- MOVD R3, ret+0(FP)
- RET
-
TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
MOVW (R0), R0
UNDEF
MOVD R1, LR
RET
-TEXT runtime·getcallerpc(SB),NOSPLIT|NOFRAME,$0-8
- MOVD 0(R15), R3 // LR saved by caller
- MOVD R3, ret+0(FP)
- RET
-
TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
MOVW (R0), R0
UNDEF