go/src/cmd/asm/internal/arch/s390x.go
Michael Munday 85bbabd9c4 cmd/asm: add s390x support
s390x doesn't introduce any new assembly syntax. There are a few
instructions which require the operands to be reordered, notably
the storage-storage instructions that put the length into From3 so
that the memory operands can be put into From and To.

The assembly test currently covers a subset of instructions but
tries to hit edge cases as much as possible. Unlike the other ports
it can be linked as an executable to make disassembling it easy.
It would be nice to autogenerate it at some point in the future.

Change-Id: I7615ac6ecf239e3f347fad9ae1f8eede91742859
Reviewed-on: https://go-review.googlesource.com/20934
Run-TryBot: Rob Pike <r@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-03-28 20:13:17 +00:00

140 lines
2.9 KiB
Go

// Copyright 2016 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.
// This file encapsulates some of the odd characteristics of the
// s390x instruction set, to minimize its interaction
// with the core of the assembler.
package arch
import (
"cmd/internal/obj"
"cmd/internal/obj/s390x"
)
func jumpS390x(word string) bool {
switch word {
case "BC",
"BCL",
"BEQ",
"BGE",
"BGT",
"BL",
"BLE",
"BLT",
"BNE",
"BR",
"BVC",
"BVS",
"CMPBEQ",
"CMPBGE",
"CMPBGT",
"CMPBLE",
"CMPBLT",
"CMPBNE",
"CMPUBEQ",
"CMPUBGE",
"CMPUBGT",
"CMPUBLE",
"CMPUBLT",
"CMPUBNE",
"CALL",
"JMP":
return true
}
return false
}
// IsS390xRLD reports whether the op (as defined by an s390x.A* constant) is
// one of the RLD-like instructions that require special handling.
// The FMADD-like instructions behave similarly.
func IsS390xRLD(op obj.As) bool {
switch op {
case s390x.AFMADD,
s390x.AFMADDS,
s390x.AFMSUB,
s390x.AFMSUBS,
s390x.AFNMADD,
s390x.AFNMADDS,
s390x.AFNMSUB,
s390x.AFNMSUBS:
return true
}
return false
}
// IsS390xCMP reports whether the op (as defined by an s390x.A* constant) is
// one of the CMP instructions that require special handling.
func IsS390xCMP(op obj.As) bool {
switch op {
case s390x.ACMP, s390x.ACMPU, s390x.ACMPW, s390x.ACMPWU:
return true
}
return false
}
// IsS390xNEG reports whether the op (as defined by an s390x.A* constant) is
// one of the NEG-like instructions that require special handling.
func IsS390xNEG(op obj.As) bool {
switch op {
case s390x.AADDME,
s390x.AADDZE,
s390x.ANEG,
s390x.ASUBME,
s390x.ASUBZE:
return true
}
return false
}
// IsS390xWithLength reports whether the op (as defined by an s390x.A* constant)
// refers to an instruction which takes a length as its first argument.
func IsS390xWithLength(op obj.As) bool {
switch op {
case s390x.AMVC, s390x.ACLC, s390x.AXC, s390x.AOC, s390x.ANC:
return true
case s390x.AVLL, s390x.AVSTL:
return true
}
return false
}
// IsS390xWithIndex reports whether the op (as defined by an s390x.A* constant)
// refers to an instruction which takes an index as its first argument.
func IsS390xWithIndex(op obj.As) bool {
switch op {
case s390x.AVSCEG, s390x.AVSCEF, s390x.AVGEG, s390x.AVGEF:
return true
case s390x.AVGMG, s390x.AVGMF, s390x.AVGMH, s390x.AVGMB:
return true
case s390x.AVLEIG, s390x.AVLEIF, s390x.AVLEIH, s390x.AVLEIB:
return true
case s390x.AVPDI:
return true
}
return false
}
func s390xRegisterNumber(name string, n int16) (int16, bool) {
switch name {
case "AR":
if 0 <= n && n <= 15 {
return s390x.REG_AR0 + n, true
}
case "F":
if 0 <= n && n <= 15 {
return s390x.REG_F0 + n, true
}
case "R":
if 0 <= n && n <= 15 {
return s390x.REG_R0 + n, true
}
case "V":
if 0 <= n && n <= 31 {
return s390x.REG_V0 + n, true
}
}
return 0, false
}