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