Skip to content

Commit 8abd4ac

Browse files
committed
cmd/compile/internal: eliminate special branch psuedo-ops
The behavior of the RISCV BRANCH block is not safe. It reaches into the control value and uses the registers of the control's args, rather than the control value itself. regalloc ensures that the control value is in a register, but it does *not* do so for the control's arguments. It does not know that BRANCH uses them and thus may not consider them live. The reason for this weird BRANCH behavior is that RISC-V branches are binary instructions, comparing two operands to decide which branch to take, but we only have one control value, not two. The best way to solve this would be to teach the compiler than some blocks need two control values. While that doesn't look too difficult to implement, it is a fairly large scale, intrusive change to the compiler. Maintaining these changes as upstream continues to change the compiler would become a painful maintainance burden. Instead, make the branches behave much more like other architectures, where the condition comparision is done in an instruction before the branch. We then generate a branch instruction that simply compares the condition with zero. Once we are merged upstream, we can come back and investigate generating better code by adding a second control value. Fixes golang#12 Change-Id: I926d7ea45973c88927d42e915eb68265e79eb345
1 parent 98556aa commit 8abd4ac

File tree

5 files changed

+20
-360
lines changed

5 files changed

+20
-360
lines changed

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

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
340340
p.From.Reg = v.Args[0].Reg()
341341
p.To.Type = obj.TYPE_REG
342342
p.To.Reg = v.Reg()
343-
case ssa.OpRISCVBEQ, ssa.OpRISCVBNE, ssa.OpRISCVBLT, ssa.OpRISCVBLTU, ssa.OpRISCVBGE, ssa.OpRISCVBGEU:
344-
// These are flag pseudo-ops used as control values for conditional branch blocks.
345-
// See the discussion in RISCVOps.
346-
// The actual conditional branch instruction will be issued in ssaGenBlock.
347343
case ssa.OpRISCVCALLstatic, ssa.OpRISCVCALLclosure, ssa.OpRISCVCALLdefer, ssa.OpRISCVCALLgo, ssa.OpRISCVCALLinter:
348344
if v.Op == ssa.OpRISCVCALLstatic && v.Aux.(*gc.Sym) == gc.Deferreturn.Sym {
349345
// Deferred calls will appear to be returning to
@@ -513,32 +509,13 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
513509
p.To.Type = obj.TYPE_MEM
514510
p.To.Name = obj.NAME_EXTERN
515511
p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
516-
case ssa.BlockRISCVBRANCH:
517-
// Conditional branch. The control value tells us what kind.
518-
v := b.Control
519-
520-
// The control value need not be in this block, as the code
521-
// below asserts. regalloc will ensure that it is in a register
522-
// at this point so we can use it.
523-
//
524-
// FIXME(prattmic): Remove this block. It is left for now for
525-
// easy debugging should the assertion above turn out to be
526-
// incorrect after all.
527-
if false {
528-
// Double-check that the value is exactly where we expect it.
529-
if v.Block != b {
530-
gc.Fatalf("control value in the wrong block %v, want %v: %v", v.Block, b, v.LongString())
531-
}
532-
if v != b.Values[len(b.Values)-1] {
533-
gc.Fatalf("badly scheduled control value for block %v: %v", b, v.LongString())
534-
}
535-
}
536-
537-
p := gc.Prog(v.Op.Asm())
512+
case ssa.BlockRISCVBNE:
513+
// Conditional branch if Control != 0.
514+
p := gc.Prog(riscv.ABNE)
538515
p.To.Type = obj.TYPE_BRANCH
539-
p.Reg = v.Args[1].Reg()
516+
p.Reg = b.Control.Reg()
540517
p.From.Type = obj.TYPE_REG
541-
p.From.Reg = v.Args[0].Reg()
518+
p.From.Reg = riscv.REG_ZERO
542519
switch next {
543520
case b.Succs[0].Block():
544521
p.As = riscv.InvertBranch(p.As)

src/cmd/compile/internal/ssa/gen/RISCV.rules

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -422,22 +422,14 @@
422422
(Addr {sym} base) -> (MOVaddr {sym} base)
423423

424424
// Conditional branches
425-
(If (Eq64 x y) yes no) -> (BRANCH (BEQ x y) yes no)
426-
(If (Neq64 x y) yes no) -> (BRANCH (BNE x y) yes no)
427-
(If (Less64 x y) yes no) -> (BRANCH (BLT x y) yes no)
428-
(If (Less64U x y) yes no) -> (BRANCH (BLTU x y) yes no)
429-
(If (Geq64 x y) yes no) -> (BRANCH (BGE x y) yes no)
430-
(If (Geq64U x y) yes no) -> (BRANCH (BGEU x y) yes no)
431-
432-
// Conditional branches using reversed operands
433-
(If (Leq64 x y) yes no) -> (BRANCH (BGE y x) yes no)
434-
(If (Leq64U x y) yes no) -> (BRANCH (BGEU y x) yes no)
435-
(If (Greater64 x y) yes no) -> (BRANCH (BLT y x) yes no)
436-
(If (Greater64U x y) yes no) -> (BRANCH (BLTU y x) yes no)
437-
438-
// Conditional branches on a boolean value
439-
// This must be last in the rules file, so that all specialized If block rewrites take higher priority.
440-
(If cond yes no) && cond.Type.IsBoolean() -> (BRANCH (BNE (MOVDconst <cond.Type>) (ANDI <cond.Type> [1] cond)) yes no)
425+
//
426+
// cond is 1 if true. BNE compares against 0.
427+
//
428+
// TODO(prattmic): RISCV branch instructions take two operands to compare,
429+
// so we could generate more efficient code by computing the condition in the
430+
// branch itself. Unfortunately, the compiler doesn't current support Blocks
431+
// with two control values. Revisit adding support for two control values.
432+
(If cond yes no) -> (BNE cond yes no)
441433

442434
// Calls
443435
(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)

src/cmd/compile/internal/ssa/gen/RISCVOps.go

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,8 @@ func init() {
7272
var (
7373
gpstore = regInfo{inputs: []regMask{gpspsbMask, gpspMask, 0}} // SB in first input so we can load from a global, but not in second to avoid using SB as a temporary register
7474
gp01 = regInfo{outputs: []regMask{gpMask}}
75-
// FIXME(prattmic): This is a hack to get things to build, but it probably
76-
// not correct.
7775
gp11 = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}
7876
gp21 = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask}}
79-
gp20 = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{}}
8077
gpload = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{gpMask}}
8178
gp11sb = regInfo{inputs: []regMask{gpspsbMask}, outputs: []regMask{gpMask}}
8279

@@ -161,20 +158,6 @@ func init() {
161158
{name: "SLTU", argLength: 2, reg: gp21, asm: "SLTU"}, // arg0 < arg1, unsigned, result is 0 or 1
162159
{name: "SLTIU", argLength: 1, reg: gp11, asm: "SLTIU", aux: "Int64"}, // arg0 < auxint, unsigned, result is 0 or 1
163160

164-
// Flag pseudo-ops.
165-
// RISC-V doesn't have flags, but SSA wants branches to be flag-based.
166-
// These are pseudo-ops that contain the arguments to the comparison.
167-
// There is a single branching block type, BRANCH,
168-
// which accepts one of these values as its control.
169-
// During code generation we consult the control value
170-
// to emit the correct conditional branch instruction.
171-
{name: "BEQ", argLength: 2, reg: gp20, asm: "BEQ", typ: "Flags"}, // branch if arg0 == arg1
172-
{name: "BNE", argLength: 2, reg: gp20, asm: "BNE", typ: "Flags"}, // branch if arg0 != arg1
173-
{name: "BLT", argLength: 2, reg: gp20, asm: "BLT", typ: "Flags"}, // branch if arg0 < arg1
174-
{name: "BLTU", argLength: 2, reg: gp20, asm: "BLTU", typ: "Flags"}, // branch if arg0 < arg1, unsigned
175-
{name: "BGE", argLength: 2, reg: gp20, asm: "BGE", typ: "Flags"}, // branch if arg0 >= arg1
176-
{name: "BGEU", argLength: 2, reg: gp20, asm: "BGEU", typ: "Flags"}, // branch if arg0 >= arg1, unsigned
177-
178161
// MOVconvert converts between pointers and integers.
179162
// We have a special op for this so as to not confuse GC
180163
// (particularly stack maps). It takes a memory arg so it
@@ -284,7 +267,7 @@ func init() {
284267
}
285268

286269
RISCVblocks := []blockData{
287-
{name: "BRANCH"}, // see flag pseudo-ops above.
270+
{name: "BNE"}, // Control != 0 (take a register)
288271
}
289272

290273
archs = append(archs, arch{

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

Lines changed: 2 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ const (
9393
BlockPPC64FGT
9494
BlockPPC64FGE
9595

96-
BlockRISCVBRANCH
96+
BlockRISCVBNE
9797

9898
BlockS390XEQ
9999
BlockS390XNE
@@ -192,7 +192,7 @@ var blockString = [...]string{
192192
BlockPPC64FGT: "FGT",
193193
BlockPPC64FGE: "FGE",
194194

195-
BlockRISCVBRANCH: "BRANCH",
195+
BlockRISCVBNE: "BNE",
196196

197197
BlockS390XEQ: "EQ",
198198
BlockS390XNE: "NE",
@@ -1296,12 +1296,6 @@ const (
12961296
OpRISCVSLTI
12971297
OpRISCVSLTU
12981298
OpRISCVSLTIU
1299-
OpRISCVBEQ
1300-
OpRISCVBNE
1301-
OpRISCVBLT
1302-
OpRISCVBLTU
1303-
OpRISCVBGE
1304-
OpRISCVBGEU
13051299
OpRISCVMOVconvert
13061300
OpRISCVCALLstatic
13071301
OpRISCVCALLclosure
@@ -16235,72 +16229,6 @@ var opcodeTable = [...]opInfo{
1623516229
},
1623616230
},
1623716231
},
16238-
{
16239-
name: "BEQ",
16240-
argLen: 2,
16241-
asm: riscv.ABEQ,
16242-
reg: regInfo{
16243-
inputs: []inputInfo{
16244-
{0, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16245-
{1, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16246-
},
16247-
},
16248-
},
16249-
{
16250-
name: "BNE",
16251-
argLen: 2,
16252-
asm: riscv.ABNE,
16253-
reg: regInfo{
16254-
inputs: []inputInfo{
16255-
{0, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16256-
{1, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16257-
},
16258-
},
16259-
},
16260-
{
16261-
name: "BLT",
16262-
argLen: 2,
16263-
asm: riscv.ABLT,
16264-
reg: regInfo{
16265-
inputs: []inputInfo{
16266-
{0, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16267-
{1, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16268-
},
16269-
},
16270-
},
16271-
{
16272-
name: "BLTU",
16273-
argLen: 2,
16274-
asm: riscv.ABLTU,
16275-
reg: regInfo{
16276-
inputs: []inputInfo{
16277-
{0, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16278-
{1, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16279-
},
16280-
},
16281-
},
16282-
{
16283-
name: "BGE",
16284-
argLen: 2,
16285-
asm: riscv.ABGE,
16286-
reg: regInfo{
16287-
inputs: []inputInfo{
16288-
{0, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16289-
{1, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16290-
},
16291-
},
16292-
},
16293-
{
16294-
name: "BGEU",
16295-
argLen: 2,
16296-
asm: riscv.ABGEU,
16297-
reg: regInfo{
16298-
inputs: []inputInfo{
16299-
{0, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16300-
{1, 1073741812}, // GP T0 T1 T2 S0 S1 A0 A1 A2 A3 A4 A5 A6 A7 S2 S3 CTXT S5 S6 S7 S8 S9 S10 S11 T3 T4 T5
16301-
},
16302-
},
16303-
},
1630416232
{
1630516233
name: "MOVconvert",
1630616234
argLen: 2,

0 commit comments

Comments
 (0)