Skip to content

Commit 0ee5d20

Browse files
committed
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 <[email protected]> Reviewed-by: Meng Zhuo <[email protected]> Reviewed-by: Tim King <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 301499f commit 0ee5d20

File tree

8 files changed

+188
-21
lines changed

8 files changed

+188
-21
lines changed

src/cmd/asm/internal/asm/testdata/riscv64.s

+6-6
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,8 @@ start:
361361
SLLIUW $1, X18, X19 // 9b191908
362362

363363
// 1.2: Basic Bit Manipulation (Zbb)
364-
ANDN X19, X20, X21 // b37a3a41
365-
ANDN X19, X20 // 337a3a41
364+
ANDN X19, X20, X21 // b37a3a41 or 93caf9ffb37a5a01
365+
ANDN X19, X20 // 337a3a41 or 93cff9ff337afa01
366366
CLZ X20, X21 // 931a0a60
367367
CLZW X21, X22 // 1b9b0a60
368368
CPOP X22, X23 // 931b2b60
@@ -377,12 +377,12 @@ start:
377377
MIN X29, X30 // 334fdf0b
378378
MINU X30, X5, X6 // 33d3e20b
379379
MINU X30, X5 // b3d2e20b
380-
ORN X6, X7, X8 // 33e46340
381-
ORN X6, X7 // b3e36340
380+
ORN X6, X7, X8 // 33e46340 or 1344f3ff33e48300
381+
ORN X6, X7 // b3e36340 or 934ff3ffb3e3f301
382382
SEXTB X16, X17 // 93184860
383383
SEXTH X17, X18 // 13995860
384-
XNOR X18, X19, X20 // 33ca2941
385-
XNOR X18, X19 // b3c92941
384+
XNOR X18, X19, X20 // 33ca2941 or 33ca2901134afaff
385+
XNOR X18, X19 // b3c92941 or b3c9290193c9f9ff
386386
ZEXTH X19, X20 // 3bca0908
387387

388388
// 1.3: Bitwise Rotation (Zbb)

src/cmd/compile/internal/riscv64/ssa.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
278278
p.From.Reg = rs
279279
p.To.Type = obj.TYPE_REG
280280
p.To.Reg = rd
281-
case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND,
281+
case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XNOR, ssa.OpRISCV64XOR,
282+
ssa.OpRISCV64OR, ssa.OpRISCV64ORN, ssa.OpRISCV64AND, ssa.OpRISCV64ANDN,
282283
ssa.OpRISCV64SLL, ssa.OpRISCV64SLLW, ssa.OpRISCV64SRA, ssa.OpRISCV64SRAW, ssa.OpRISCV64SRL, ssa.OpRISCV64SRLW,
283284
ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH,
284285
ssa.OpRISCV64MULHU, ssa.OpRISCV64DIV, ssa.OpRISCV64DIVU, ssa.OpRISCV64DIVW,

src/cmd/compile/internal/ssa/_gen/RISCV64.rules

-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262

6363
(Com(64|32|16|8) ...) => (NOT ...)
6464

65-
6665
(Sqrt ...) => (FSQRTD ...)
6766
(Sqrt32 ...) => (FSQRTS ...)
6867

src/cmd/compile/internal/ssa/_gen/RISCV64Ops.go

+16-13
Original file line numberDiff line numberDiff line change
@@ -226,19 +226,22 @@ func init() {
226226
{name: "SH3ADD", argLength: 2, reg: gp21, asm: "SH3ADD"}, // arg0 << 3 + arg1
227227

228228
// Bitwise ops
229-
{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
230-
{name: "ANDI", argLength: 1, reg: gp11, asm: "ANDI", aux: "Int64"}, // arg0 & auxint
231-
{name: "NOT", argLength: 1, reg: gp11, asm: "NOT"}, // ^arg0
232-
{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1
233-
{name: "ORI", argLength: 1, reg: gp11, asm: "ORI", aux: "Int64"}, // arg0 | auxint
234-
{name: "ROL", argLength: 2, reg: gp21, asm: "ROL"}, // rotate left arg0 by (arg1 & 63)
235-
{name: "ROLW", argLength: 2, reg: gp21, asm: "ROLW"}, // rotate left least significant word of arg0 by (arg1 & 31), sign extended
236-
{name: "ROR", argLength: 2, reg: gp21, asm: "ROR"}, // rotate right arg0 by (arg1 & 63)
237-
{name: "RORI", argLength: 1, reg: gp11, asm: "RORI", aux: "Int64"}, // rotate right arg0 by auxint, shift amount 0-63
238-
{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
239-
{name: "RORW", argLength: 2, reg: gp21, asm: "RORW"}, // rotate right least significant word of arg0 by (arg1 & 31), sign extended
240-
{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true}, // arg0 ^ arg1
241-
{name: "XORI", argLength: 1, reg: gp11, asm: "XORI", aux: "Int64"}, // arg0 ^ auxint
229+
{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
230+
{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // ^arg0 & arg1
231+
{name: "ANDI", argLength: 1, reg: gp11, asm: "ANDI", aux: "Int64"}, // arg0 & auxint
232+
{name: "NOT", argLength: 1, reg: gp11, asm: "NOT"}, // ^arg0
233+
{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1
234+
{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // ^arg0 | arg1
235+
{name: "ORI", argLength: 1, reg: gp11, asm: "ORI", aux: "Int64"}, // arg0 | auxint
236+
{name: "ROL", argLength: 2, reg: gp21, asm: "ROL"}, // rotate left arg0 by (arg1 & 63)
237+
{name: "ROLW", argLength: 2, reg: gp21, asm: "ROLW"}, // rotate left least significant word of arg0 by (arg1 & 31), sign extended
238+
{name: "ROR", argLength: 2, reg: gp21, asm: "ROR"}, // rotate right arg0 by (arg1 & 63)
239+
{name: "RORI", argLength: 1, reg: gp11, asm: "RORI", aux: "Int64"}, // rotate right arg0 by auxint, shift amount 0-63
240+
{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
241+
{name: "RORW", argLength: 2, reg: gp21, asm: "RORW"}, // rotate right least significant word of arg0 by (arg1 & 31), sign extended
242+
{name: "XNOR", argLength: 2, reg: gp21, asm: "XNOR", commutative: true}, // ^(arg0 ^ arg1)
243+
{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true}, // arg0 ^ arg1
244+
{name: "XORI", argLength: 1, reg: gp11, asm: "XORI", aux: "Int64"}, // arg0 ^ auxint
242245

243246
// Minimum and maximum
244247
{name: "MIN", argLength: 2, reg: gp21, asm: "MIN", commutative: true}, // min(arg0,arg1), signed

src/cmd/compile/internal/ssa/_gen/RISCV64latelower.rules

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
// Combine bitwise operation and bitwise inversion.
6+
(AND x (NOT y)) => (ANDN x y)
7+
(OR x (NOT y)) => (ORN x y)
8+
(XOR x (NOT y)) => (XNOR x y)
9+
(NOT (XOR x y)) => (XNOR x y)
10+
511
// Fold constant shift with extension.
612
(SRAI [c] (MOVBreg x)) && c < 8 => (SRAI [56+c] (SLLI <typ.Int64> [56] x))
713
(SRAI [c] (MOVHreg x)) && c < 16 => (SRAI [48+c] (SLLI <typ.Int64> [48] x))

src/cmd/compile/internal/ssa/opGen.go

+46
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/compile/internal/ssa/rewriteRISCV64latelower.go

+84
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/internal/obj/riscv/obj.go

+28
Original file line numberDiff line numberDiff line change
@@ -2535,6 +2535,34 @@ func instructionsForProg(p *obj.Prog) []*instruction {
25352535

25362536
case AORCB, AREV8:
25372537
ins.rd, ins.rs1, ins.rs2 = uint32(p.To.Reg), uint32(p.From.Reg), obj.REG_NONE
2538+
2539+
case AANDN, AORN:
2540+
if buildcfg.GORISCV64 >= 22 {
2541+
// ANDN and ORN instructions are supported natively.
2542+
break
2543+
}
2544+
// ANDN -> (AND (NOT x) y)
2545+
// ORN -> (OR (NOT x) y)
2546+
bitwiseOp, notReg := AAND, ins.rd
2547+
if ins.as == AORN {
2548+
bitwiseOp = AOR
2549+
}
2550+
if ins.rs1 == notReg {
2551+
notReg = REG_TMP
2552+
}
2553+
inss = []*instruction{
2554+
&instruction{as: AXORI, rs1: ins.rs2, rs2: obj.REG_NONE, rd: notReg, imm: -1},
2555+
&instruction{as: bitwiseOp, rs1: ins.rs1, rs2: notReg, rd: ins.rd},
2556+
}
2557+
2558+
case AXNOR:
2559+
if buildcfg.GORISCV64 >= 22 {
2560+
// XNOR instruction is supported natively.
2561+
break
2562+
}
2563+
// XNOR -> (NOT (XOR x y))
2564+
ins.as = AXOR
2565+
inss = append(inss, &instruction{as: AXORI, rs1: ins.rd, rs2: obj.REG_NONE, rd: ins.rd, imm: -1})
25382566
}
25392567

25402568
for _, ins := range inss {

0 commit comments

Comments
 (0)