]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/{asm,compile}: avoid zeroAuto clobbering flags on s390x
authorMichael Munday <munday@ca.ibm.com>
Sun, 30 Apr 2017 18:25:57 +0000 (14:25 -0400)
committerMichael Munday <munday@ca.ibm.com>
Tue, 2 May 2017 17:43:31 +0000 (17:43 +0000)
This CL modifies how MOV[DWHB] instructions that store a constant to
memory are assembled to avoid them clobbering the condition code
(flags). It also modifies zeroAuto to use MOVD instructions instead of
CLEAR (which is assembled as XC).

MOV[DWHB]storeconst ops also no longer clobbers flags.

Note: this CL modifies the assembler so that it can no longer handle
immediates outside the range of an int16 or offsets from SB, which
reflects what the machine instructions support. The compiler doesn't
need this capability any more and I don't think this affects any existing
assembly, but it is easy to workaround if it does.

Fixes #20187.

Change-Id: Ie54947ff38367bd6a19962bf1a6d0296a4accffb
Reviewed-on: https://go-review.googlesource.com/42179
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/asm/internal/asm/testdata/s390x.s
src/cmd/compile/internal/s390x/ggen.go
src/cmd/compile/internal/ssa/gen/S390X.rules
src/cmd/compile/internal/ssa/gen/S390XOps.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewrite.go
src/cmd/compile/internal/ssa/rewriteS390X.go
src/cmd/internal/obj/s390x/asmz.go

index d8688e7ba6a594d0625ee5cfb1c1434e49ed521a..6cc129ccc51cd6ed26299a5e29bebab4241e1335 100644 (file)
@@ -47,10 +47,16 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
        MOVH    $-512, R3             // a739fe00
        MOVB    $-1, R4               // a749ffff
 
-       MOVD    $-2147483648, n-8(SP) // c0b180000000e3b0f0100024
-       MOVW    $-131072, n-8(SP)     // c0b1fffe0000e3b0f0100050
-       MOVH    $-512, n-8(SP)        // e544f010fe00
+       MOVD    $32767, n-8(SP)       // e548f0107fff
+       MOVD    $-1, -524288(R1)      // e3a010008071e548a000ffff
+       MOVW    $32767, n-8(SP)       // e54cf0107fff
+       MOVW    $-32768, 4096(R2)     // e3a020000171e54ca0008000
+       MOVH    $512, n-8(SP)         // e544f0100200
+       MOVH    $-512, 524288(R3)     // c0a10008000041aa3000e544a000fe00
        MOVB    $-1, n-8(SP)          // 92fff010
+       MOVB    $255, 4096(R4)        // ebff40000152
+       MOVB    $-128, -524288(R5)    // eb8050008052
+       MOVB    $1, -524289(R6)       // c0a1fff7ffff41aa60009201a000
 
        ADD     R1, R2                // b9e81022
        ADD     R1, R2, R3            // b9e81032
index f1ab5b0ddc68d5731ce1a7d67f6c98258721d42c..636ab16dd4ab4915333547d472a2750a15496fc4 100644 (file)
@@ -88,15 +88,20 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
 }
 
 func zeroAuto(pp *gc.Progs, n *gc.Node) {
-       // Note: this code must not clobber any registers.
-       p := pp.Prog(s390x.ACLEAR)
-       p.From.Type = obj.TYPE_CONST
-       p.From.Offset = n.Type.Size()
-       p.To.Type = obj.TYPE_MEM
-       p.To.Name = obj.NAME_AUTO
-       p.To.Reg = s390x.REGSP
-       p.To.Offset = n.Xoffset
-       p.To.Sym = n.Sym.Linksym()
+       // Note: this code must not clobber any registers or the
+       // condition code.
+       sym := n.Sym.Linksym()
+       size := n.Type.Size()
+       for i := int64(0); i < size; i += int64(gc.Widthptr) {
+               p := pp.Prog(s390x.AMOVD)
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = 0
+               p.To.Type = obj.TYPE_MEM
+               p.To.Name = obj.NAME_AUTO
+               p.To.Reg = s390x.REGSP
+               p.To.Offset = n.Xoffset + i
+               p.To.Sym = sym
+       }
 }
 
 func ginsnop(pp *gc.Progs) {
index eef6853d9feaf5b9799ab176431bce77ad9b93ac..f54169de58102c986abd8b6f1e0e9bfa9660a18d 100644 (file)
 (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVDstore [off1+off2] {sym} ptr val mem)
 
 // Fold constants into stores.
-(MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && validValAndOff(c,off) && int64(int16(c)) == c && ptr.Op != OpSB ->
+(MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB ->
        (MOVDstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
-(MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB ->
+(MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB ->
        (MOVWstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
-(MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && ptr.Op != OpSB ->
+(MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && isU12Bit(off) && ptr.Op != OpSB ->
        (MOVHstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
-(MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && ptr.Op != OpSB ->
+(MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && is20Bit(off) && ptr.Op != OpSB ->
        (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
 
 // Fold address offsets into constant stores.
-(MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+(MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) ->
        (MOVDstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-(MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+(MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) ->
        (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-(MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+(MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) ->
        (MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-(MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+(MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && is20Bit(ValAndOff(sc).Off()+off) ->
        (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 
 // We need to fold MOVDaddr into the MOVx ops so that the live variable analysis knows
 (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
        (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 
-(MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+// Cannot store constant to SB directly (no 'move relative long immediate' instructions).
+(MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
        (MOVDstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+(MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
        (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+(MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
        (MOVHstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+(MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
        (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
 
 // generating indexed loads and stores
        -> (XORWload <t> [off] {sym} x ptr mem)
 
 // Combine constant stores into larger (unaligned) stores.
-// It doesn't work to global data (based on SB),
-// because STGRL doesn't support unaligned address
+// Avoid SB because constant stores to relative offsets are
+// emulated by the assembler and also can't handle unaligned offsets.
 (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
   && p.Op != OpSB
   && x.Uses == 1
   && x.Uses == 1
   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
   && clobber(x)
-  -> (MOVWstoreconst [makeValAndOff(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16, ValAndOff(a).Off())] {s} p mem)
+  -> (MOVWstore [ValAndOff(a).Off()] {s} p (MOVDconst [int64(int32(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16))]) mem)
 (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
   && p.Op != OpSB
   && x.Uses == 1
index a1a5aa2dc43c731eb342df005459be33563ac2dc..c3edb9385dff44ddf78ab1c152d55dcff86eb093 100644 (file)
@@ -406,10 +406,10 @@ func init() {
                // For storeconst ops, the AuxInt field encodes both
                // the value to store and an address offset of the store.
                // Cast AuxInt to a ValAndOff to extract Val and Off fields.
-               {name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux.  arg1=mem
-               {name: "MOVHstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVH", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store low 2 bytes of ...
-               {name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store low 4 bytes of ...
-               {name: "MOVDstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVD", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of ...
+               {name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux.  arg1=mem
+               {name: "MOVHstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVH", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 2 bytes of ...
+               {name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 4 bytes of ...
+               {name: "MOVDstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVD", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of ...
 
                {name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},
 
index 47c9dba37d1f0cd9eabaa3a8c464e579c567a73c..32d928388fa8bbc94f04bb1820bab1b47fbf860e 100644 (file)
@@ -20356,7 +20356,6 @@ var opcodeTable = [...]opInfo{
                name:           "MOVBstoreconst",
                auxType:        auxSymValAndOff,
                argLen:         2,
-               clobberFlags:   true,
                faultOnNilArg0: true,
                symEffect:      SymWrite,
                asm:            s390x.AMOVB,
@@ -20370,7 +20369,6 @@ var opcodeTable = [...]opInfo{
                name:           "MOVHstoreconst",
                auxType:        auxSymValAndOff,
                argLen:         2,
-               clobberFlags:   true,
                faultOnNilArg0: true,
                symEffect:      SymWrite,
                asm:            s390x.AMOVH,
@@ -20384,7 +20382,6 @@ var opcodeTable = [...]opInfo{
                name:           "MOVWstoreconst",
                auxType:        auxSymValAndOff,
                argLen:         2,
-               clobberFlags:   true,
                faultOnNilArg0: true,
                symEffect:      SymWrite,
                asm:            s390x.AMOVW,
@@ -20398,7 +20395,6 @@ var opcodeTable = [...]opInfo{
                name:           "MOVDstoreconst",
                auxType:        auxSymValAndOff,
                argLen:         2,
-               clobberFlags:   true,
                faultOnNilArg0: true,
                symEffect:      SymWrite,
                asm:            s390x.AMOVD,
index ccd723388d6295571fc467177512dafd27c8e682..db1540d16c5b151248b2dc662b3832894c628573 100644 (file)
@@ -365,6 +365,11 @@ func is16Bit(n int64) bool {
        return n == int64(int16(n))
 }
 
+// isU12Bit reports whether n can be represented as an unsigned 12 bit integer.
+func isU12Bit(n int64) bool {
+       return 0 <= n && n < (1<<12)
+}
+
 // isU16Bit reports whether n can be represented as an unsigned 16 bit integer.
 func isU16Bit(n int64) bool {
        return n == int64(uint16(n))
index d8e8bd70f1b6244825bd3aef5d81745ba7e97101..ee3f07e904aa90ceaa3692751d9b871ef788ae3e 100644 (file)
@@ -9108,7 +9108,7 @@ func rewriteValueS390X_OpS390XMOVBstore_0(v *Value) bool {
                return true
        }
        // match: (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem)
-       // cond: validOff(off) && ptr.Op != OpSB
+       // cond: is20Bit(off) && ptr.Op != OpSB
        // result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
        for {
                off := v.AuxInt
@@ -9120,7 +9120,7 @@ func rewriteValueS390X_OpS390XMOVBstore_0(v *Value) bool {
                }
                c := v_1.AuxInt
                mem := v.Args[2]
-               if !(validOff(off) && ptr.Op != OpSB) {
+               if !(is20Bit(off) && ptr.Op != OpSB) {
                        break
                }
                v.reset(OpS390XMOVBstoreconst)
@@ -9581,7 +9581,7 @@ func rewriteValueS390X_OpS390XMOVBstore_10(v *Value) bool {
 }
 func rewriteValueS390X_OpS390XMOVBstoreconst_0(v *Value) bool {
        // match: (MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem)
-       // cond: ValAndOff(sc).canAdd(off)
+       // cond: is20Bit(ValAndOff(sc).Off()+off)
        // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
        for {
                sc := v.AuxInt
@@ -9593,7 +9593,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst_0(v *Value) bool {
                off := v_0.AuxInt
                ptr := v_0.Args[0]
                mem := v.Args[1]
-               if !(ValAndOff(sc).canAdd(off)) {
+               if !(is20Bit(ValAndOff(sc).Off() + off)) {
                        break
                }
                v.reset(OpS390XMOVBstoreconst)
@@ -9604,7 +9604,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst_0(v *Value) bool {
                return true
        }
        // match: (MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
-       // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+       // cond: ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
        // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
        for {
                sc := v.AuxInt
@@ -9617,7 +9617,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst_0(v *Value) bool {
                sym2 := v_0.Aux
                ptr := v_0.Args[0]
                mem := v.Args[1]
-               if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+               if !(ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
                        break
                }
                v.reset(OpS390XMOVBstoreconst)
@@ -12765,7 +12765,7 @@ func rewriteValueS390X_OpS390XMOVDstore_0(v *Value) bool {
                return true
        }
        // match: (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem)
-       // cond: validValAndOff(c,off) && int64(int16(c)) == c && ptr.Op != OpSB
+       // cond: is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB
        // result: (MOVDstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
        for {
                off := v.AuxInt
@@ -12777,7 +12777,7 @@ func rewriteValueS390X_OpS390XMOVDstore_0(v *Value) bool {
                }
                c := v_1.AuxInt
                mem := v.Args[2]
-               if !(validValAndOff(c, off) && int64(int16(c)) == c && ptr.Op != OpSB) {
+               if !(is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB) {
                        break
                }
                v.reset(OpS390XMOVDstoreconst)
@@ -12982,7 +12982,7 @@ func rewriteValueS390X_OpS390XMOVDstore_0(v *Value) bool {
 }
 func rewriteValueS390X_OpS390XMOVDstoreconst_0(v *Value) bool {
        // match: (MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem)
-       // cond: ValAndOff(sc).canAdd(off)
+       // cond: isU12Bit(ValAndOff(sc).Off()+off)
        // result: (MOVDstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
        for {
                sc := v.AuxInt
@@ -12994,7 +12994,7 @@ func rewriteValueS390X_OpS390XMOVDstoreconst_0(v *Value) bool {
                off := v_0.AuxInt
                ptr := v_0.Args[0]
                mem := v.Args[1]
-               if !(ValAndOff(sc).canAdd(off)) {
+               if !(isU12Bit(ValAndOff(sc).Off() + off)) {
                        break
                }
                v.reset(OpS390XMOVDstoreconst)
@@ -13005,7 +13005,7 @@ func rewriteValueS390X_OpS390XMOVDstoreconst_0(v *Value) bool {
                return true
        }
        // match: (MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
-       // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+       // cond: ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
        // result: (MOVDstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
        for {
                sc := v.AuxInt
@@ -13018,7 +13018,7 @@ func rewriteValueS390X_OpS390XMOVDstoreconst_0(v *Value) bool {
                sym2 := v_0.Aux
                ptr := v_0.Args[0]
                mem := v.Args[1]
-               if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+               if !(ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
                        break
                }
                v.reset(OpS390XMOVDstoreconst)
@@ -14725,7 +14725,7 @@ func rewriteValueS390X_OpS390XMOVHstore_0(v *Value) bool {
                return true
        }
        // match: (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem)
-       // cond: validOff(off) && ptr.Op != OpSB
+       // cond: isU12Bit(off) && ptr.Op != OpSB
        // result: (MOVHstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
        for {
                off := v.AuxInt
@@ -14737,7 +14737,7 @@ func rewriteValueS390X_OpS390XMOVHstore_0(v *Value) bool {
                }
                c := v_1.AuxInt
                mem := v.Args[2]
-               if !(validOff(off) && ptr.Op != OpSB) {
+               if !(isU12Bit(off) && ptr.Op != OpSB) {
                        break
                }
                v.reset(OpS390XMOVHstoreconst)
@@ -15015,8 +15015,12 @@ func rewriteValueS390X_OpS390XMOVHstore_10(v *Value) bool {
        return false
 }
 func rewriteValueS390X_OpS390XMOVHstoreconst_0(v *Value) bool {
+       b := v.Block
+       _ = b
+       types := &b.Func.Config.Types
+       _ = types
        // match: (MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem)
-       // cond: ValAndOff(sc).canAdd(off)
+       // cond: isU12Bit(ValAndOff(sc).Off()+off)
        // result: (MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
        for {
                sc := v.AuxInt
@@ -15028,7 +15032,7 @@ func rewriteValueS390X_OpS390XMOVHstoreconst_0(v *Value) bool {
                off := v_0.AuxInt
                ptr := v_0.Args[0]
                mem := v.Args[1]
-               if !(ValAndOff(sc).canAdd(off)) {
+               if !(isU12Bit(ValAndOff(sc).Off() + off)) {
                        break
                }
                v.reset(OpS390XMOVHstoreconst)
@@ -15039,7 +15043,7 @@ func rewriteValueS390X_OpS390XMOVHstoreconst_0(v *Value) bool {
                return true
        }
        // match: (MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
-       // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+       // cond: ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
        // result: (MOVHstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
        for {
                sc := v.AuxInt
@@ -15052,7 +15056,7 @@ func rewriteValueS390X_OpS390XMOVHstoreconst_0(v *Value) bool {
                sym2 := v_0.Aux
                ptr := v_0.Args[0]
                mem := v.Args[1]
-               if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+               if !(ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
                        break
                }
                v.reset(OpS390XMOVHstoreconst)
@@ -15064,7 +15068,7 @@ func rewriteValueS390X_OpS390XMOVHstoreconst_0(v *Value) bool {
        }
        // match: (MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem))
        // cond: p.Op != OpSB   && x.Uses == 1   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()   && clobber(x)
-       // result: (MOVWstoreconst [makeValAndOff(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16, ValAndOff(a).Off())] {s} p mem)
+       // result: (MOVWstore [ValAndOff(a).Off()] {s} p (MOVDconst [int64(int32(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16))]) mem)
        for {
                c := v.AuxInt
                s := v.Aux
@@ -15084,10 +15088,13 @@ func rewriteValueS390X_OpS390XMOVHstoreconst_0(v *Value) bool {
                if !(p.Op != OpSB && x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
                        break
                }
-               v.reset(OpS390XMOVWstoreconst)
-               v.AuxInt = makeValAndOff(ValAndOff(c).Val()&0xffff|ValAndOff(a).Val()<<16, ValAndOff(a).Off())
+               v.reset(OpS390XMOVWstore)
+               v.AuxInt = ValAndOff(a).Off()
                v.Aux = s
                v.AddArg(p)
+               v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, types.UInt64)
+               v0.AuxInt = int64(int32(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16))
+               v.AddArg(v0)
                v.AddArg(mem)
                return true
        }
@@ -17176,7 +17183,7 @@ func rewriteValueS390X_OpS390XMOVWstore_0(v *Value) bool {
                return true
        }
        // match: (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem)
-       // cond: validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB
+       // cond: is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB
        // result: (MOVWstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
        for {
                off := v.AuxInt
@@ -17188,7 +17195,7 @@ func rewriteValueS390X_OpS390XMOVWstore_0(v *Value) bool {
                }
                c := v_1.AuxInt
                mem := v.Args[2]
-               if !(validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB) {
+               if !(is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB) {
                        break
                }
                v.reset(OpS390XMOVWstoreconst)
@@ -17491,7 +17498,7 @@ func rewriteValueS390X_OpS390XMOVWstoreconst_0(v *Value) bool {
        types := &b.Func.Config.Types
        _ = types
        // match: (MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem)
-       // cond: ValAndOff(sc).canAdd(off)
+       // cond: isU12Bit(ValAndOff(sc).Off()+off)
        // result: (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
        for {
                sc := v.AuxInt
@@ -17503,7 +17510,7 @@ func rewriteValueS390X_OpS390XMOVWstoreconst_0(v *Value) bool {
                off := v_0.AuxInt
                ptr := v_0.Args[0]
                mem := v.Args[1]
-               if !(ValAndOff(sc).canAdd(off)) {
+               if !(isU12Bit(ValAndOff(sc).Off() + off)) {
                        break
                }
                v.reset(OpS390XMOVWstoreconst)
@@ -17514,7 +17521,7 @@ func rewriteValueS390X_OpS390XMOVWstoreconst_0(v *Value) bool {
                return true
        }
        // match: (MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
-       // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+       // cond: ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
        // result: (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
        for {
                sc := v.AuxInt
@@ -17527,7 +17534,7 @@ func rewriteValueS390X_OpS390XMOVWstoreconst_0(v *Value) bool {
                sym2 := v_0.Aux
                ptr := v_0.Args[0]
                mem := v.Args[1]
-               if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+               if !(ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
                        break
                }
                v.reset(OpS390XMOVWstoreconst)
index 624d3b74ffd528e75389cd4805edf017602624c0..3bba7b2a5ce905f4d4c6b34e1c95c7a3bce2bc24 100644 (file)
@@ -89,21 +89,26 @@ var optab = []Optab{
        Optab{AMOVBZ, C_DCON, C_NONE, C_NONE, C_REG, 3, 0},
 
        // store constant
-       Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
-       Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
-       Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
-       Optab{AMOVBZ, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
-       Optab{AMOVB, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
-       Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
-       Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
-       Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
-       Optab{AMOVB, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
-       Optab{AMOVBZ, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
-       Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
-       Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
-       Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
-       Optab{AMOVB, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
-       Optab{AMOVBZ, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVD, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVD, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVW, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVW, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVWZ, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVWZ, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVB, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVB, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVBZ, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVBZ, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+       Optab{AMOVD, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVD, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVW, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVW, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVWZ, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVWZ, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVB, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVB, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVBZ, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+       Optab{AMOVBZ, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
 
        // store
        Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
@@ -3303,84 +3308,49 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
                v := c.regoff(&p.From)
                d := c.regoff(&p.To)
                r := p.To.Reg
-               x := p.To.Index
+               if p.To.Index != 0 {
+                       c.ctxt.Diag("cannot use index register")
+               }
                if r == 0 {
                        r = o.param
                }
-               if int32(int16(v)) == v && x == 0 {
-                       if d < 0 || d >= DISP12 {
-                               if r == REGTMP || r == REGTMP2 {
-                                       zRIL(_a, op_AGFI, uint32(r), uint32(d), asm)
+               var opcode uint32
+               switch p.As {
+               case AMOVD:
+                       opcode = op_MVGHI
+               case AMOVW, AMOVWZ:
+                       opcode = op_MVHI
+               case AMOVH, AMOVHZ:
+                       opcode = op_MVHHI
+               case AMOVB, AMOVBZ:
+                       opcode = op_MVI
+               }
+               if d < 0 || d >= DISP12 {
+                       if r == REGTMP {
+                               c.ctxt.Diag("displacement must be in range [0, 4096) to use %v", r)
+                       }
+                       if d >= -DISP20/2 && d < DISP20/2 {
+                               if opcode == op_MVI {
+                                       opcode = op_MVIY
                                } else {
-                                       zRIL(_a, op_LGFI, REGTMP, uint32(d), asm)
-                                       zRRE(op_AGR, REGTMP, uint32(r), asm)
+                                       zRXY(op_LAY, uint32(REGTMP), 0, uint32(r), uint32(d), asm)
                                        r = REGTMP
+                                       d = 0
                                }
-                               d = 0
-                       }
-                       var opcode uint32
-                       switch p.As {
-                       case AMOVD:
-                               opcode = op_MVGHI
-                       case AMOVW, AMOVWZ:
-                               opcode = op_MVHI
-                       case AMOVH, AMOVHZ:
-                               opcode = op_MVHHI
-                       case AMOVB, AMOVBZ:
-                               opcode = op_MVI
-                       }
-                       if opcode == op_MVI {
-                               zSI(opcode, uint32(v), uint32(r), uint32(d), asm)
                        } else {
-                               zSIL(opcode, uint32(r), uint32(d), uint32(v), asm)
-                       }
-               } else {
-                       zRIL(_a, op_LGFI, REGTMP2, uint32(v), asm)
-                       if d < -DISP20/2 || d >= DISP20/2 {
-                               if r == REGTMP {
-                                       zRIL(_a, op_AGFI, REGTMP, uint32(d), asm)
-                               } else {
-                                       zRIL(_a, op_LGFI, REGTMP, uint32(d), asm)
-                                       if x != 0 {
-                                               zRRE(op_AGR, REGTMP, uint32(x), asm)
-                                       }
-                                       x = REGTMP
-                               }
+                               zRIL(_a, op_LGFI, REGTMP, uint32(d), asm)
+                               zRX(op_LA, REGTMP, REGTMP, uint32(r), 0, asm)
+                               r = REGTMP
                                d = 0
                        }
-                       zRXY(c.zopstore(p.As), REGTMP2, uint32(x), uint32(r), uint32(d), asm)
-               }
-
-       case 73: // mov $constant addr (including relocation)
-               v := c.regoff(&p.From)
-               d := c.regoff(&p.To)
-               a := uint32(0)
-               if d&1 != 0 {
-                       d -= 1
-                       a = 1
                }
-               zRIL(_b, op_LARL, REGTMP, uint32(d), asm)
-               c.addrilreloc(p.To.Sym, int64(d))
-               if int32(int16(v)) == v {
-                       var opcode uint32
-                       switch p.As {
-                       case AMOVD:
-                               opcode = op_MVGHI
-                       case AMOVW, AMOVWZ:
-                               opcode = op_MVHI
-                       case AMOVH, AMOVHZ:
-                               opcode = op_MVHHI
-                       case AMOVB, AMOVBZ:
-                               opcode = op_MVI
-                       }
-                       if opcode == op_MVI {
-                               zSI(opcode, uint32(v), REGTMP, a, asm)
-                       } else {
-                               zSIL(opcode, REGTMP, a, uint32(v), asm)
-                       }
-               } else {
-                       zRIL(_a, op_LGFI, REGTMP2, uint32(v), asm)
-                       zRXY(c.zopstore(p.As), REGTMP2, 0, REGTMP, a, asm)
+               switch opcode {
+               case op_MVI:
+                       zSI(opcode, uint32(v), uint32(r), uint32(d), asm)
+               case op_MVIY:
+                       zSIY(opcode, uint32(v), uint32(r), uint32(d), asm)
+               default:
+                       zSIL(opcode, uint32(r), uint32(d), uint32(v), asm)
                }
 
        case 74: // mov reg addr (including relocation)