cmd/internal/obj/loong64: recheck jump offset boundary after auto-aligning loop heads

After the alignment of the loop header is performed, the offset of the checked
conditional branch instruction may overflow, so it needs to be checked again.

When checking whether the offset of the branch jump instruction overflows, it
can be classified and processed according to the range of the immediate field
of the specific instruction, which can reduce the introduction of unnecessary
jump instructions.

Fixes #61819

Change-Id: I772a5b5b8b8de21c78d7566be30be8ff65fdbce8
Reviewed-on: https://go-review.googlesource.com/c/go/+/519915
Reviewed-by: sophie zhao <zhaoxiaolin@loongson.cn>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Meidan Li <limeidan@loongson.cn>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Run-TryBot: qiu laidongfeng2 <2645477756@qq.com>
Reviewed-by: WANG Xuerui <git@xen0n.name>
This commit is contained in:
Guoqi Chen 2023-08-16 02:09:49 +08:00 committed by Cherry Mui
parent 59209c4b35
commit f7f56ded01
2 changed files with 112 additions and 14 deletions

View file

@ -449,11 +449,8 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Run these passes until convergence.
bflag := 1
var otxt int64
var q *obj.Prog
for bflag != 0 {
bflag = 0
for {
rescan := false
pc = 0
prev := c.cursym.Func().Text
for p = prev.Link; p != nil; prev, p = p, p.Link {
@ -468,7 +465,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// because pc will be adjusted if padding happens.
if p.Mark&branchLoopHead != 0 && pc&(loopAlign-1) != 0 &&
!(prev.As == obj.APCALIGN && prev.From.Offset >= loopAlign) {
q = c.newprog()
q := c.newprog()
prev.Link = q
q.Link = p
q.Pc = pc
@ -484,18 +481,29 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// since this loop iteration is for p.
pc += int64(pcAlignPadLength(ctxt, pc, loopAlign))
p.Pc = pc
rescan = true
}
// very large conditional branches
//
// if any procedure is large enough to
// generate a large SBRA branch, then
// generate extra passes putting branches
// around jmps to fix. this is rare.
// if any procedure is large enough to generate a large SBRA branch, then
// generate extra passes putting branches around jmps to fix. this is rare.
if o.type_ == 6 && p.To.Target() != nil {
otxt = p.To.Target().Pc - pc
if otxt < -(1<<17)+10 || otxt >= (1<<17)-10 {
q = c.newprog()
otxt := p.To.Target().Pc - pc
// On loong64, the immediate value field of the conditional branch instructions
// BFPT and BFPT is 21 bits, and the others are 16 bits. The jump target address
// is to logically shift the immediate value in the instruction code to the left
// by 2 bits and then sign extend.
bound := int64(1 << (18 - 1))
switch p.As {
case ABFPT, ABFPF:
bound = int64(1 << (23 - 1))
}
if otxt < -bound || otxt >= bound {
q := c.newprog()
q.Link = p.Link
p.Link = q
q.As = AJMP
@ -510,7 +518,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Pos = p.Pos
q.To.Type = obj.TYPE_BRANCH
q.To.SetTarget(q.Link.Link)
bflag = 1
rescan = true
}
}
@ -532,7 +540,12 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
c.cursym.Size = pc
if !rescan {
break
}
}
pc += -pc & (FuncAlign - 1)
c.cursym.Size = pc