@@ -5,8 +5,9 @@ public import Veir.GlobalOpInfo
55/-!
66# ControlFlowInterfaces
77
8- This file provides support for querying which operands are forwarded to a successor
9- and mapping those operands to successor block arguments.
8+ This file provides support for querying which operands are forwarded to a successor,
9+ mapping those operands to successor block arguments, and selecting a successor from
10+ known constant operands.
1011-/
1112
1213namespace Veir
@@ -29,6 +30,18 @@ instance : GetElem? SuccessorOperands Nat ValuePtr
2930
3031namespace BranchOpInterface
3132
33+ /-- Return the known value of an operand, or `none` when it is unknown. -/
34+ private def getKnownOperand?
35+ (operands : Array (Option RuntimeValue)) (index : Nat) : Option RuntimeValue := do
36+ let operand ← operands[index]?
37+ operand
38+
39+ /-- Return the true or false successor of a conditional branch. -/
40+ private def getConditionalSuccessor?
41+ (branchOp : OperationPtr) (condition : Bool) (raw : IRContext OpCode) : Option BlockPtr :=
42+ let successors := branchOp.getSuccessors! raw
43+ if condition then successors[0 ]? else successors[1 ]?
44+
3245/--
3346 Return the operands passed to `successorIndex` of a branch operation.
3447-/
@@ -82,6 +95,52 @@ def getSuccessorOperand?
8295 getSuccessorOperands? branchOp successorIndex raw >>= fun operands =>
8396 operands[blockArgumentIndex]?
8497
98+ /--
99+ Return the successor selected by the known constant operands of a branch operation.
100+ An operand is `none` when its value is unknown. Returns `none` when the operation is
101+ not a supported branch or a single successor cannot be determined.
102+ -/
103+ def getSuccessorForOperands?
104+ (branchOp : OperationPtr) (operands : Array (Option RuntimeValue))
105+ (raw : IRContext OpCode) : Option BlockPtr :=
106+ match branchOp.getOpType! raw with
107+ | .cf .br | .llvm .br | .riscv_cf .branch =>
108+ (branchOp.getSuccessors! raw)[0 ]?
109+ | .cf .cond_br | .llvm .cond_br => do
110+ let .int _ (.val condition) ← getKnownOperand? operands 0 | none
111+ getConditionalSuccessor? branchOp (condition ≠ 0 ) raw
112+ | .riscv_cf .beqz => do
113+ let .reg condition ← getKnownOperand? operands 0 | none
114+ getConditionalSuccessor? branchOp (condition.val = 0 #64 ) raw
115+ | .riscv_cf .bnez => do
116+ let .reg condition ← getKnownOperand? operands 0 | none
117+ getConditionalSuccessor? branchOp (condition.val ≠ 0 #64 ) raw
118+ | .riscv_cf .beq => do
119+ let .reg lhs ← getKnownOperand? operands 0 | none
120+ let .reg rhs ← getKnownOperand? operands 1 | none
121+ getConditionalSuccessor? branchOp (lhs = rhs) raw
122+ | .riscv_cf .bne => do
123+ let .reg lhs ← getKnownOperand? operands 0 | none
124+ let .reg rhs ← getKnownOperand? operands 1 | none
125+ getConditionalSuccessor? branchOp (lhs ≠ rhs) raw
126+ | .riscv_cf .blt => do
127+ let .reg lhs ← getKnownOperand? operands 0 | none
128+ let .reg rhs ← getKnownOperand? operands 1 | none
129+ getConditionalSuccessor? branchOp (BitVec.slt lhs.val rhs.val) raw
130+ | .riscv_cf .bge => do
131+ let .reg lhs ← getKnownOperand? operands 0 | none
132+ let .reg rhs ← getKnownOperand? operands 1 | none
133+ getConditionalSuccessor? branchOp (!BitVec.slt lhs.val rhs.val) raw
134+ | .riscv_cf .bltu => do
135+ let .reg lhs ← getKnownOperand? operands 0 | none
136+ let .reg rhs ← getKnownOperand? operands 1 | none
137+ getConditionalSuccessor? branchOp (BitVec.ult lhs.val rhs.val) raw
138+ | .riscv_cf .bgeu => do
139+ let .reg lhs ← getKnownOperand? operands 0 | none
140+ let .reg rhs ← getKnownOperand? operands 1 | none
141+ getConditionalSuccessor? branchOp (!BitVec.ult lhs.val rhs.val) raw
142+ | _ => none
143+
85144end BranchOpInterface
86145
87146end
0 commit comments