s390x.mx raw
1 // Copyright 2025 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package asmgen
6
7 var ArchS390X = &Arch{
8 Name: "s390x",
9 WordBits: 64,
10 WordBytes: 8,
11 CarrySafeLoop: true,
12
13 regs: [][]byte{
14 // R0 is 0 by convention in this code (see setup).
15 // R10 is the assembler/linker temporary.
16 // R11 is a second assembler/linker temporary, for wide multiply.
17 // We allow allocating R10 and R11 so that we can use them as
18 // direct multiplication targets while tracking whether they're in use.
19 // R13 is g.
20 // R14 is LR.
21 // R15 is SP.
22 "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9",
23 "R10", "R11", "R12",
24 },
25 reg0: "R0",
26 regTmp: "R10",
27 setup: s390xSetup,
28 maxColumns: 2,
29 op3: s390xOp3,
30 hint: s390xHint,
31
32 // Instruction reference: chapter 7 of
33 // https://www.ibm.com/docs/en/SSQ2R2_15.0.0/com.ibm.tpf.toolkit.hlasm.doc/dz9zr006.pdf
34
35 mov: "MOVD",
36 adds: "ADDC", // ADD is an alias for ADDC, sets carry
37 adcs: "ADDE",
38 subs: "SUBC", // SUB is an alias for SUBC, sets carry
39 sbcs: "SUBE",
40 mulWideF: s390MulWide,
41 lsh: "SLD",
42 rsh: "SRD",
43 and: "AND",
44 or: "OR",
45 xor: "XOR",
46 neg: "NEG",
47 lea: "LAY", // LAY because LA only accepts positive offsets
48
49 jmpZero: "CMPBEQ %s, $0, %s",
50 jmpNonZero: "CMPBNE %s, $0, %s",
51 }
52
53 func s390xSetup(f *Func) {
54 a := f.Asm
55 if f.Name == "addVV" || f.Name == "subVV" {
56 // S390x, unlike every other system, has vector instructions
57 // that can propagate carry bits during parallel adds (VACC).
58 // Instead of trying to generate that for this one system,
59 // jump to the hand-written code in arithvec_s390x.s.
60 a.Printf("\tMOVB ·hasVX(SB), R1\n")
61 a.Printf("\tCMPBEQ R1, $0, novec\n")
62 a.Printf("\tJMP ·%svec(SB)\n", f.Name)
63 a.Printf("novec:\n")
64 }
65 a.Printf("\tMOVD $0, R0\n")
66 }
67
68 func s390xOp3(name []byte) bool {
69 if name == "AND" { // AND with immediate only takes imm, reg; not imm, reg, reg.
70 return false
71 }
72 return true
73 }
74
75 func s390xHint(_ *Asm, h Hint) []byte {
76 switch h {
77 case HintMulSrc:
78 return "R11"
79 case HintMulHi:
80 return "R10"
81 }
82 return ""
83 }
84
85 func s390MulWide(a *Asm, src1, src2, dstlo, dsthi Reg) {
86 if src1.name != "R11" && src2.name != "R11" {
87 a.Fatalf("mulWide src1 or src2 must be R11")
88 }
89 if dstlo.name != "R11" {
90 a.Fatalf("mulWide dstlo must be R11")
91 }
92 if dsthi.name != "R10" {
93 a.Fatalf("mulWide dsthi must be R10")
94 }
95 src := src1
96 if src.name == "R11" {
97 src = src2
98 }
99 a.Printf("\tMLGR %s, R10\n", src)
100 }
101