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