Skip to content

Commit

Permalink
all: handle FP offsets
Browse files Browse the repository at this point in the history
Remove both FP and SB as concrete registers; they are purely
psuedo-registers.

FP offsets are handled by adding the current SP adjustment to the offset
of NAME_PARAM Addrs.

I am unsure of my arg and frame sizes in riscv_hello.s. It is not clear
to me if callers are supposed to leave room for return values in their
frame size or if callees are supposed to add them to their argument
size. The assembly in the runtime seems to be inconsistent.

Fixes golang#8

Change-Id: Ib79efb4fea8629f22461b4ebfc987bc8785a3ce3
  • Loading branch information
prattmic committed Aug 16, 2016
1 parent 06c03cc commit e4d2172
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 34 deletions.
5 changes: 5 additions & 0 deletions src/cmd/asm/internal/arch/arch.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,11 @@ var riscvJumps = map[string]bool{
}

func archRiscv() *Arch {
// Pseudo-registers.
riscv.Registers["SB"] = RSB
riscv.Registers["FP"] = RFP
riscv.Registers["PC"] = RPC

return &Arch{
LinkArch: &riscv.LinkRISCV,
Instructions: riscv.Instructions,
Expand Down
9 changes: 3 additions & 6 deletions src/cmd/asm/internal/asm/testdata/riscv_hello.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@
#define SYS_WRITE 64

// func helloChar() uint64
TEXT helloChar(SB),0,$8
TEXT helloChar(SB),0,$0
MOV $72, T0
// FIXME(mpratt): this should use FP.
MOV T0, 0(SP)
MOV T0, ret+0(FP)
RET

// _rt0_riscv_linux is the entry point.
TEXT main·main(SB),0,$8
TEXT main·main(SB),0,$8-0
// Write "H" to stdout...not quite to hello world, yet
CALL helloChar(SB)
MOV -8(SP), T0
MOVW T0, 0(SP)
MOV SP, A1 // ptr to data
MOV $1, A0 // fd 1 for stdout
MOV $1, A2 // len("H") == 1
Expand Down
51 changes: 31 additions & 20 deletions src/cmd/internal/obj/riscv/asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,11 @@ import (
"fmt"
)

// resolvepseudoreg concretizes pseudo-registers in an Addr.
func resolvepseudoreg(a *obj.Addr) {
if a.Type == obj.TYPE_MEM {
switch a.Name {
case obj.NAME_PARAM:
a.Reg = REG_FP
}
// stackOffset updates Addr offsets based on the current stack size.
func stackOffset(a *obj.Addr, stacksize int64) {
switch a.Name {
case obj.NAME_AUTO, obj.NAME_PARAM:
a.Offset += stacksize
}
}

Expand Down Expand Up @@ -108,11 +106,9 @@ func movtos(mnemonic obj.As) obj.As {
}
}

// addrtoreg extracts the register from an addr, handling SB and SP.
// addrtoreg extracts the register from an Addr, handling special Addr.Names.
func addrtoreg(a obj.Addr) int16 {
switch a.Name {
case obj.NAME_EXTERN:
return REG_SB
case obj.NAME_PARAM, obj.NAME_AUTO:
return REG_SP
}
Expand Down Expand Up @@ -164,11 +160,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
}
}

// Concretize pseudo-registers.
resolvepseudoreg(&p.From)
resolvepseudoreg(p.From3)
resolvepseudoreg(&p.To)

// Do additional single-instruction rewriting.
switch p.As {
// Turn JMP into JAL ZERO or JALR ZERO.
Expand Down Expand Up @@ -272,10 +263,10 @@ func InvertBranch(i obj.As) obj.As {
}
}

// preprocess generates prologue and epilogue code and computes PC-relative
// branch and jump offsets.
// preprocess generates prologue and epilogue code, computes PC-relative branch
// and jump offsets, and resolves psuedo-registers.
//
// preprocess is called once for each linker symbol.
// preprocess is called once per linker symbol.
//
// When preprocess finishes, all instructions in the symbol are either
// concrete, real RISC-V instructions or directive pseudo-ops like TEXT,
Expand All @@ -287,7 +278,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
return
}

stacksize := text.To.Offset

cursym.Args = text.To.Val.(int32)
cursym.Locals = int32(stacksize)

// Insert stack adjustment if necessary.
if stacksize != 0 {
spadj := obj.Appendp(ctxt, text)
Expand All @@ -300,11 +296,25 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
spadj.Spadj = int32(-stacksize)
}

// Update stack-based offsets.
for p := cursym.Text; p != nil; p = p.Link {
stackOffset(&p.From, stacksize)
if p.From3 != nil {
stackOffset(p.From3, stacksize)
}
stackOffset(&p.To, stacksize)

// TODO: update stacksize when instructions that modify SP are
// found, or disallow it entirely.
}

// Additional instruction rewriting.
for p := cursym.Text; p != nil; p = p.Link {
switch p.As {

// Rewrite MOV.
// Rewrite MOV. This couldn't be done in progedit, as SP
// offsets needed to be applied before we split up some of the
// Addrs.
case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU:
switch p.From.Type {
case obj.TYPE_MEM: // MOV c(Rs), Rd -> L $c, Rs, Rd
Expand Down Expand Up @@ -404,7 +414,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.From.Type = obj.TYPE_CONST
switch p.From.Name {
case obj.NAME_EXTERN:
p.From3.Reg = REG_SB
// Doesn't matter, we'll add a
// relocation later.
case obj.NAME_PARAM, obj.NAME_AUTO:
p.From3.Reg = REG_SP
default:
Expand Down
2 changes: 0 additions & 2 deletions src/cmd/internal/obj/riscv/cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ const (
REG_T1 = REG_X6
REG_T2 = REG_X7
REG_S0 = REG_X8
REG_FP = REG_X8 // S0 and FP are the same.
REG_S1 = REG_X9
REG_A0 = REG_X10
REG_A1 = REG_X11
Expand All @@ -142,7 +141,6 @@ const (
REG_T6 = REG_X31

// Go runtime register names.
REG_SB = REG_X3 // Static base.
REG_G = REG_X4 // G pointer.
REG_RT1 = REG_S2 // Reserved for runtime (duffzero and duffcopy).
REG_RT2 = REG_S3 // Reserved for runtime (duffcopy).
Expand Down
9 changes: 3 additions & 6 deletions src/cmd/internal/obj/riscv/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@ var (
REG_ZERO: "ZERO",
REG_RA: "RA",
REG_SP: "SP",
// REG_GP is REG_SB
REG_GP: "GP",
// REG_TP is REG_G
REG_T0: "T0",
REG_T1: "T1",
REG_T2: "T2",
REG_S0: "S0",
// REG_FP is REG_S0.
REG_S1: "S1",
REG_A0: "A0",
REG_A1: "A1",
Expand All @@ -80,7 +79,6 @@ var (
REG_T6: "T6",

// Go runtime register names.
REG_SB: "SB",
REG_RT1: "RT1",
REG_RT2: "RT2",
REG_CTXT: "CTXT",
Expand Down Expand Up @@ -122,6 +120,8 @@ var (
}
)

// initRegisters initializes the Registers map. arch.archRiscv will also add
// some psuedoregisters.
func initRegisters() {
// Standard register names.
for i := REG_X0; i <= REG_X31; i++ {
Expand All @@ -134,7 +134,6 @@ func initRegisters() {
}

// General registers with ABI names.

Registers["ZERO"] = REG_ZERO
Registers["RA"] = REG_RA
Registers["SP"] = REG_SP
Expand All @@ -144,7 +143,6 @@ func initRegisters() {
Registers["T1"] = REG_T1
Registers["T2"] = REG_T2
Registers["S0"] = REG_S0
Registers["FP"] = REG_FP
Registers["S1"] = REG_S1
Registers["A0"] = REG_A0
Registers["A1"] = REG_A1
Expand All @@ -170,7 +168,6 @@ func initRegisters() {
Registers["T6"] = REG_T6

// Golang runtime register names.
Registers["SB"] = REG_SB
Registers["RT1"] = REG_RT1
Registers["RT2"] = REG_RT2
Registers["CTXT"] = REG_CTXT
Expand Down

0 comments on commit e4d2172

Please sign in to comment.