1
0
mirror of https://github.com/golang/go synced 2024-11-22 03:34:40 -07:00

cmd/compile,cmd/internal/obj/riscv: always provide ANDN, ORN and XNOR for riscv64

The ANDN, ORN and XNOR RISC-V Zbb extension instructions are easily
synthesised. Make them always available by adding support to the
riscv64 assembler so that we either emit two instruction sequences,
or a single instruction, when permitted by the GORISCV64 profile.
This means that these instructions can be used unconditionally,
simplifying compiler rewrite rules, codegen tests and manually
written assembly.

Around 180 instructions are removed from the Go binary on riscv64
when built with rva22u64.

Change-Id: Ib2d90f2593a306530dc0ed08a981acde4d01be20
Reviewed-on: https://go-review.googlesource.com/c/go/+/611895
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Meng Zhuo <mengzhuo1203@gmail.com>
Reviewed-by: Tim King <taking@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
Joel Sing 2024-09-10 01:04:51 +10:00
parent 301499ff7b
commit 0ee5d20b1f
8 changed files with 188 additions and 21 deletions

View File

@ -361,8 +361,8 @@ start:
SLLIUW $1, X18, X19 // 9b191908
// 1.2: Basic Bit Manipulation (Zbb)
ANDN X19, X20, X21 // b37a3a41
ANDN X19, X20 // 337a3a41
ANDN X19, X20, X21 // b37a3a41 or 93caf9ffb37a5a01
ANDN X19, X20 // 337a3a41 or 93cff9ff337afa01
CLZ X20, X21 // 931a0a60
CLZW X21, X22 // 1b9b0a60
CPOP X22, X23 // 931b2b60
@ -377,12 +377,12 @@ start:
MIN X29, X30 // 334fdf0b
MINU X30, X5, X6 // 33d3e20b
MINU X30, X5 // b3d2e20b
ORN X6, X7, X8 // 33e46340
ORN X6, X7 // b3e36340
ORN X6, X7, X8 // 33e46340 or 1344f3ff33e48300
ORN X6, X7 // b3e36340 or 934ff3ffb3e3f301
SEXTB X16, X17 // 93184860
SEXTH X17, X18 // 13995860
XNOR X18, X19, X20 // 33ca2941
XNOR X18, X19 // b3c92941
XNOR X18, X19, X20 // 33ca2941 or 33ca2901134afaff
XNOR X18, X19 // b3c92941 or b3c9290193c9f9ff
ZEXTH X19, X20 // 3bca0908
// 1.3: Bitwise Rotation (Zbb)

View File

@ -278,7 +278,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.From.Reg = rs
p.To.Type = obj.TYPE_REG
p.To.Reg = rd
case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND,
case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XNOR, ssa.OpRISCV64XOR,
ssa.OpRISCV64OR, ssa.OpRISCV64ORN, ssa.OpRISCV64AND, ssa.OpRISCV64ANDN,
ssa.OpRISCV64SLL, ssa.OpRISCV64SLLW, ssa.OpRISCV64SRA, ssa.OpRISCV64SRAW, ssa.OpRISCV64SRL, ssa.OpRISCV64SRLW,
ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH,
ssa.OpRISCV64MULHU, ssa.OpRISCV64DIV, ssa.OpRISCV64DIVU, ssa.OpRISCV64DIVW,

View File

@ -62,7 +62,6 @@
(Com(64|32|16|8) ...) => (NOT ...)
(Sqrt ...) => (FSQRTD ...)
(Sqrt32 ...) => (FSQRTS ...)

View File

@ -226,19 +226,22 @@ func init() {
{name: "SH3ADD", argLength: 2, reg: gp21, asm: "SH3ADD"}, // arg0 << 3 + arg1
// Bitwise ops
{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
{name: "ANDI", argLength: 1, reg: gp11, asm: "ANDI", aux: "Int64"}, // arg0 & auxint
{name: "NOT", argLength: 1, reg: gp11, asm: "NOT"}, // ^arg0
{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1
{name: "ORI", argLength: 1, reg: gp11, asm: "ORI", aux: "Int64"}, // arg0 | auxint
{name: "ROL", argLength: 2, reg: gp21, asm: "ROL"}, // rotate left arg0 by (arg1 & 63)
{name: "ROLW", argLength: 2, reg: gp21, asm: "ROLW"}, // rotate left least significant word of arg0 by (arg1 & 31), sign extended
{name: "ROR", argLength: 2, reg: gp21, asm: "ROR"}, // rotate right arg0 by (arg1 & 63)
{name: "RORI", argLength: 1, reg: gp11, asm: "RORI", aux: "Int64"}, // rotate right arg0 by auxint, shift amount 0-63
{name: "RORIW", argLength: 1, reg: gp11, asm: "RORIW", aux: "Int64"}, // rotate right least significant word of arg0 by auxint, shift amount 0-31, sign extended
{name: "RORW", argLength: 2, reg: gp21, asm: "RORW"}, // rotate right least significant word of arg0 by (arg1 & 31), sign extended
{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true}, // arg0 ^ arg1
{name: "XORI", argLength: 1, reg: gp11, asm: "XORI", aux: "Int64"}, // arg0 ^ auxint
{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // ^arg0 & arg1
{name: "ANDI", argLength: 1, reg: gp11, asm: "ANDI", aux: "Int64"}, // arg0 & auxint
{name: "NOT", argLength: 1, reg: gp11, asm: "NOT"}, // ^arg0
{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1
{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // ^arg0 | arg1
{name: "ORI", argLength: 1, reg: gp11, asm: "ORI", aux: "Int64"}, // arg0 | auxint
{name: "ROL", argLength: 2, reg: gp21, asm: "ROL"}, // rotate left arg0 by (arg1 & 63)
{name: "ROLW", argLength: 2, reg: gp21, asm: "ROLW"}, // rotate left least significant word of arg0 by (arg1 & 31), sign extended
{name: "ROR", argLength: 2, reg: gp21, asm: "ROR"}, // rotate right arg0 by (arg1 & 63)
{name: "RORI", argLength: 1, reg: gp11, asm: "RORI", aux: "Int64"}, // rotate right arg0 by auxint, shift amount 0-63
{name: "RORIW", argLength: 1, reg: gp11, asm: "RORIW", aux: "Int64"}, // rotate right least significant word of arg0 by auxint, shift amount 0-31, sign extended
{name: "RORW", argLength: 2, reg: gp21, asm: "RORW"}, // rotate right least significant word of arg0 by (arg1 & 31), sign extended
{name: "XNOR", argLength: 2, reg: gp21, asm: "XNOR", commutative: true}, // ^(arg0 ^ arg1)
{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true}, // arg0 ^ arg1
{name: "XORI", argLength: 1, reg: gp11, asm: "XORI", aux: "Int64"}, // arg0 ^ auxint
// Minimum and maximum
{name: "MIN", argLength: 2, reg: gp21, asm: "MIN", commutative: true}, // min(arg0,arg1), signed

View File

@ -2,6 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Combine bitwise operation and bitwise inversion.
(AND x (NOT y)) => (ANDN x y)
(OR x (NOT y)) => (ORN x y)
(XOR x (NOT y)) => (XNOR x y)
(NOT (XOR x y)) => (XNOR x y)
// Fold constant shift with extension.
(SRAI [c] (MOVBreg x)) && c < 8 => (SRAI [56+c] (SLLI <typ.Int64> [56] x))
(SRAI [c] (MOVHreg x)) && c < 16 => (SRAI [48+c] (SLLI <typ.Int64> [48] x))

View File

@ -2425,9 +2425,11 @@ const (
OpRISCV64SH2ADD
OpRISCV64SH3ADD
OpRISCV64AND
OpRISCV64ANDN
OpRISCV64ANDI
OpRISCV64NOT
OpRISCV64OR
OpRISCV64ORN
OpRISCV64ORI
OpRISCV64ROL
OpRISCV64ROLW
@ -2435,6 +2437,7 @@ const (
OpRISCV64RORI
OpRISCV64RORIW
OpRISCV64RORW
OpRISCV64XNOR
OpRISCV64XOR
OpRISCV64XORI
OpRISCV64MIN
@ -32683,6 +32686,20 @@ var opcodeTable = [...]opInfo{
},
},
},
{
name: "ANDN",
argLen: 2,
asm: riscv.AANDN,
reg: regInfo{
inputs: []inputInfo{
{0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
{1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
{
name: "ANDI",
auxType: auxInt64,
@ -32725,6 +32742,20 @@ var opcodeTable = [...]opInfo{
},
},
},
{
name: "ORN",
argLen: 2,
asm: riscv.AORN,
reg: regInfo{
inputs: []inputInfo{
{0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
{1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
{
name: "ORI",
auxType: auxInt64,
@ -32823,6 +32854,21 @@ var opcodeTable = [...]opInfo{
},
},
},
{
name: "XNOR",
argLen: 2,
commutative: true,
asm: riscv.AXNOR,
reg: regInfo{
inputs: []inputInfo{
{0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
{1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
{
name: "XOR",
argLen: 2,

View File

@ -4,12 +4,76 @@ package ssa
func rewriteValueRISCV64latelower(v *Value) bool {
switch v.Op {
case OpRISCV64AND:
return rewriteValueRISCV64latelower_OpRISCV64AND(v)
case OpRISCV64NOT:
return rewriteValueRISCV64latelower_OpRISCV64NOT(v)
case OpRISCV64OR:
return rewriteValueRISCV64latelower_OpRISCV64OR(v)
case OpRISCV64SLLI:
return rewriteValueRISCV64latelower_OpRISCV64SLLI(v)
case OpRISCV64SRAI:
return rewriteValueRISCV64latelower_OpRISCV64SRAI(v)
case OpRISCV64SRLI:
return rewriteValueRISCV64latelower_OpRISCV64SRLI(v)
case OpRISCV64XOR:
return rewriteValueRISCV64latelower_OpRISCV64XOR(v)
}
return false
}
func rewriteValueRISCV64latelower_OpRISCV64AND(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (AND x (NOT y))
// result: (ANDN x y)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0
if v_1.Op != OpRISCV64NOT {
continue
}
y := v_1.Args[0]
v.reset(OpRISCV64ANDN)
v.AddArg2(x, y)
return true
}
break
}
return false
}
func rewriteValueRISCV64latelower_OpRISCV64NOT(v *Value) bool {
v_0 := v.Args[0]
// match: (NOT (XOR x y))
// result: (XNOR x y)
for {
if v_0.Op != OpRISCV64XOR {
break
}
y := v_0.Args[1]
x := v_0.Args[0]
v.reset(OpRISCV64XNOR)
v.AddArg2(x, y)
return true
}
return false
}
func rewriteValueRISCV64latelower_OpRISCV64OR(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (OR x (NOT y))
// result: (ORN x y)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0
if v_1.Op != OpRISCV64NOT {
continue
}
y := v_1.Args[0]
v.reset(OpRISCV64ORN)
v.AddArg2(x, y)
return true
}
break
}
return false
}
@ -241,6 +305,26 @@ func rewriteValueRISCV64latelower_OpRISCV64SRLI(v *Value) bool {
}
return false
}
func rewriteValueRISCV64latelower_OpRISCV64XOR(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (XOR x (NOT y))
// result: (XNOR x y)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0
if v_1.Op != OpRISCV64NOT {
continue
}
y := v_1.Args[0]
v.reset(OpRISCV64XNOR)
v.AddArg2(x, y)
return true
}
break
}
return false
}
func rewriteBlockRISCV64latelower(b *Block) bool {
return false
}

View File

@ -2535,6 +2535,34 @@ func instructionsForProg(p *obj.Prog) []*instruction {
case AORCB, AREV8:
ins.rd, ins.rs1, ins.rs2 = uint32(p.To.Reg), uint32(p.From.Reg), obj.REG_NONE
case AANDN, AORN:
if buildcfg.GORISCV64 >= 22 {
// ANDN and ORN instructions are supported natively.
break
}
// ANDN -> (AND (NOT x) y)
// ORN -> (OR (NOT x) y)
bitwiseOp, notReg := AAND, ins.rd
if ins.as == AORN {
bitwiseOp = AOR
}
if ins.rs1 == notReg {
notReg = REG_TMP
}
inss = []*instruction{
&instruction{as: AXORI, rs1: ins.rs2, rs2: obj.REG_NONE, rd: notReg, imm: -1},
&instruction{as: bitwiseOp, rs1: ins.rs1, rs2: notReg, rd: ins.rd},
}
case AXNOR:
if buildcfg.GORISCV64 >= 22 {
// XNOR instruction is supported natively.
break
}
// XNOR -> (NOT (XOR x y))
ins.as = AXOR
inss = append(inss, &instruction{as: AXORI, rs1: ins.rd, rs2: obj.REG_NONE, rd: ins.rd, imm: -1})
}
for _, ins := range inss {