]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/asm: add s390x branch-on-count instructions
authorMichael Munday <mike.munday@ibm.com>
Thu, 15 Aug 2019 20:53:37 +0000 (21:53 +0100)
committerMichael Munday <mike.munday@ibm.com>
Wed, 9 Oct 2019 15:04:59 +0000 (15:04 +0000)
The branch-on-count instructions on s390x decrement the input
register and then compare its value to 0. If not equal the branch
is taken.

These instructions are useful for implementing loops with a set
number of iterations (which might be in a register).

For example, this for loop:

for i := 0; i < n; i++ {
... // i is not used or modified in the loop
}

Could be implemented using this assembly:

MOVD  Rn, Ri
loop:
...
BRCTG Ri, loop

Note that i will count down from n in the assembly whereas in the
original for loop it counted up to n which is why we can't use i
in the loop.

These instructions will only be used in hand-written codegen and
assembly for now since SSA blocks cannot currently modify values.
We could look into this in the future though.

Change-Id: Iaab93b8aa2699513b825439b8ea20d8fe2ea1ee6
Reviewed-on: https://go-review.googlesource.com/c/go/+/199977
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/asm/internal/arch/s390x.go
src/cmd/asm/internal/asm/testdata/s390x.s
src/cmd/compile/internal/s390x/ggen.go
src/cmd/internal/obj/s390x/a.out.go
src/cmd/internal/obj/s390x/anames.go
src/cmd/internal/obj/s390x/asmz.go

index 6efae26e1c3815ae06e17b57479ee8e091efdd7b..0a4d2788994b576ffcf4523b910532d15a4f9bbf 100644 (file)
@@ -30,6 +30,8 @@ func jumpS390x(word string) bool {
                "BR",
                "BVC",
                "BVS",
+               "BRCT",
+               "BRCTG",
                "CMPBEQ",
                "CMPBGE",
                "CMPBGT",
index 6888651007051ce3bafb60414c7f5f7c61fb4708..bc0a49c8cca122ceea957ca234b539394cf97560 100644 (file)
@@ -266,6 +266,9 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
        BLTU    0(PC)                  // a7540000
        BLEU    0(PC)                  // a7d40000
 
+       BRCT    R1, 0(PC)              // a7160000
+       BRCTG   R2, 0(PC)              // a7270000
+
        CMPBNE  R1, R2, 0(PC)          // ec1200007064
        CMPBEQ  R3, R4, 0(PC)          // ec3400008064
        CMPBLT  R5, R6, 0(PC)          // ec5600004064
index ae9965c378cb124fa4f08d157b1e048f7360f598..16af190b2f42373db68ab51d9311e00f76eb5306 100644 (file)
@@ -38,18 +38,14 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
 
        // Generate a loop of large clears.
        if cnt > clearLoopCutoff {
-               n := cnt - (cnt % 256)
-               end := int16(s390x.REGRT2)
-               p = pp.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, off+n, obj.TYPE_REG, end, 0)
-               p.Reg = reg
+               ireg := int16(s390x.REGRT2) // register holds number of remaining loop iterations
+               p = pp.Appendpp(p, s390x.AMOVD, obj.TYPE_CONST, 0, cnt/256, obj.TYPE_REG, ireg, 0)
                p = pp.Appendpp(p, s390x.ACLEAR, obj.TYPE_CONST, 0, 256, obj.TYPE_MEM, reg, off)
                pl := p
                p = pp.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0)
-               p = pp.Appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0)
-               p = pp.Appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+               p = pp.Appendpp(p, s390x.ABRCTG, obj.TYPE_REG, ireg, 0, obj.TYPE_BRANCH, 0, 0)
                gc.Patch(p, pl)
-
-               cnt -= n
+               cnt = cnt % 256
        }
 
        // Generate remaining clear instructions without a loop.
index b44531cfe62a3b663d24a7d9d4a1afc5c11c89c0..7dcf3e8cfe7a65fdd583a2758a29bc53fecaac05 100644 (file)
@@ -409,6 +409,10 @@ const (
        ABVS
        ASYSCALL
 
+       // branch on count
+       ABRCT
+       ABRCTG
+
        // compare and branch
        ACRJ
        ACGRJ
index dad710bc45eb52b71e70e0fc5bc327f10928fee9..c3a76a0df0b6790eb007c9b48fa033488e4759ee 100644 (file)
@@ -155,6 +155,8 @@ var Anames = []string{
        "BVC",
        "BVS",
        "SYSCALL",
+       "BRCT",
+       "BRCTG",
        "CRJ",
        "CGRJ",
        "CLRJ",
index ea254c74a84b561c80c8fd13c6239c21604946a9..3cc7d0b160e331d73c6874464fac972ed2ceba89 100644 (file)
@@ -256,6 +256,10 @@ var optab = []Optab{
        {i: 90, as: ACLGIJ, a1: C_SCON, a2: C_REG, a3: C_ADDCON, a6: C_SBRA},
        {i: 90, as: ACMPUBEQ, a1: C_REG, a3: C_ANDCON, a6: C_SBRA},
 
+       // branch on count
+       {i: 41, as: ABRCT, a1: C_REG, a6: C_SBRA},
+       {i: 41, as: ABRCTG, a1: C_REG, a6: C_SBRA},
+
        // move on condition
        {i: 17, as: AMOVDEQ, a1: C_REG, a6: C_REG},
 
@@ -3394,6 +3398,21 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
                        *asm = append(*asm, uint8(wd))
                }
 
+       case 41: // branch on count
+               r1 := p.From.Reg
+               ri2 := (p.Pcond.Pc - p.Pc) >> 1
+               if int64(int16(ri2)) != ri2 {
+                       c.ctxt.Diag("branch target too far away")
+               }
+               var opcode uint32
+               switch p.As {
+               case ABRCT:
+                       opcode = op_BRCT
+               case ABRCTG:
+                       opcode = op_BRCTG
+               }
+               zRI(opcode, uint32(r1), uint32(ri2), asm)
+
        case 47: // negate [reg] reg
                r := p.From.Reg
                if r == 0 {