mirror of
https://github.com/golang/go
synced 2024-11-02 13:42:29 +00:00
cmd/internal/obj/riscv: avoid obj.Prog rewriting for memory stores
Rather than rewriting the obj.Prog for a MOV pseudo-instruction targeting a register to memory stores, generate the appropriate machine instruction sequence directly. Change-Id: I6eac8637e1fcb48c04d9f331cac7ae5d8cc54092 Reviewed-on: https://go-review.googlesource.com/c/go/+/344455 Trust: Joel Sing <joel@sing.id.au> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
5ec298d7b0
commit
ba66d62b68
1 changed files with 29 additions and 23 deletions
|
@ -250,7 +250,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
|
||||||
ctxt.Diag("unsupported register-register move at %v", p)
|
ctxt.Diag("unsupported register-register move at %v", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case obj.TYPE_MEM: // MOV Rs, c(Rd) -> S $c, Rs, Rd
|
case obj.TYPE_MEM:
|
||||||
switch p.As {
|
switch p.As {
|
||||||
case AMOVBU, AMOVHU, AMOVWU:
|
case AMOVBU, AMOVHU, AMOVWU:
|
||||||
ctxt.Diag("unsupported unsigned store at %v", p)
|
ctxt.Diag("unsupported unsigned store at %v", p)
|
||||||
|
@ -258,26 +258,9 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
|
||||||
}
|
}
|
||||||
switch p.To.Name {
|
switch p.To.Name {
|
||||||
case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
|
case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
|
||||||
p.As = movToStore(p.As)
|
|
||||||
p.To.Reg = addrToReg(p.To)
|
|
||||||
|
|
||||||
case obj.NAME_EXTERN, obj.NAME_STATIC:
|
case obj.NAME_EXTERN, obj.NAME_STATIC:
|
||||||
// AUIPC $off_hi, TMP
|
|
||||||
// S $off_lo, TMP, R
|
|
||||||
as := p.As
|
|
||||||
from := p.From
|
|
||||||
|
|
||||||
p.As = AAUIPC
|
|
||||||
p.Mark |= NEED_PCREL_STYPE_RELOC
|
p.Mark |= NEED_PCREL_STYPE_RELOC
|
||||||
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym})
|
|
||||||
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
|
|
||||||
p.Reg = 0
|
|
||||||
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
|
|
||||||
p = obj.Appendp(p, newprog)
|
|
||||||
|
|
||||||
p.As = movToStore(as)
|
|
||||||
p.From = from
|
|
||||||
p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: 0}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
|
ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
|
||||||
|
@ -1772,22 +1755,25 @@ func instructionsForLoad(p *obj.Prog, as obj.As, rs int16) []*instruction {
|
||||||
return []*instruction{insLUI, insADD, ins}
|
return []*instruction{insLUI, insADD, ins}
|
||||||
}
|
}
|
||||||
|
|
||||||
func instructionsForStore(p *obj.Prog) []*instruction {
|
// instructionsForStore returns the machine instructions for a store. The store
|
||||||
|
// instruction is specified by as and the target/source register is specified
|
||||||
|
// by rd, instead of the obj.Prog.
|
||||||
|
func instructionsForStore(p *obj.Prog, as obj.As, rd int16) []*instruction {
|
||||||
if p.To.Type != obj.TYPE_MEM {
|
if p.To.Type != obj.TYPE_MEM {
|
||||||
p.Ctxt.Diag("%v requires memory for destination", p)
|
p.Ctxt.Diag("%v requires memory for destination", p)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch p.As {
|
switch as {
|
||||||
case ASW, ASH, ASB, ASD, AFSW, AFSD:
|
case ASW, ASH, ASB, ASD, AFSW, AFSD:
|
||||||
default:
|
default:
|
||||||
p.Ctxt.Diag("%v: unknown store instruction %v", p, p.As)
|
p.Ctxt.Diag("%v: unknown store instruction %v", p, as)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// <store> $imm, REG, TO (store $imm+(TO), REG)
|
// <store> $imm, REG, TO (store $imm+(TO), REG)
|
||||||
ins := instructionForProg(p)
|
ins := instructionForProg(p)
|
||||||
ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
|
ins.as, ins.rd, ins.rs1, ins.rs2 = as, uint32(rd), uint32(p.From.Reg), obj.REG_NONE
|
||||||
ins.imm = p.To.Offset
|
ins.imm = p.To.Offset
|
||||||
|
|
||||||
low, high, err := Split32BitImmediate(ins.imm)
|
low, high, err := Split32BitImmediate(ins.imm)
|
||||||
|
@ -1888,6 +1874,26 @@ func instructionsForMOV(p *obj.Prog) []*instruction {
|
||||||
inss = []*instruction{insAUIPC, ins}
|
inss = []*instruction{insAUIPC, ins}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
|
||||||
|
// Register to memory stores.
|
||||||
|
switch p.As {
|
||||||
|
case AMOVBU, AMOVHU, AMOVWU:
|
||||||
|
// rewriteMOV should have already added an error for these.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch p.To.Name {
|
||||||
|
case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
|
||||||
|
// MOV Rs, c(Rd) -> S $c, Rs, Rd
|
||||||
|
inss = instructionsForStore(p, movToStore(p.As), addrToReg(p.To))
|
||||||
|
|
||||||
|
case obj.NAME_EXTERN, obj.NAME_STATIC:
|
||||||
|
// AUIPC $off_hi, Rtmp
|
||||||
|
// S $off_lo, Rtmp, Rd
|
||||||
|
insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
|
||||||
|
ins.as, ins.rd, ins.rs1, ins.rs2, ins.imm = movToStore(p.As), REG_TMP, uint32(p.From.Reg), obj.REG_NONE, 0
|
||||||
|
inss = []*instruction{insAUIPC, ins}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// If we get here with a MOV pseudo-instruction it is going to
|
// If we get here with a MOV pseudo-instruction it is going to
|
||||||
// remain unhandled. For now we trust rewriteMOV to catch these.
|
// remain unhandled. For now we trust rewriteMOV to catch these.
|
||||||
|
@ -1947,7 +1953,7 @@ func instructionsForProg(p *obj.Prog) []*instruction {
|
||||||
return instructionsForLoad(p, ins.as, p.From.Reg)
|
return instructionsForLoad(p, ins.as, p.From.Reg)
|
||||||
|
|
||||||
case ASW, ASH, ASB, ASD, AFSW, AFSD:
|
case ASW, ASH, ASB, ASD, AFSW, AFSD:
|
||||||
return instructionsForStore(p)
|
return instructionsForStore(p, ins.as, p.To.Reg)
|
||||||
|
|
||||||
case ALRW, ALRD:
|
case ALRW, ALRD:
|
||||||
// Set aq to use acquire access ordering, which matches Go's memory requirements.
|
// Set aq to use acquire access ordering, which matches Go's memory requirements.
|
||||||
|
|
Loading…
Reference in a new issue