]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/asm,cmd/internal/obj/riscv: provide branch pseudo-instructions
authorJoel Sing <joel@sing.id.au>
Mon, 30 Mar 2020 14:57:52 +0000 (01:57 +1100)
committerJoel Sing <joel@sing.id.au>
Tue, 31 Mar 2020 13:13:58 +0000 (13:13 +0000)
Implement various branch pseudo-instructions for riscv64. These make it easier
to read/write assembly and will also make it easier for the compiler to generate
optimised code.

Change-Id: Ic31a7748c0e1495522ebecf34b440842b8d12c04
Reviewed-on: https://go-review.googlesource.com/c/go/+/226397
Run-TryBot: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/asm/internal/arch/arch.go
src/cmd/asm/internal/asm/testdata/riscvenc.s
src/cmd/internal/obj/riscv/anames.go
src/cmd/internal/obj/riscv/asm_test.go
src/cmd/internal/obj/riscv/cpu.go
src/cmd/internal/obj/riscv/obj.go
src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go [new file with mode: 0644]
src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s [new file with mode: 0644]

index d9ba6670e8b9cb91d77b463d3b0df6a34a9f2ce0..2e5d0ff9911d3000e7162516c2fd02568dd487a9 100644 (file)
@@ -88,7 +88,8 @@ func jumpX86(word string) bool {
 
 func jumpRISCV(word string) bool {
        switch word {
-       case "BEQ", "BNE", "BLT", "BGE", "BLTU", "BGEU", "CALL", "JAL", "JALR", "JMP":
+       case "BEQ", "BEQZ", "BGE", "BGEU", "BGEZ", "BGT", "BGTU", "BGTZ", "BLE", "BLEU", "BLEZ",
+               "BLT", "BLTU", "BLTZ", "BNE", "BNEZ", "CALL", "JAL", "JALR", "JMP":
                return true
        }
        return false
index 74bc43d727a112755132c1679d50f0aa8e68c8be..8d301f2dd5e36851dcd851d5aea22484d484409e 100644 (file)
@@ -330,6 +330,19 @@ start:
        CALL    asmtest(SB)                             // 970f0000
        JMP     asmtest(SB)                             // 970f0000
 
+       // Branch pseudo-instructions
+       BEQZ    X5, start       // BEQZ X5, 2           // e38a02c2
+       BGEZ    X5, start       // BGEZ X5, 2           // e3d802c2
+       BGT     X5, X6, start   // BGT  X5, X6, 2       // e3c662c2
+       BGTU    X5, X6, start   // BGTU X5, X6, 2       // e3e462c2
+       BGTZ    X5, start       // BGTZ X5, 2           // e34250c2
+       BLE     X5, X6, start   // BLE  X5, X6, 2       // e3d062c2
+       BLEU    X5, X6, start   // BLEU X5, X6, 2       // e3fe62c0
+       BLEZ    X5, start       // BLEZ X5, 2           // e35c50c0
+       BLTZ    X5, start       // BLTZ X5, 2           // e3ca02c0
+       BNEZ    X5, start       // BNEZ X5, 2           // e39802c0
+
+       // Set pseudo-instructions
        SEQZ    X15, X15                                // 93b71700
        SNEZ    X15, X15                                // b337f000
 
index fa236d81e5dcc6e5956296e4eb676dbfd054cc72..6581bb34022ad1ebf3a27f9f8e04023f495cca36 100644 (file)
@@ -226,6 +226,16 @@ var Anames = []string{
        "HFENCEGVMA",
        "HFENCEVVMA",
        "WORD",
+       "BEQZ",
+       "BGEZ",
+       "BGT",
+       "BGTU",
+       "BGTZ",
+       "BLE",
+       "BLEU",
+       "BLEZ",
+       "BLTZ",
+       "BNEZ",
        "FNEGD",
        "FNEGS",
        "FNED",
index 849a87b7063ef861ea613c4c7b0daf42137c3220..f8f7b4f2ced0756c5c9ea868cf074a0e55062060 100644 (file)
@@ -12,6 +12,7 @@ import (
        "os"
        "os/exec"
        "path/filepath"
+       "runtime"
        "testing"
 )
 
@@ -131,3 +132,20 @@ TEXT _stub(SB),$0-0
                t.Errorf("%v\n%s", err, out)
        }
 }
+
+func TestBranch(t *testing.T) {
+       if testing.Short() {
+               t.Skip("Skipping in short mode")
+       }
+       if runtime.GOARCH != "riscv64" {
+               t.Skip("Requires riscv64 to run")
+       }
+
+       testenv.MustHaveGoBuild(t)
+
+       cmd := exec.Command(testenv.GoToolPath(t), "test")
+       cmd.Dir = "testdata/testbranch"
+       if out, err := testenv.CleanCmdEnv(cmd).CombinedOutput(); err != nil {
+               t.Errorf("Branch test failed: %v\n%s", err, out)
+       }
+}
index 76457dd8d27c6123ce3f79d36f4eef42da5d83e9..482f9e0b6da1b8773701d2390c0b9be9c545d9de 100644 (file)
@@ -576,6 +576,16 @@ const (
 
        // Pseudo-instructions.  These get translated by the assembler into other
        // instructions, based on their operands.
+       ABEQZ
+       ABGEZ
+       ABGT
+       ABGTU
+       ABGTZ
+       ABLE
+       ABLEU
+       ABLEZ
+       ABLTZ
+       ABNEZ
        AFNEGD
        AFNEGS
        AFNED
index ed5d533402fb77fec232f19c956fa46f592adfbb..73fe8c284f165386b1495bfdce4bdcc86afed6bb 100644 (file)
@@ -406,20 +406,40 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
 }
 
 // InvertBranch inverts the condition of a conditional branch.
-func InvertBranch(i obj.As) obj.As {
-       switch i {
+func InvertBranch(as obj.As) obj.As {
+       switch as {
        case ABEQ:
                return ABNE
-       case ABNE:
-               return ABEQ
-       case ABLT:
-               return ABGE
+       case ABEQZ:
+               return ABNEZ
        case ABGE:
                return ABLT
-       case ABLTU:
-               return ABGEU
        case ABGEU:
                return ABLTU
+       case ABGEZ:
+               return ABLTZ
+       case ABGT:
+               return ABLE
+       case ABGTU:
+               return ABLEU
+       case ABGTZ:
+               return ABLEZ
+       case ABLE:
+               return ABGT
+       case ABLEU:
+               return ABGTU
+       case ABLEZ:
+               return ABGTZ
+       case ABLT:
+               return ABGE
+       case ABLTU:
+               return ABGEU
+       case ABLTZ:
+               return ABGEZ
+       case ABNE:
+               return ABEQ
+       case ABNEZ:
+               return ABEQZ
        default:
                panic("InvertBranch: not a branch")
        }
@@ -860,7 +880,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 
                for p := cursym.Func.Text; p != nil; p = p.Link {
                        switch p.As {
-                       case ABEQ, ABNE, ABLT, ABGE, ABLTU, ABGEU:
+                       case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
                                if p.To.Type != obj.TYPE_BRANCH {
                                        panic("assemble: instruction with branch-like opcode lacks destination")
                                }
@@ -917,7 +937,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
        // instructions will break everything--don't do it!
        for p := cursym.Func.Text; p != nil; p = p.Link {
                switch p.As {
-               case AJAL, ABEQ, ABNE, ABLT, ABLTU, ABGE, ABGEU:
+               case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, AJAL:
                        switch p.To.Type {
                        case obj.TYPE_BRANCH:
                                p.To.Type, p.To.Offset = obj.TYPE_CONST, p.Pcond.Pc-p.Pc
@@ -1778,7 +1798,29 @@ func instructionsForProg(p *obj.Prog) []*instruction {
                ins.rd, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
                ins.imm = p.To.Offset
 
-       case ABEQ, ABNE, ABLT, ABGE, ABLTU, ABGEU:
+       case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
+               switch ins.as {
+               case ABEQZ:
+                       ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg)
+               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)
+               case ABGTU:
+                       ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.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)
+               case ABLEU:
+                       ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg)
+               case ABLEZ:
+                       ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
+               case ABLTZ:
+                       ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg)
+               case ABNEZ:
+                       ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg)
+               }
                ins.imm = p.To.Offset
 
        case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go
new file mode 100644 (file)
index 0000000..b0ab5f7
--- /dev/null
@@ -0,0 +1,94 @@
+// 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.
+
+// +build riscv64
+
+package testbranch
+
+import (
+       "testing"
+)
+
+func testBEQZ(a int64) (r bool)
+func testBGEZ(a int64) (r bool)
+func testBGT(a, b int64) (r bool)
+func testBGTU(a, b int64) (r bool)
+func testBGTZ(a int64) (r bool)
+func testBLE(a, b int64) (r bool)
+func testBLEU(a, b int64) (r bool)
+func testBLEZ(a int64) (r bool)
+func testBLTZ(a int64) (r bool)
+func testBNEZ(a int64) (r bool)
+
+func TestBranchCondition(t *testing.T) {
+       tests := []struct{
+               ins string
+               a int64
+               b int64
+               fn func(a, b int64) bool
+               want bool
+       }{
+               {"BGT", 0, 1, testBGT, true},
+               {"BGT", 0, 0, testBGT, false},
+               {"BGT", 0, -1, testBGT, false},
+               {"BGT", -1, 0, testBGT, true},
+               {"BGT", 1, 0, testBGT, false},
+               {"BGTU", 0, 1, testBGTU, true},
+               {"BGTU", 0, -1, testBGTU, true},
+               {"BGTU", -1, 0, testBGTU, false},
+               {"BGTU", 1, 0, testBGTU, false},
+               {"BLE", 0, 1, testBLE, false},
+               {"BLE", 0, -1, testBLE, true},
+               {"BLE", 0, 0, testBLE, true},
+               {"BLE", -1, 0, testBLE, false},
+               {"BLE", 1, 0, testBLE, true},
+               {"BLEU", 0, 1, testBLEU, false},
+               {"BLEU", 0, -1, testBLEU, false},
+               {"BLEU", 0, 0, testBLEU, true},
+               {"BLEU", -1, 0, testBLEU, true},
+               {"BLEU", 1, 0, testBLEU, true},
+       }
+       for _, test := range tests {
+               t.Run(test.ins, func(t *testing.T) {
+                       if got := test.fn(test.a, test.b); got != test.want {
+                               t.Errorf("%v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
+                       }
+               })
+       }
+}
+
+func TestBranchZero(t *testing.T) {
+       tests := []struct{
+               ins string
+               a int64
+               fn func(a int64) bool
+               want bool
+       }{
+               {"BEQZ", -1, testBEQZ, false},
+               {"BEQZ", 0, testBEQZ, true},
+               {"BEQZ", 1, testBEQZ, false},
+               {"BGEZ", -1, testBGEZ, false},
+               {"BGEZ", 0, testBGEZ, true},
+               {"BGEZ", 1, testBGEZ, true},
+               {"BGTZ", -1, testBGTZ, false},
+               {"BGTZ", 0, testBGTZ, false},
+               {"BGTZ", 1, testBGTZ, true},
+               {"BLEZ", -1, testBLEZ, true},
+               {"BLEZ", 0, testBLEZ, true},
+               {"BLEZ", 1, testBLEZ, false},
+               {"BLTZ", -1, testBLTZ, true},
+               {"BLTZ", 0, testBLTZ, false},
+               {"BLTZ", 1, testBLTZ, false},
+               {"BNEZ", -1, testBNEZ, true},
+               {"BNEZ", 0, testBNEZ, false},
+               {"BNEZ", 1, testBNEZ, true},
+       }
+       for _, test := range tests {
+               t.Run(test.ins, func(t *testing.T) {
+                       if got := test.fn(test.a); got != test.want {
+                               t.Errorf("%v %v = %v, want %v", test.ins, test.a, got, test.want)
+                       }
+               })
+       }
+}
diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s
new file mode 100644 (file)
index 0000000..6cff235
--- /dev/null
@@ -0,0 +1,111 @@
+// 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.
+
+// +build riscv64
+
+#include "textflag.h"
+
+// func testBEQZ(a int64) (r bool)
+TEXT ·testBEQZ(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     $1, X6
+       BEQZ    X5, b
+       MOV     $0, X6
+b:
+       MOV     X6, r+8(FP)
+       RET
+
+// func testBGEZ(a int64) (r bool)
+TEXT ·testBGEZ(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     $1, X6
+       BGEZ    X5, b
+       MOV     $0, X6
+b:
+       MOV     X6, r+8(FP)
+       RET
+
+// func testBGT(a, b int64) (r bool)
+TEXT ·testBGT(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     b+8(FP), X6
+       MOV     $1, X7
+       BGT     X5, X6, b
+       MOV     $0, X7
+b:
+       MOV     X7, r+16(FP)
+       RET
+
+// func testBGTU(a, b int64) (r bool)
+TEXT ·testBGTU(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     b+8(FP), X6
+       MOV     $1, X7
+       BGTU    X5, X6, b
+       MOV     $0, X7
+b:
+       MOV     X7, r+16(FP)
+       RET
+
+// func testBGTZ(a int64) (r bool)
+TEXT ·testBGTZ(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     $1, X6
+       BGTZ    X5, b
+       MOV     $0, X6
+b:
+       MOV     X6, r+8(FP)
+       RET
+
+// func testBLE(a, b int64) (r bool)
+TEXT ·testBLE(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     b+8(FP), X6
+       MOV     $1, X7
+       BLE     X5, X6, b
+       MOV     $0, X7
+b:
+       MOV     X7, r+16(FP)
+       RET
+
+// func testBLEU(a, b int64) (r bool)
+TEXT ·testBLEU(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     b+8(FP), X6
+       MOV     $1, X7
+       BLEU    X5, X6, b
+       MOV     $0, X7
+b:
+       MOV     X7, r+16(FP)
+       RET
+
+// func testBLEZ(a int64) (r bool)
+TEXT ·testBLEZ(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     $1, X6
+       BLEZ    X5, b
+       MOV     $0, X6
+b:
+       MOV     X6, r+8(FP)
+       RET
+
+// func testBLTZ(a int64) (r bool)
+TEXT ·testBLTZ(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     $1, X6
+       BLTZ    X5, b
+       MOV     $0, X6
+b:
+       MOV     X6, r+8(FP)
+       RET
+
+// func testBNEZ(a int64) (r bool)
+TEXT ·testBNEZ(SB),NOSPLIT,$0-0
+       MOV     a+0(FP), X5
+       MOV     $1, X6
+       BNEZ    X5, b
+       MOV     $0, X6
+b:
+       MOV     X6, r+8(FP)
+       RET