]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/asm,cmd/internal/obj/riscv: add LR/SC instructions
authorJoel Sing <joel@sing.id.au>
Thu, 20 Feb 2020 15:30:09 +0000 (02:30 +1100)
committerJoel Sing <joel@sing.id.au>
Sun, 15 Mar 2020 07:51:41 +0000 (07:51 +0000)
Add support for Load-Reserved (LR) and Store-Conditional (SC) instructions.

Use instructions in place of currently used defines.

Updates #36765

Change-Id: I77e660639802293ece40cfde4865ac237e3308d6
Reviewed-on: https://go-review.googlesource.com/c/go/+/220540
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/asm/internal/arch/riscv64.go [new file with mode: 0644]
src/cmd/asm/internal/asm/asm.go
src/cmd/asm/internal/asm/testdata/riscvenc.s
src/cmd/internal/obj/riscv/obj.go
src/runtime/internal/atomic/atomic_riscv64.s

diff --git a/src/cmd/asm/internal/arch/riscv64.go b/src/cmd/asm/internal/arch/riscv64.go
new file mode 100644 (file)
index 0000000..1b0ccce
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file encapsulates some of the odd characteristics of the RISCV64
+// instruction set, to minimize its interaction with the core of the
+// assembler.
+
+package arch
+
+import (
+       "cmd/internal/obj"
+       "cmd/internal/obj/riscv"
+)
+
+// IsRISCV64AMO reports whether the op (as defined by a riscv.A*
+// constant) is one of the AMO instructions that requires special
+// handling.
+func IsRISCV64AMO(op obj.As) bool {
+       switch op {
+       case riscv.ASCW, riscv.ASCD:
+               return true
+       }
+       return false
+}
index 26b355dee1ee4e076c26b05858616d95fa64463c..42e217dc233fc7b6779c0c5f3f7c8929a1b0687e 100644 (file)
@@ -590,7 +590,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                prog.To = a[1]
        case 3:
                switch p.arch.Family {
-               case sys.MIPS, sys.MIPS64, sys.RISCV64:
+               case sys.MIPS, sys.MIPS64:
                        prog.From = a[0]
                        prog.Reg = p.getRegister(prog, op, &a[1])
                        prog.To = a[2]
@@ -675,6 +675,21 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                                p.errorf("invalid addressing modes for %s instruction", op)
                                return
                        }
+               case sys.RISCV64:
+                       // RISCV64 instructions with one input and two outputs.
+                       if arch.IsRISCV64AMO(op) {
+                               prog.From = a[0]
+                               prog.To = a[1]
+                               if a[2].Type != obj.TYPE_REG {
+                                       p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
+                                       return
+                               }
+                               prog.RegTo2 = a[2].Reg
+                               break
+                       }
+                       prog.From = a[0]
+                       prog.Reg = p.getRegister(prog, op, &a[1])
+                       prog.To = a[2]
                case sys.S390X:
                        prog.From = a[0]
                        if a[1].Type == obj.TYPE_REG {
index 18f94adb6917dab183e23a17c80c252b310fc62e..1327505e2a45225b64f7e53c017874c790c0c843 100644 (file)
@@ -157,6 +157,12 @@ start:
        REMW    X5, X6, X7                              // bb635302
        REMUW   X5, X6, X7                              // bb735302
 
+       // 8.2: Load-Reserved/Store-Conditional
+       LRW     (X5), X6                                // 2fa30214
+       LRD     (X5), X6                                // 2fb30214
+       SCW     X5, (X6), X7                            // af23531c
+       SCD     X5, (X6), X7                            // af33531c
+
        // 10.1: Base Counters and Timers
        RDCYCLE         X5                              // f32200c0
        RDTIME          X5                              // f32210c0
@@ -276,7 +282,7 @@ start:
        // These jumps can get printed as jumps to 2 because they go to the
        // second instruction in the function (the first instruction is an
        // invisible stack pointer adjustment).
-       JMP     start           // JMP  2               // 6ff09fcc
+       JMP     start           // JMP  2               // 6ff09fcb
        JMP     (X5)                                    // 67800200
        JMP     4(X5)                                   // 67804200
 
index 5497a1dbc5284585122f64fc7fe47fe0ecce2aa3..d55c05a38c154997f51733b95826a7e8cc23377d 100644 (file)
@@ -1318,7 +1318,7 @@ func validateRaw(ctxt *obj.Link, ins *instruction) {
 }
 
 // encodeR encodes an R-type RISC-V instruction.
-func encodeR(as obj.As, rs1, rs2, rd, funct3 uint32) uint32 {
+func encodeR(as obj.As, rs1, rs2, rd, funct3, funct7 uint32) uint32 {
        enc := encode(as)
        if enc == nil {
                panic("encodeR: could not encode instruction")
@@ -1326,31 +1326,31 @@ func encodeR(as obj.As, rs1, rs2, rd, funct3 uint32) uint32 {
        if enc.rs2 != 0 && rs2 != 0 {
                panic("encodeR: instruction uses rs2, but rs2 was nonzero")
        }
-       return enc.funct7<<25 | enc.rs2<<20 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
+       return funct7<<25 | enc.funct7<<25 | enc.rs2<<20 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
 }
 
 func encodeRIII(ins *instruction) uint32 {
-       return encodeR(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd), ins.funct3)
+       return encodeR(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
 }
 
 func encodeRFFF(ins *instruction) uint32 {
-       return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rd), ins.funct3)
+       return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rd), ins.funct3, ins.funct7)
 }
 
 func encodeRFFI(ins *instruction) uint32 {
-       return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regI(ins.rd), ins.funct3)
+       return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
 }
 
 func encodeRFI(ins *instruction) uint32 {
-       return encodeR(ins.as, regF(ins.rs2), 0, regI(ins.rd), ins.funct3)
+       return encodeR(ins.as, regF(ins.rs2), 0, regI(ins.rd), ins.funct3, ins.funct7)
 }
 
 func encodeRIF(ins *instruction) uint32 {
-       return encodeR(ins.as, regI(ins.rs2), 0, regF(ins.rd), ins.funct3)
+       return encodeR(ins.as, regI(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
 }
 
 func encodeRFF(ins *instruction) uint32 {
-       return encodeR(ins.as, regF(ins.rs2), 0, regF(ins.rd), ins.funct3)
+       return encodeR(ins.as, regF(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7)
 }
 
 // encodeI encodes an I-type RISC-V instruction.
@@ -1585,6 +1585,12 @@ var encodings = [ALAST & obj.AMask]encoding{
        AREMW & obj.AMask:   rIIIEncoding,
        AREMUW & obj.AMask:  rIIIEncoding,
 
+       // 8.2: Load-Reserved/Store-Conditional
+       ALRW & obj.AMask: rIIIEncoding,
+       ALRD & obj.AMask: rIIIEncoding,
+       ASCW & obj.AMask: rIIIEncoding,
+       ASCD & obj.AMask: rIIIEncoding,
+
        // 10.1: Base Counters and Timers
        ARDCYCLE & obj.AMask:   iIEncoding,
        ARDTIME & obj.AMask:    iIEncoding,
@@ -1699,6 +1705,7 @@ type instruction struct {
        rs2    uint32 // Source register 2
        imm    int64  // Immediate
        funct3 uint32 // Function 3
+       funct7 uint32 // Function 7
 }
 
 func (ins *instruction) encode() (uint32, error) {
@@ -1764,6 +1771,16 @@ func instructionsForProg(p *obj.Prog) []*instruction {
                ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
                ins.imm = p.To.Offset
 
+       case ALRW, ALRD:
+               // Set aq to use acquire access ordering, which matches Go's memory requirements.
+               ins.funct7 = 2
+               ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO
+
+       case ASCW, ASCD:
+               // Set aq to use acquire access ordering, which matches Go's memory requirements.
+               ins.funct7 = 2
+               ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
+
        case AECALL, AEBREAK, ARDCYCLE, ARDTIME, ARDINSTRET:
                insEnc := encode(p.As)
                if p.To.Type == obj.TYPE_NONE {
index 80c84cf7d3bfab61f7415586228759c6adfb032f..e4b7902d521e15eef1bb8cab93645c985ff5f942 100644 (file)
@@ -52,9 +52,9 @@ TEXT ·Cas(SB), NOSPLIT, $0-17
        MOVW    old+8(FP), A1
        MOVW    new+12(FP), A2
 cas_again:
-       AMOWSC(LR_,13,10,0)     // lr.w.aq a3,(a0)
+       LRW     (A0), A3
        BNE     A3, A1, cas_fail
-       AMOWSC(SC_,14,10,12)    // sc.w.aq a4,a2,(a0)
+       SCW     A2, (A0), A4
        BNE     A4, ZERO, cas_again
        MOV     $1, A0
        MOVB    A0, ret+16(FP)
@@ -70,9 +70,9 @@ TEXT ·Cas64(SB), NOSPLIT, $0-25
        MOV     old+8(FP), A1
        MOV     new+16(FP), A2
 cas_again:
-       AMODSC(LR_,13,10,0)     // lr.d.aq a3,(a0)
+       LRD     (A0), A3
        BNE     A3, A1, cas_fail
-       AMODSC(SC_,14,10,12)    // sc.d.aq a4,a2,(a0)
+       SCD     A2, (A0), A4
        BNE     A4, ZERO, cas_again
        MOV     $1, A0
        MOVB    A0, ret+24(FP)
@@ -84,7 +84,7 @@ cas_fail:
 // func Load(ptr *uint32) uint32
 TEXT ·Load(SB),NOSPLIT|NOFRAME,$0-12
        MOV     ptr+0(FP), A0
-       AMOWSC(LR_,10,10,0)
+       LRW     (A0), A0
        MOVW    A0, ret+8(FP)
        RET
 
@@ -100,7 +100,7 @@ TEXT ·Load8(SB),NOSPLIT|NOFRAME,$0-9
 // func Load64(ptr *uint64) uint64
 TEXT ·Load64(SB),NOSPLIT|NOFRAME,$0-16
        MOV     ptr+0(FP), A0
-       AMODSC(LR_,10,10,0)
+       LRD     (A0), A0
        MOV     A0, ret+8(FP)
        RET