aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal/obj/riscv/obj.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal/obj/riscv/obj.go')
-rw-r--r--src/cmd/internal/obj/riscv/obj.go168
1 files changed, 89 insertions, 79 deletions
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 77d383b290..9257a6453a 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -33,7 +33,7 @@ func buildop(ctxt *obj.Link) {}
// lr is the link register to use for the JALR.
// p must be a CALL, JMP or RET.
func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *obj.Prog {
- if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET {
+ if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET && p.As != obj.ADUFFZERO && p.As != obj.ADUFFCOPY {
ctxt.Diag("unexpected Prog in jalrToSym: %v", p)
return p
}
@@ -48,7 +48,7 @@ func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *ob
p.As = AAUIPC
p.Mark |= NEED_PCREL_ITYPE_RELOC
- p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: to.Offset, Sym: to.Sym}}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: to.Offset, Sym: 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}
@@ -58,30 +58,14 @@ func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *ob
p.As = AJALR
p.From.Type = obj.TYPE_REG
p.From.Reg = lr
- p.From.Sym = to.Sym
p.Reg = 0
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_TMP
- lowerJALR(p)
+ p.To.Sym = to.Sym
return p
}
-// lowerJALR normalizes a JALR instruction.
-func lowerJALR(p *obj.Prog) {
- if p.As != AJALR {
- panic("lowerJALR: not a JALR")
- }
-
- // JALR gets parsed like JAL - the linkage pointer goes in From,
- // and the target is in To. However, we need to assemble it as an
- // I-type instruction, so place the linkage pointer in To, the
- // target register in Reg, and the offset in From.
- p.Reg = p.To.Reg
- p.From, p.To = p.To, p.From
- p.From.Type, p.From.Reg = obj.TYPE_CONST, obj.REG_NONE
-}
-
// progedit is called individually for each *obj.Prog. It normalizes instruction
// formats and eliminates as many pseudo-instructions as possible.
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
@@ -125,7 +109,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
switch p.As {
case obj.AJMP:
// Turn JMP into JAL ZERO or JALR ZERO.
- // p.From is actually an _output_ for this instruction.
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_ZERO
@@ -136,7 +119,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
switch p.To.Name {
case obj.NAME_NONE:
p.As = AJALR
- lowerJALR(p)
case obj.NAME_EXTERN:
// Handled in preprocess.
default:
@@ -154,14 +136,10 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.As = AJALR
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_LR
- lowerJALR(p)
default:
ctxt.Diag("unknown destination type %+v in CALL: %v", p.To.Type, p)
}
- case AJALR:
- lowerJALR(p)
-
case obj.AUNDEF:
p.As = AEBREAK
@@ -256,7 +234,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
p.As = AAUIPC
p.Mark |= NEED_PCREL_ITYPE_RELOC
- p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym}}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym})
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
p.Reg = 0
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: to.Reg}
@@ -274,19 +252,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
switch p.To.Type {
case obj.TYPE_REG:
switch p.As {
- case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
- p.As = AADDI
- p.Reg = p.From.Reg
- p.From = obj.Addr{Type: obj.TYPE_CONST}
-
- case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb
- p.As = AFSGNJS
- p.Reg = p.From.Reg
-
- case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb
- p.As = AFSGNJD
- p.Reg = p.From.Reg
-
+ case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
default:
ctxt.Diag("unsupported register-register move at %v", p)
}
@@ -309,7 +275,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
p.As = AAUIPC
p.Mark |= NEED_PCREL_STYPE_RELOC
- p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym}}
+ 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}
@@ -374,7 +340,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
p.As = AAUIPC
p.Mark |= NEED_PCREL_ITYPE_RELOC
- p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym}}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym})
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
p.Reg = 0
p.To = to
@@ -449,12 +415,12 @@ func InvertBranch(as obj.As) obj.As {
// instruction. Must be called after progedit.
func containsCall(sym *obj.LSym) bool {
// CALLs are CALL or JAL(R) with link register LR.
- for p := sym.Func.Text; p != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil; p = p.Link {
switch p.As {
- case obj.ACALL:
+ case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
return true
case AJAL, AJALR:
- if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_LR {
+ if p.From.Type == obj.TYPE_REG && p.From.Reg == REG_LR {
return true
}
}
@@ -521,12 +487,12 @@ func stackOffset(a *obj.Addr, stacksize int64) {
// concrete, real RISC-V instructions or directive pseudo-ops like TEXT,
// PCDATA, and FUNCDATA.
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
// Generate the prologue.
- text := cursym.Func.Text
+ text := cursym.Func().Text
if text.As != obj.ATEXT {
ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
return
@@ -560,12 +526,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
stacksize += ctxt.FixedFrameSize()
}
- cursym.Func.Args = text.To.Val.(int32)
- cursym.Func.Locals = int32(stacksize)
+ cursym.Func().Args = text.To.Val.(int32)
+ cursym.Func().Locals = int32(stacksize)
prologue := text
- if !cursym.Func.Text.From.Sym.NoSplit() {
+ if !cursym.Func().Text.From.Sym.NoSplit() {
prologue = stacksplit(ctxt, prologue, cursym, newprog, stacksize) // emit split check
}
@@ -589,7 +555,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
prologue = ctxt.EndUnsafePoint(prologue, newprog, -1)
}
- if cursym.Func.Text.From.Sym.Wrapper() {
+ if cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), X11
@@ -669,13 +635,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Update stack-based offsets.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
stackOffset(&p.From, stacksize)
stackOffset(&p.To, stacksize)
}
// Additional instruction rewriting.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.AGETCALLERPC:
if cursym.Leaf() {
@@ -690,7 +656,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Reg = REG_SP
}
- case obj.ACALL:
+ case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
switch p.To.Type {
case obj.TYPE_MEM:
jalrToSym(ctxt, p, newprog, REG_LR)
@@ -731,11 +697,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p = jalrToSym(ctxt, p, newprog, REG_ZERO)
} else {
p.As = AJALR
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.Reg = REG_LR
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_ZERO
+ p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
+ p.Reg = 0
+ p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
}
// "Add back" the stack removed in the previous instruction.
@@ -757,7 +721,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// Rewrite MOV pseudo-instructions. This cannot be done in
// progedit, as SP offsets need to be applied before we split
// up some of the Addrs.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
rewriteMOV(ctxt, newprog, p)
@@ -765,7 +729,7 @@ 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 {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
// <opi> $imm, REG, TO
case AADDI, AANDI, AORI, AXORI:
@@ -882,9 +846,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// a fixed point will be reached). No attempt to handle functions > 2GiB.
for {
rescan := false
- setPCs(cursym.Func.Text, 0)
+ setPCs(cursym.Func().Text, 0)
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
if p.To.Type != obj.TYPE_BRANCH {
@@ -917,9 +881,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// it is reserved by SSA.
jmp := obj.Appendp(p, newprog)
jmp.As = AJALR
- jmp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
- jmp.To = p.From
- jmp.Reg = REG_TMP
+ jmp.From = p.From
+ jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
// p.From is not generally valid, however will be
// fixed up in the next loop.
@@ -942,7 +905,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// Now that there are no long branches, resolve branch and jump targets.
// At this point, instruction rewriting which changes the number of
// instructions will break everything--don't do it!
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, AJAL:
switch p.To.Type {
@@ -965,7 +928,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Validate all instructions - this provides nice error messages.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
for _, ins := range instructionsForProg(p) {
ins.validate(ctxt)
}
@@ -1093,7 +1056,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgA
p.To.Type = obj.TYPE_BRANCH
if cursym.CFunc() {
p.To.Sym = ctxt.Lookup("runtime.morestackc")
- } else if !cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !cursym.Func().Text.From.Sym.NeedCtxt() {
p.To.Sym = ctxt.Lookup("runtime.morestack_noctxt")
} else {
p.To.Sym = ctxt.Lookup("runtime.morestack")
@@ -1108,7 +1071,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgA
p.As = AJAL
p.To = obj.Addr{Type: obj.TYPE_BRANCH}
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
- p.To.SetTarget(cursym.Func.Text.Link)
+ p.To.SetTarget(cursym.Func().Text.Link)
// placeholder for to_done's jump target
p = obj.Appendp(p, newprog)
@@ -1733,6 +1696,8 @@ var encodings = [ALAST & obj.AMask]encoding{
obj.APCDATA: pseudoOpEncoding,
obj.ATEXT: pseudoOpEncoding,
obj.ANOP: pseudoOpEncoding,
+ obj.ADUFFZERO: pseudoOpEncoding,
+ obj.ADUFFCOPY: pseudoOpEncoding,
}
// encodingForAs returns the encoding for an obj.As.
@@ -1801,8 +1766,8 @@ func instructionsForProg(p *obj.Prog) []*instruction {
inss := []*instruction{ins}
switch ins.as {
- case AJAL:
- ins.rd, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
+ case AJAL, AJALR:
+ ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE
ins.imm = p.To.Offset
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
@@ -1812,15 +1777,15 @@ func instructionsForProg(p *obj.Prog) []*instruction {
case ABGEZ:
ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
case ABGT:
- ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.Reg), uint32(p.From.Reg)
+ ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
case ABGTU:
- ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.Reg)
+ ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
case ABGTZ:
ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
case ABLE:
- ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.Reg), uint32(p.From.Reg)
+ ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
case ABLEU:
- ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg)
+ ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
case ABLEZ:
ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
case ABLTZ:
@@ -1830,6 +1795,44 @@ func instructionsForProg(p *obj.Prog) []*instruction {
}
ins.imm = p.To.Offset
+ case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
+ // Handle register to register moves.
+ if p.From.Type != obj.TYPE_REG || p.To.Type != obj.TYPE_REG {
+ break
+ }
+ switch p.As {
+ case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, uint32(p.From.Reg), obj.REG_NONE, 0
+ case AMOVW: // MOVW Ra, Rb -> ADDIW $0, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AADDIW, uint32(p.From.Reg), obj.REG_NONE, 0
+ case AMOVBU: // MOVBU Ra, Rb -> ANDI $255, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AANDI, uint32(p.From.Reg), obj.REG_NONE, 255
+ case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb
+ ins.as, ins.rs1 = AFSGNJS, uint32(p.From.Reg)
+ case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb
+ ins.as, ins.rs1 = AFSGNJD, uint32(p.From.Reg)
+ case AMOVB, AMOVH:
+ // Use SLLI/SRAI to extend.
+ ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
+ if p.As == AMOVB {
+ ins.imm = 56
+ } else if p.As == AMOVH {
+ ins.imm = 48
+ }
+ ins2 := &instruction{as: ASRAI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
+ inss = append(inss, ins2)
+ case AMOVHU, AMOVWU:
+ // Use SLLI/SRLI to extend.
+ ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
+ if p.As == AMOVHU {
+ ins.imm = 48
+ } else if p.As == AMOVWU {
+ ins.imm = 32
+ }
+ ins2 := &instruction{as: ASRLI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
+ inss = append(inss, ins2)
+ }
+
case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
if p.From.Type != obj.TYPE_MEM {
p.Ctxt.Diag("%v requires memory for source", p)
@@ -1884,13 +1887,13 @@ func instructionsForProg(p *obj.Prog) []*instruction {
} else {
ins.as = AFEQD
}
- ins = &instruction{
+ ins2 := &instruction{
as: AXORI, // [bit] xor 1 = not [bit]
rd: ins.rd,
rs1: ins.rd,
imm: 1,
}
- inss = append(inss, ins)
+ inss = append(inss, ins2)
case AFSQRTS, AFSQRTD:
// These instructions expect a zero (i.e. float register 0)
@@ -1951,7 +1954,7 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
var symcode []uint32
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case AJALR:
if p.To.Sym != nil {
@@ -1983,6 +1986,13 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Diag("AUIPC needing PC-relative reloc missing symbol")
break
}
+ if addr.Sym.Type == objabi.STLSBSS {
+ if rt == objabi.R_RISCV_PCREL_ITYPE {
+ rt = objabi.R_RISCV_TLS_IE_ITYPE
+ } else if rt == objabi.R_RISCV_PCREL_STYPE {
+ rt = objabi.R_RISCV_TLS_IE_STYPE
+ }
+ }
rel := obj.Addrel(cursym)
rel.Off = int32(p.Pc)
@@ -2006,7 +2016,7 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Arch.ByteOrder.PutUint32(p, symcode[i])
}
- obj.MarkUnsafePoints(ctxt, cursym.Func.Text, newprog, isUnsafePoint, nil)
+ obj.MarkUnsafePoints(ctxt, cursym.Func().Text, newprog, isUnsafePoint, nil)
}
func isUnsafePoint(p *obj.Prog) bool {