Commit cf032380 authored by Michael Munday's avatar Michael Munday

cmd/compile: use numeric condition code masks on s390x

Prior to this CL conditional branches on s390x always used an
extended mnemonic such as BNE, BLT and so on to represent branch
instructions with different condition code masks. This CL adds
support for numeric condition code masks to the s390x SSA backend
so that we can encode the condition under which a Block's
successor is chosen as a field in that Block rather than in its
type.

This change will be useful as we come to add support for combined
compare-and-branch instructions. Rather than trying to add extended
mnemonics for every possible combination of mask and compare-and-
branch instruction we can instead use a single mnemonic for each
instruction.

Change-Id: Idb7458f187b50906877d683695c291dff5279553
Reviewed-on: https://go-review.googlesource.com/c/go/+/197178Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent 8506b7d4
...@@ -571,17 +571,15 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -571,17 +571,15 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
v.Fatalf("NOT/NOTW generated %s", v.LongString()) v.Fatalf("NOT/NOTW generated %s", v.LongString())
case ssa.OpS390XSumBytes2, ssa.OpS390XSumBytes4, ssa.OpS390XSumBytes8: case ssa.OpS390XSumBytes2, ssa.OpS390XSumBytes4, ssa.OpS390XSumBytes8:
v.Fatalf("SumBytes generated %s", v.LongString()) v.Fatalf("SumBytes generated %s", v.LongString())
case ssa.OpS390XMOVDEQ, ssa.OpS390XMOVDNE, case ssa.OpS390XLOCGR:
ssa.OpS390XMOVDLT, ssa.OpS390XMOVDLE,
ssa.OpS390XMOVDGT, ssa.OpS390XMOVDGE,
ssa.OpS390XMOVDGTnoinv, ssa.OpS390XMOVDGEnoinv:
r := v.Reg() r := v.Reg()
if r != v.Args[0].Reg() { if r != v.Args[0].Reg() {
v.Fatalf("input[0] and output not in same register %s", v.LongString()) v.Fatalf("input[0] and output not in same register %s", v.LongString())
} }
p := s.Prog(v.Op.Asm()) p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_CONST
p.From.Reg = v.Args[1].Reg() p.From.Offset = int64(v.Aux.(s390x.CCMask))
p.Reg = v.Args[1].Reg()
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = r p.To.Reg = r
case ssa.OpS390XFSQRT: case ssa.OpS390XFSQRT:
...@@ -817,19 +815,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -817,19 +815,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
} }
} }
var blockJump = [...]struct {
asm, invasm obj.As
}{
ssa.BlockS390XEQ: {s390x.ABEQ, s390x.ABNE},
ssa.BlockS390XNE: {s390x.ABNE, s390x.ABEQ},
ssa.BlockS390XLT: {s390x.ABLT, s390x.ABGE},
ssa.BlockS390XGE: {s390x.ABGE, s390x.ABLT},
ssa.BlockS390XLE: {s390x.ABLE, s390x.ABGT},
ssa.BlockS390XGT: {s390x.ABGT, s390x.ABLE},
ssa.BlockS390XGTF: {s390x.ABGT, s390x.ABLEU},
ssa.BlockS390XGEF: {s390x.ABGE, s390x.ABLTU},
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
switch b.Kind { switch b.Kind {
case ssa.BlockPlain: case ssa.BlockPlain:
...@@ -863,24 +848,20 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { ...@@ -863,24 +848,20 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN p.To.Name = obj.NAME_EXTERN
p.To.Sym = b.Aux.(*obj.LSym) p.To.Sym = b.Aux.(*obj.LSym)
case ssa.BlockS390XEQ, ssa.BlockS390XNE, case ssa.BlockS390XBRC:
ssa.BlockS390XLT, ssa.BlockS390XGE, succs := [...]*ssa.Block{b.Succs[0].Block(), b.Succs[1].Block()}
ssa.BlockS390XLE, ssa.BlockS390XGT, mask := b.Aux.(s390x.CCMask)
ssa.BlockS390XGEF, ssa.BlockS390XGTF: if next == succs[0] {
jmp := blockJump[b.Kind] succs[0], succs[1] = succs[1], succs[0]
switch next { mask = mask.Inverse()
case b.Succs[0].Block(): }
s.Br(jmp.invasm, b.Succs[1].Block()) // TODO: take into account Likely property for forward/backward
case b.Succs[1].Block(): // branches.
s.Br(jmp.asm, b.Succs[0].Block()) p := s.Br(s390x.ABRC, succs[0])
default: p.From.Type = obj.TYPE_CONST
if b.Likely != ssa.BranchUnlikely { p.From.Offset = int64(mask)
s.Br(jmp.asm, b.Succs[0].Block()) if next != succs[1] {
s.Br(s390x.ABR, b.Succs[1].Block()) s.Br(s390x.ABR, succs[1])
} else {
s.Br(jmp.invasm, b.Succs[1].Block())
s.Br(s390x.ABR, b.Succs[0].Block())
}
} }
default: default:
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
......
...@@ -150,7 +150,7 @@ func checkFunc(f *Func) { ...@@ -150,7 +150,7 @@ func checkFunc(f *Func) {
if !isExactFloat32(v.AuxFloat()) { if !isExactFloat32(v.AuxFloat()) {
f.Fatalf("value %v has an AuxInt value that is not an exact float32", v) f.Fatalf("value %v has an AuxInt value that is not an exact float32", v)
} }
case auxString, auxSym, auxTyp: case auxString, auxSym, auxTyp, auxArchSpecific:
canHaveAux = true canHaveAux = true
case auxSymOff, auxSymValAndOff, auxTypSize: case auxSymOff, auxSymValAndOff, auxTypSize:
canHaveAuxInt = true canHaveAuxInt = true
......
...@@ -354,18 +354,9 @@ func init() { ...@@ -354,18 +354,9 @@ func init() {
{name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0)
{name: "MOVDEQ", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDEQ"}, // extract == condition from arg0 // Conditional register-register moves.
{name: "MOVDNE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDNE"}, // extract != condition from arg0 // The aux for these values is an s390x.CCMask value representing the condition code mask.
{name: "MOVDLT", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDLT"}, // extract signed < condition from arg0 {name: "LOCGR", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "LOCGR", aux: "ArchSpecific"}, // load arg1 into arg0 if the condition code in arg2 matches a masked bit in aux.
{name: "MOVDLE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDLE"}, // extract signed <= condition from arg0
{name: "MOVDGT", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGT"}, // extract signed > condition from arg0
{name: "MOVDGE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGE"}, // extract signed >= condition from arg0
// Different rules for floating point conditions because
// any comparison involving a NaN is always false and thus
// the patterns for inverting conditions cannot be used.
{name: "MOVDGTnoinv", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGT"}, // extract floating > condition from arg0
{name: "MOVDGEnoinv", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGE"}, // extract floating >= condition from arg0
{name: "MOVBreg", argLength: 1, reg: gp11sp, asm: "MOVB", typ: "Int64"}, // sign extend arg0 from int8 to int64 {name: "MOVBreg", argLength: 1, reg: gp11sp, asm: "MOVB", typ: "Int64"}, // sign extend arg0 from int8 to int64
{name: "MOVBZreg", argLength: 1, reg: gp11sp, asm: "MOVBZ", typ: "UInt64"}, // zero extend arg0 from int8 to int64 {name: "MOVBZreg", argLength: 1, reg: gp11sp, asm: "MOVBZ", typ: "UInt64"}, // zero extend arg0 from int8 to int64
...@@ -717,14 +708,7 @@ func init() { ...@@ -717,14 +708,7 @@ func init() {
} }
var S390Xblocks = []blockData{ var S390Xblocks = []blockData{
{name: "EQ"}, {name: "BRC"}, // aux is condition code mask (s390x.CCMask)
{name: "NE"},
{name: "LT"},
{name: "LE"},
{name: "GT"},
{name: "GE"},
{name: "GTF"}, // FP comparison
{name: "GEF"}, // FP comparison
} }
archs = append(archs, arch{ archs = append(archs, arch{
...@@ -738,5 +722,8 @@ func init() { ...@@ -738,5 +722,8 @@ func init() {
fpregmask: fp, fpregmask: fp,
framepointerreg: -1, // not used framepointerreg: -1, // not used
linkreg: int8(num["R14"]), linkreg: int8(num["R14"]),
imports: []string{
"cmd/internal/obj/s390x",
},
}) })
} }
...@@ -41,6 +41,7 @@ type arch struct { ...@@ -41,6 +41,7 @@ type arch struct {
framepointerreg int8 framepointerreg int8
linkreg int8 linkreg int8
generic bool generic bool
imports []string
} }
type opData struct { type opData struct {
......
...@@ -554,11 +554,13 @@ func fprint(w io.Writer, n Node) { ...@@ -554,11 +554,13 @@ func fprint(w io.Writer, n Node) {
fmt.Fprintf(w, "// Code generated from gen/%s%s.rules; DO NOT EDIT.\n", n.arch.name, n.suffix) fmt.Fprintf(w, "// Code generated from gen/%s%s.rules; DO NOT EDIT.\n", n.arch.name, n.suffix)
fmt.Fprintf(w, "// generated with: cd gen; go run *.go\n") fmt.Fprintf(w, "// generated with: cd gen; go run *.go\n")
fmt.Fprintf(w, "\npackage ssa\n") fmt.Fprintf(w, "\npackage ssa\n")
for _, path := range []string{ for _, path := range append([]string{
"fmt", "math", "fmt",
"cmd/internal/obj", "cmd/internal/objabi", "math",
"cmd/internal/obj",
"cmd/internal/objabi",
"cmd/compile/internal/types", "cmd/compile/internal/types",
} { }, n.arch.imports...) {
fmt.Fprintf(w, "import %q\n", path) fmt.Fprintf(w, "import %q\n", path)
} }
for _, f := range n.list { for _, f := range n.list {
...@@ -1162,7 +1164,7 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxi ...@@ -1162,7 +1164,7 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxi
} }
if aux != "" { if aux != "" {
switch op.aux { switch op.aux {
case "String", "Sym", "SymOff", "SymValAndOff", "Typ", "TypSize", "CCop": case "String", "Sym", "SymOff", "SymValAndOff", "Typ", "TypSize", "CCop", "ArchSpecific":
default: default:
log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux) log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
} }
......
...@@ -37,7 +37,7 @@ func TestLoopConditionS390X(t *testing.T) { ...@@ -37,7 +37,7 @@ func TestLoopConditionS390X(t *testing.T) {
// MOVD $0, R2 // MOVD $0, R2
// MOVD $1, R3 // MOVD $1, R3
// CMP R0, R1 // CMP R0, R1
// MOVDLT R2, R3 // LOCGR $(8+2) R2, R3
// CMPW R2, $0 // CMPW R2, $0
// BNE done // BNE done
// ADD $3, R4 // ADD $3, R4
...@@ -76,12 +76,7 @@ func TestLoopConditionS390X(t *testing.T) { ...@@ -76,12 +76,7 @@ func TestLoopConditionS390X(t *testing.T) {
CheckFunc(fun.f) CheckFunc(fun.f)
checkOpcodeCounts(t, fun.f, map[Op]int{ checkOpcodeCounts(t, fun.f, map[Op]int{
OpS390XMOVDLT: 0, OpS390XLOCGR: 0,
OpS390XMOVDGT: 0,
OpS390XMOVDLE: 0,
OpS390XMOVDGE: 0,
OpS390XMOVDEQ: 0,
OpS390XMOVDNE: 0,
OpS390XCMP: 1, OpS390XCMP: 1,
OpS390XCMPWconst: 0, OpS390XCMPWconst: 0,
}) })
......
...@@ -83,6 +83,7 @@ const ( ...@@ -83,6 +83,7 @@ const (
auxTyp // aux is a type auxTyp // aux is a type
auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan) auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan)
auxArchSpecific // aux type is specific to a particular backend (see the relevant op for the actual type)
) )
// A SymEffect describes the effect that an SSA Value has on the variable // A SymEffect describes the effect that an SSA Value has on the variable
......
...@@ -111,14 +111,7 @@ const ( ...@@ -111,14 +111,7 @@ const (
BlockPPC64FGT BlockPPC64FGT
BlockPPC64FGE BlockPPC64FGE
BlockS390XEQ BlockS390XBRC
BlockS390XNE
BlockS390XLT
BlockS390XLE
BlockS390XGT
BlockS390XGE
BlockS390XGTF
BlockS390XGEF
BlockPlain BlockPlain
BlockIf BlockIf
...@@ -227,14 +220,7 @@ var blockString = [...]string{ ...@@ -227,14 +220,7 @@ var blockString = [...]string{
BlockPPC64FGT: "FGT", BlockPPC64FGT: "FGT",
BlockPPC64FGE: "FGE", BlockPPC64FGE: "FGE",
BlockS390XEQ: "EQ", BlockS390XBRC: "BRC",
BlockS390XNE: "NE",
BlockS390XLT: "LT",
BlockS390XLE: "LE",
BlockS390XGT: "GT",
BlockS390XGE: "GE",
BlockS390XGTF: "GTF",
BlockS390XGEF: "GEF",
BlockPlain: "Plain", BlockPlain: "Plain",
BlockIf: "If", BlockIf: "If",
...@@ -1967,14 +1953,7 @@ const ( ...@@ -1967,14 +1953,7 @@ const (
OpS390XNOT OpS390XNOT
OpS390XNOTW OpS390XNOTW
OpS390XFSQRT OpS390XFSQRT
OpS390XMOVDEQ OpS390XLOCGR
OpS390XMOVDNE
OpS390XMOVDLT
OpS390XMOVDLE
OpS390XMOVDGT
OpS390XMOVDGE
OpS390XMOVDGTnoinv
OpS390XMOVDGEnoinv
OpS390XMOVBreg OpS390XMOVBreg
OpS390XMOVBZreg OpS390XMOVBZreg
OpS390XMOVHreg OpS390XMOVHreg
...@@ -26453,115 +26432,11 @@ var opcodeTable = [...]opInfo{ ...@@ -26453,115 +26432,11 @@ var opcodeTable = [...]opInfo{
}, },
}, },
{ {
name: "MOVDEQ", name: "LOCGR",
auxType: auxArchSpecific,
argLen: 3, argLen: 3,
resultInArg0: true, resultInArg0: true,
asm: s390x.AMOVDEQ, asm: s390x.ALOCGR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
{1, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
outputs: []outputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
},
},
{
name: "MOVDNE",
argLen: 3,
resultInArg0: true,
asm: s390x.AMOVDNE,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
{1, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
outputs: []outputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
},
},
{
name: "MOVDLT",
argLen: 3,
resultInArg0: true,
asm: s390x.AMOVDLT,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
{1, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
outputs: []outputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
},
},
{
name: "MOVDLE",
argLen: 3,
resultInArg0: true,
asm: s390x.AMOVDLE,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
{1, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
outputs: []outputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
},
},
{
name: "MOVDGT",
argLen: 3,
resultInArg0: true,
asm: s390x.AMOVDGT,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
{1, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
outputs: []outputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
},
},
{
name: "MOVDGE",
argLen: 3,
resultInArg0: true,
asm: s390x.AMOVDGE,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
{1, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
outputs: []outputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
},
},
{
name: "MOVDGTnoinv",
argLen: 3,
resultInArg0: true,
asm: s390x.AMOVDGT,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
{1, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
outputs: []outputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
},
},
},
{
name: "MOVDGEnoinv",
argLen: 3,
resultInArg0: true,
asm: s390x.AMOVDGE,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 {0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
......
...@@ -179,7 +179,7 @@ func (v *Value) auxString() string { ...@@ -179,7 +179,7 @@ func (v *Value) auxString() string {
return fmt.Sprintf(" [%g]", v.AuxFloat()) return fmt.Sprintf(" [%g]", v.AuxFloat())
case auxString: case auxString:
return fmt.Sprintf(" {%q}", v.Aux) return fmt.Sprintf(" {%q}", v.Aux)
case auxSym, auxTyp: case auxSym, auxTyp, auxArchSpecific:
if v.Aux != nil { if v.Aux != nil {
return fmt.Sprintf(" {%v}", v.Aux) return fmt.Sprintf(" {%v}", v.Aux)
} }
......
...@@ -2639,35 +2639,35 @@ func (c *ctxtz) addcallreloc(sym *obj.LSym, add int64) *obj.Reloc { ...@@ -2639,35 +2639,35 @@ func (c *ctxtz) addcallreloc(sym *obj.LSym, add int64) *obj.Reloc {
return rel return rel
} }
func (c *ctxtz) branchMask(p *obj.Prog) uint32 { func (c *ctxtz) branchMask(p *obj.Prog) CCMask {
switch p.As { switch p.As {
case ABRC, ALOCR, ALOCGR, case ABRC, ALOCR, ALOCGR,
ACRJ, ACGRJ, ACIJ, ACGIJ, ACRJ, ACGRJ, ACIJ, ACGIJ,
ACLRJ, ACLGRJ, ACLIJ, ACLGIJ: ACLRJ, ACLGRJ, ACLIJ, ACLGIJ:
return uint32(p.From.Offset) return CCMask(p.From.Offset)
case ABEQ, ACMPBEQ, ACMPUBEQ, AMOVDEQ: case ABEQ, ACMPBEQ, ACMPUBEQ, AMOVDEQ:
return 0x8 return Equal
case ABGE, ACMPBGE, ACMPUBGE, AMOVDGE: case ABGE, ACMPBGE, ACMPUBGE, AMOVDGE:
return 0xA return GreaterOrEqual
case ABGT, ACMPBGT, ACMPUBGT, AMOVDGT: case ABGT, ACMPBGT, ACMPUBGT, AMOVDGT:
return 0x2 return Greater
case ABLE, ACMPBLE, ACMPUBLE, AMOVDLE: case ABLE, ACMPBLE, ACMPUBLE, AMOVDLE:
return 0xC return LessOrEqual
case ABLT, ACMPBLT, ACMPUBLT, AMOVDLT: case ABLT, ACMPBLT, ACMPUBLT, AMOVDLT:
return 0x4 return Less
case ABNE, ACMPBNE, ACMPUBNE, AMOVDNE: case ABNE, ACMPBNE, ACMPUBNE, AMOVDNE:
return 0x7 return NotEqual
case ABLEU: // LE or unordered case ABLEU: // LE or unordered
return 0xD return NotGreater
case ABLTU: // LT or unordered case ABLTU: // LT or unordered
return 0x5 return LessOrUnordered
case ABVC: case ABVC:
return 0x0 // needs extra instruction return Never // needs extra instruction
case ABVS: case ABVS:
return 0x1 // unordered return Unordered
} }
c.ctxt.Diag("unknown conditional branch %v", p.As) c.ctxt.Diag("unknown conditional branch %v", p.As)
return 0xF return Always
} }
func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
...@@ -3073,7 +3073,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3073,7 +3073,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
if p.As == ABCL || p.As == ABL { if p.As == ABCL || p.As == ABL {
zRR(op_BASR, uint32(REG_LR), uint32(r), asm) zRR(op_BASR, uint32(REG_LR), uint32(r), asm)
} else { } else {
zRR(op_BCR, 0xF, uint32(r), asm) zRR(op_BCR, uint32(Always), uint32(r), asm)
} }
case 16: // conditional branch case 16: // conditional branch
...@@ -3081,7 +3081,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3081,7 +3081,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
if p.Pcond != nil { if p.Pcond != nil {
v = int32((p.Pcond.Pc - p.Pc) >> 1) v = int32((p.Pcond.Pc - p.Pc) >> 1)
} }
mask := c.branchMask(p) mask := uint32(c.branchMask(p))
if p.To.Sym == nil && int32(int16(v)) == v { if p.To.Sym == nil && int32(int16(v)) == v {
zRI(op_BRC, mask, uint32(v), asm) zRI(op_BRC, mask, uint32(v), asm)
} else { } else {
...@@ -3092,14 +3092,14 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3092,14 +3092,14 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
} }
case 17: // move on condition case 17: // move on condition
m3 := c.branchMask(p) m3 := uint32(c.branchMask(p))
zRRF(op_LOCGR, m3, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm) zRRF(op_LOCGR, m3, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
case 18: // br/bl reg case 18: // br/bl reg
if p.As == ABL { if p.As == ABL {
zRR(op_BASR, uint32(REG_LR), uint32(p.To.Reg), asm) zRR(op_BASR, uint32(REG_LR), uint32(p.To.Reg), asm)
} else { } else {
zRR(op_BCR, 0xF, uint32(p.To.Reg), asm) zRR(op_BCR, uint32(Always), uint32(p.To.Reg), asm)
} }
case 19: // mov $sym+n(SB) reg case 19: // mov $sym+n(SB) reg
...@@ -3233,7 +3233,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3233,7 +3233,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
} }
case 25: // load on condition (register) case 25: // load on condition (register)
m3 := c.branchMask(p) m3 := uint32(c.branchMask(p))
var opcode uint32 var opcode uint32
switch p.As { switch p.As {
case ALOCR: case ALOCR:
...@@ -3448,7 +3448,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3448,7 +3448,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
zRRE(op_MLGR, uint32(p.To.Reg), uint32(p.From.Reg), asm) zRRE(op_MLGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
case 66: case 66:
zRR(op_BCR, 0, 0, asm) zRR(op_BCR, uint32(Never), 0, asm)
case 67: // fmov $0 freg case 67: // fmov $0 freg
var opcode uint32 var opcode uint32
...@@ -3634,7 +3634,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3634,7 +3634,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
} }
case 80: // sync case 80: // sync
zRR(op_BCR, 0xE, 0, asm) zRR(op_BCR, uint32(NotEqual), 0, asm)
case 81: // float to fixed and fixed to float moves (no conversion) case 81: // float to fixed and fixed to float moves (no conversion)
switch p.As { switch p.As {
...@@ -3830,7 +3830,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3830,7 +3830,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
if p.From.Type == obj.TYPE_CONST { if p.From.Type == obj.TYPE_CONST {
r1, r2 = p.Reg, p.RestArgs[0].Reg r1, r2 = p.Reg, p.RestArgs[0].Reg
} }
m3 := c.branchMask(p) m3 := uint32(c.branchMask(p))
var opcode uint32 var opcode uint32
switch p.As { switch p.As {
...@@ -3859,7 +3859,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3859,7 +3859,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
// the condition code. // the condition code.
m3 ^= 0xe // invert 3-bit mask m3 ^= 0xe // invert 3-bit mask
zRIE(_b, opcode, uint32(r1), uint32(r2), uint32(sizeRIE+sizeRIL)/2, 0, 0, m3, 0, asm) zRIE(_b, opcode, uint32(r1), uint32(r2), uint32(sizeRIE+sizeRIL)/2, 0, 0, m3, 0, asm)
zRIL(_c, op_BRCL, 0xf, uint32(v-sizeRIE/2), asm) zRIL(_c, op_BRCL, uint32(Always), uint32(v-sizeRIE/2), asm)
} else { } else {
zRIE(_b, opcode, uint32(r1), uint32(r2), uint32(v), 0, 0, m3, 0, asm) zRIE(_b, opcode, uint32(r1), uint32(r2), uint32(v), 0, 0, m3, 0, asm)
} }
...@@ -3875,7 +3875,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3875,7 +3875,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
if p.From.Type == obj.TYPE_CONST { if p.From.Type == obj.TYPE_CONST {
r1 = p.Reg r1 = p.Reg
} }
m3 := c.branchMask(p) m3 := uint32(c.branchMask(p))
var opcode uint32 var opcode uint32
switch p.As { switch p.As {
...@@ -3899,7 +3899,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3899,7 +3899,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
// the condition code. // the condition code.
m3 ^= 0xe // invert 3-bit mask m3 ^= 0xe // invert 3-bit mask
zRIE(_c, opcode, uint32(r1), m3, uint32(sizeRIE+sizeRIL)/2, 0, 0, 0, uint32(i2), asm) zRIE(_c, opcode, uint32(r1), m3, uint32(sizeRIE+sizeRIL)/2, 0, 0, 0, uint32(i2), asm)
zRIL(_c, op_BRCL, 0xf, uint32(v-sizeRIE/2), asm) zRIL(_c, op_BRCL, uint32(Always), uint32(v-sizeRIE/2), asm)
} else { } else {
zRIE(_c, opcode, uint32(r1), m3, uint32(v), 0, 0, 0, uint32(i2), asm) zRIE(_c, opcode, uint32(r1), m3, uint32(v), 0, 0, 0, uint32(i2), asm)
} }
......
// Copyright 2019 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 s390x
import (
"fmt"
)
// CCMask represents a 4-bit condition code mask. Bits that
// are not part of the mask should be 0.
//
// Condition code masks represent the 4 possible values of
// the 2-bit condition code as individual bits. Since IBM Z
// is a big-endian platform bits are numbered from left to
// right. The lowest value, 0, is represented by 8 (0b1000)
// and the highest value, 3, is represented by 1 (0b0001).
//
// Note that condition code values have different semantics
// depending on the instruction that set the condition code.
// The names given here assume that the condition code was
// set by an integer or floating point comparison. Other
// instructions may use these same codes to indicate
// different results such as a carry or overflow.
type CCMask uint8
const (
Never CCMask = 0 // no-op
// 1-bit masks
Equal CCMask = 1 << 3
Less CCMask = 1 << 2
Greater CCMask = 1 << 1
Unordered CCMask = 1 << 0
// 2-bit masks
EqualOrUnordered CCMask = Equal | Unordered // not less and not greater
LessOrEqual CCMask = Less | Equal // ordered and not greater
LessOrGreater CCMask = Less | Greater // ordered and not equal
LessOrUnordered CCMask = Less | Unordered // not greater and not equal
GreaterOrEqual CCMask = Greater | Equal // ordered and not less
GreaterOrUnordered CCMask = Greater | Unordered // not less and not equal
// 3-bit masks
NotEqual CCMask = Always ^ Equal
NotLess CCMask = Always ^ Less
NotGreater CCMask = Always ^ Greater
NotUnordered CCMask = Always ^ Unordered
// 4-bit mask
Always CCMask = Equal | Less | Greater | Unordered
)
// Inverse returns the complement of the condition code mask.
func (c CCMask) Inverse() CCMask {
return c ^ Always
}
// ReverseComparison swaps the bits at 0b0100 and 0b0010 in the mask,
// reversing the behavior of greater than and less than conditions.
func (c CCMask) ReverseComparison() CCMask {
r := c & EqualOrUnordered
if c&Less != 0 {
r |= Greater
}
if c&Greater != 0 {
r |= Less
}
return r
}
func (c CCMask) String() string {
switch c {
// 0-bit mask
case Never:
return "Never"
// 1-bit masks
case Equal:
return "Equal"
case Less:
return "Less"
case Greater:
return "Greater"
case Unordered:
return "Unordered"
// 2-bit masks
case EqualOrUnordered:
return "EqualOrUnordered"
case LessOrEqual:
return "LessOrEqual"
case LessOrGreater:
return "LessOrGreater"
case LessOrUnordered:
return "LessOrUnordered"
case GreaterOrEqual:
return "GreaterOrEqual"
case GreaterOrUnordered:
return "GreaterOrUnordered"
// 3-bit masks
case NotEqual:
return "NotEqual"
case NotLess:
return "NotLess"
case NotGreater:
return "NotGreater"
case NotUnordered:
return "NotUnordered"
// 4-bit mask
case Always:
return "Always"
}
// invalid
return fmt.Sprintf("Invalid (%#x)", c)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment