It is time to bring in some conditionals. Adding an “if” to our friend foo():
int foo() {
int retval1 = 0x0AB;
int retval2 = 0;
if (retval2)
return retval2;
return retval1;
}
We need to implement instructions for both conditional and unconditional branches (i.e jumps). An unconditional branch is just like this (assuming no carry flag is set):
...
def brtarget : Operand;
...
let isBarrier=1, isBranch=1, isTerminator=1 in
{
def JNC : HP41MCODEInst<0x00B, (outs), (ins brtarget:$addr),
"JNC $addr", [(br bb:$addr)]>;
}
We will use custom lowered pseudo instructions as an easy solution. This is a start:
class HP41MCODEPseudo pattern> : HP41MCODEInst<0, outs, ins,
asmstr, pattern> {
let isCodeGenOnly = 1;
let isPseudo = 1;
}
...
SDT_HP41MCODEBRCC : SDTypeProfile<0, 4, [SDTCisVT<0,
OtherVT>]>;
def HP41MCODEBRCC : SDNode<"HP41MCODEISD::BRCC",
SDT_HP41MCODEBRCC, [SDNPHasChain, SDNPInGlue]>;
...
let isBranch=1, isTerminator=1 in
{
def BRCC : HP41MCODEPseudo< (outs), (ins brtarget:$addr,
RC:$lhs, i32imm:$rhs, i32imm:$cond),
"#BRCC $addr $lhs $rhs $cond",
[(HP41MCODEBRCC bb:$addr, RC:$lhs, (i32 imm:$rhs),
(i32 imm:$cond))]>;
}
Note that this instruction will only match the case we have in this example. Different cases should use different instructions. More code snippets:
...
BRCC, // Branch to dest on condition
...
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
...
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
...
case HP41MCODEISD::BRCC: return "HP41MCODEISD::BRCC";
...
SDValue HP41MCODETargetLowering::LowerBR_CC(SDValue Op,
SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
ISD::CondCode CC = cast(Op.getOperand(1))->get();
SDValue LHS = Op.getOperand(2);
SDValue RHS = Op.getOperand(3);
SDValue Dest = Op.getOperand(4);
SDLoc dl(Op);
return DAG.getNode(HP41MCODEISD::BRCC, dl, MVT::Other,
Chain, Dest, LHS, RHS,
DAG.getConstant(CC, dl, MVT::i32));
}
...
case ISD::BR_CC:
return LowerBR_CC(Op, DAG);
So for this example we only need to produce machine instructions that compares the C register to 0
and then branches if it is equal. This must be done in a post-RA pass:
bool HP41MCODEInstrInfo::expandPostRAPseudo(
MachineInstr &MI) const {
MachineBasicBlock &MBB = *MI.getParent();
MachineFunction &MF = *MBB.getParent();
const HP41MCODEInstrInfo &TII = *static_cast(
MF.getSubtarget().getInstrInfo());
DebugLoc dl = MBB.findDebugLoc(MI);
switch (MI.getOpcode()) {
case HP41MCODE::BRCC: {
assert(MI.getOperand(1).getReg() == HP41MCODE::C &&
"Not implemented!");
assert(MI.getOperand(2).getImm() == 0 &&
"Not implemented!");
assert(MI.getOperand(3).getImm() == ISD::SETEQ &&
"Not implemented!");
BuildMI(MBB, MI, dl, TII.get(HP41MCODE::qCneq0ALL));
BuildMI(MBB, MI, dl,
TII.get(HP41MCODE::JNC)).addMBB(
MI.getOperand(0).getMBB());
MI.eraseFromParent();
return true;
}
}
return false;
}
This is the machine instruction used:
def qCneq0ALL : HP41MCODEInst<0x2EE, (outs), (ins),
"?C!=0 ALL", []>;
And we get:
.file "hello.c"
.text
.globl foo ! -- Begin function foo
.type foo,@function
foo: ! @foo
! %bb.0: ! %entry
LDI S&X HEX: 0AB
WRIT 2
C=0 ALL
WRIT 1
READ 1
?C!=0 ALL
JNC .LBB0_2
! %bb.1: ! %if.then
READ 1
WRIT 3
JNC .LBB0_3
.LBB0_2: ! %if.end
READ 2
WRIT 3
.LBB0_3: ! %return
READ 3
RTN
.Lfunc_end0:
.size foo, .Lfunc_end0-foo
! -- End function
.ident "clang version 20.0.0git (https://github.com/llvm/llvm-project.git ea1dfd50bfdfbd75969fd7653bc71c81f2a2350f)"
.section ".note.GNU-stack"
.addrsig