From: Joel Sing Date: Sun, 3 Nov 2019 16:25:53 +0000 (+1100) Subject: cmd/internal/obj/riscv: split immediates larger than 12-bits X-Git-Tag: go1.14beta1~160 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8cf5293caa7071601fa90358abdd20a0b787e178;p=gostls13.git cmd/internal/obj/riscv: split immediates larger than 12-bits Handle immediates larger than 12-bits by rewriting as an LUI instruction with the high bits, followed by the original instruction with the low bits. Based on the riscv-go port. Updates #27532 Change-Id: I8ed6d6e6db06fb8a27f3ab75f467ec2b7ff1f075 Reviewed-on: https://go-review.googlesource.com/c/go/+/204626 Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot --- diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index b90be07163..0325b4d40f 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -486,6 +486,116 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { } } + // Split immediates larger than 12-bits. + for p := cursym.Func.Text; p != nil; p = p.Link { + switch p.As { + // $imm, REG, TO + case AADDI, AANDI, AORI, AXORI: + // LUI $high, TMP + // ADDI $low, TMP, TMP + // TMP, REG, TO + q := *p + low, high, err := Split32BitImmediate(p.From.Offset) + if err != nil { + ctxt.Diag("%v: constant %d too large", p, p.From.Offset, err) + } + if high == 0 { + break // no need to split + } + + p.As = ALUI + p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high} + p.Reg = 0 + p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p.Spadj = 0 // needed if TO is SP + p = obj.Appendp(p, newprog) + + p.As = AADDIW + p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low} + p.Reg = REG_TMP + p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p = obj.Appendp(p, newprog) + + switch q.As { + case AADDI: + p.As = AADD + case AANDI: + p.As = AAND + case AORI: + p.As = AOR + case AXORI: + p.As = AXOR + default: + ctxt.Diag("progedit: unsupported inst %v for splitting", q) + } + p.Spadj = q.Spadj + p.To = q.To + p.Reg = q.Reg + p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + + // $imm, REG, TO (load $imm+(REG), TO) + // $imm, REG, TO (store $imm+(TO), REG) + case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, + ASD, ASB, ASH, ASW: + // LUI $high, TMP + // ADDI $low, TMP, TMP + q := *p + low, high, err := Split32BitImmediate(p.From.Offset) + if err != nil { + ctxt.Diag("%v: constant %d too large", p, p.From.Offset) + } + if high == 0 { + break // no need to split + } + + switch q.As { + case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU: + // LUI $high, TMP + // ADD TMP, REG, TMP + // $low, TMP, TO + p.As = ALUI + p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high} + p.Reg = 0 + p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p.Spadj = 0 // needed if TO is SP + p = obj.Appendp(p, newprog) + + p.As = AADD + p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p.Reg = q.Reg + p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p = obj.Appendp(p, newprog) + + p.As = q.As + p.To = q.To + p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low} + p.Reg = REG_TMP + + case ASD, ASB, ASH, ASW: + // LUI $high, TMP + // ADD TMP, TO, TMP + // $low, REG, TMP + p.As = ALUI + p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high} + p.Reg = 0 + p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p.Spadj = 0 // needed if TO is SP + p = obj.Appendp(p, newprog) + + p.As = AADD + p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p.Reg = q.To.Reg + p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p = obj.Appendp(p, newprog) + + p.As = q.As + p.Reg = q.Reg + p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} + p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low} + } + } + } + setPCs(cursym.Func.Text, 0) // Resolve branch and jump targets.