| // Copyright 2025 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. |
| |
| package asmgen |
| |
| var ArchS390X = &Arch{ |
| Name: "s390x", |
| WordBits: 64, |
| WordBytes: 8, |
| CarrySafeLoop: true, |
| |
| regs: []string{ |
| // R0 is 0 by convention in this code (see setup). |
| // R10 is the assembler/linker temporary. |
| // R11 is a second assembler/linker temporary, for wide multiply. |
| // We allow allocating R10 and R11 so that we can use them as |
| // direct multiplication targets while tracking whether they're in use. |
| // R13 is g. |
| // R14 is LR. |
| // R15 is SP. |
| "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", |
| "R10", "R11", "R12", |
| }, |
| reg0: "R0", |
| regTmp: "R10", |
| setup: s390xSetup, |
| maxColumns: 2, |
| op3: s390xOp3, |
| hint: s390xHint, |
| |
| // Instruction reference: chapter 7 of |
| // https://www.ibm.com/docs/en/SSQ2R2_15.0.0/com.ibm.tpf.toolkit.hlasm.doc/dz9zr006.pdf |
| |
| mov: "MOVD", |
| adds: "ADDC", // ADD is an alias for ADDC, sets carry |
| adcs: "ADDE", |
| subs: "SUBC", // SUB is an alias for SUBC, sets carry |
| sbcs: "SUBE", |
| mulWideF: s390MulWide, |
| lsh: "SLD", |
| rsh: "SRD", |
| and: "AND", |
| or: "OR", |
| xor: "XOR", |
| neg: "NEG", |
| lea: "LAY", // LAY because LA only accepts positive offsets |
| |
| jmpZero: "CMPBEQ %s, $0, %s", |
| jmpNonZero: "CMPBNE %s, $0, %s", |
| } |
| |
| func s390xSetup(f *Func) { |
| a := f.Asm |
| if f.Name == "addVV" || f.Name == "subVV" { |
| // S390x, unlike every other system, has vector instructions |
| // that can propagate carry bits during parallel adds (VACC). |
| // Instead of trying to generate that for this one system, |
| // jump to the hand-written code in arithvec_s390x.s. |
| a.Printf("\tMOVB ·hasVX(SB), R1\n") |
| a.Printf("\tCMPBEQ R1, $0, novec\n") |
| a.Printf("\tJMP ·%svec(SB)\n", f.Name) |
| a.Printf("novec:\n") |
| } |
| a.Printf("\tMOVD $0, R0\n") |
| } |
| |
| func s390xOp3(name string) bool { |
| if name == "AND" { // AND with immediate only takes imm, reg; not imm, reg, reg. |
| return false |
| } |
| return true |
| } |
| |
| func s390xHint(_ *Asm, h Hint) string { |
| switch h { |
| case HintMulSrc: |
| return "R11" |
| case HintMulHi: |
| return "R10" |
| } |
| return "" |
| } |
| |
| func s390MulWide(a *Asm, src1, src2, dstlo, dsthi Reg) { |
| if src1.name != "R11" && src2.name != "R11" { |
| a.Fatalf("mulWide src1 or src2 must be R11") |
| } |
| if dstlo.name != "R11" { |
| a.Fatalf("mulWide dstlo must be R11") |
| } |
| if dsthi.name != "R10" { |
| a.Fatalf("mulWide dsthi must be R10") |
| } |
| src := src1 |
| if src.name == "R11" { |
| src = src2 |
| } |
| a.Printf("\tMLGR %s, R10\n", src) |
| } |