DAG: specify dependency between nodes.

I’m struggling for a while with the following problem:

I have added couple of intrinsics which output result to the global register.
They have form of: void intrinsic1(int,int) void intrinsic2(int,int,int).
Hence, they were getting removed from DAG on the first combine.

I was able to enforce their place in DAG by creating control flow dependency between them.

That solved all problems in DAG, but llc fails in assert at InstrPrinter call. Debugging shows that for 1-arg instruction, InstrPrinter tries to access second arg.

So, it looks like adding root to DAG node as first arg of type MVT::Other breaks accordance with respective instruction.

Now, I’m gonna get more specific and provide some code.

Instrisic looks in IR like that: call void @llvm.sparc.srxacc(i32 %0)

Creating node in SelectionDAGBuilder::visitIntrinsicCall:

case Intrinsic::sparc_srxacc: {
SDVTList nodeTys = DAG.getVTList(MVT::Other, MVT::i32);
SDValue Ops[2];
Ops[0] = getControlRoot();
Ops[1] = getValue(I.getArgOperand(0));
SDValue srCall = DAG.getNode(ISD::SRXACC, sdl, nodeTys, Ops);
DAG.setRoot(srCall.getValue(0));
return nullptr;
}

Then, custom legalize it (SparcISelLowering):

static SDValue LowerSRXACC(SDValue Op, SelectionDAG &DAG,
const SparcTargetLowering &TLI) {
SDLoc dl(Op);
SDValue xacc = DAG.getRegister(SP::XACC, MVT::i32);
SDVTList nodeTys = DAG.getVTList(MVT::Other, MVT::i32,
MVT::i32);
SDValue Ops[3];
Ops[0] = Op.getOperand(0);
Ops[1] = Op.getOperand(1);
Ops[2] = xacc;

return DAG.getNode(ISD::SRXACC, dl, nodeTys, Ops);
}

Then, select it (SparcISelDAGToDAG):

case ISD::SRXACC: {
SDVTList nodeTys = CurDAG->getVTList(MVT::i32);

SDValue Ops[2];
Ops[0] = N->getOperand(1);
Ops[1] = N->getOperand(2);
return CurDAG->SelectNodeTo(N, SP::SRXACC, nodeTys,
Ops);
}

Corresponding instruction is:
def SRXACC : F3_1<2, 0b011101,
(outs IntRegs:$rd), (ins IntRegs:$rs1),
“srxacc $rs1, $rd”, []>;

Please, note:

My problem is of self-educational and investigative nature.

This instruction srxacc and register xacc are not real.

Produced code aren’t supposed to work anywhere.

I just need llc to be able to output assembly file.

Thanks for your insights.

I'm struggling for a while with the following problem:
I have added couple of intrinsics which output result to the global
register.
They have form of: void intrinsic1(int,int) void intrinsic2(int,int,int).
Hence, they were getting removed from DAG on the first combine.
I was able to enforce their place in DAG by creating control flow
dependency between them.

That solved all problems in DAG, but llc fails in assert at InstrPrinter
call. Debugging shows that for 1-arg instruction, InstrPrinter tries to
access second arg.
So, it looks like adding root to DAG node as first arg of type MVT::Other
breaks accordance with respective instruction.

Now, I'm gonna get more specific and provide some code.
Instrisic looks in IR like that: call void @llvm.sparc.srxacc(i32 %0)

Creating node in SelectionDAGBuilder::visitIntrinsicCall:

  case Intrinsic::sparc_srxacc: {
    SDVTList nodeTys = DAG.getVTList(MVT::Other, MVT::i32);
    SDValue Ops[2];
    Ops[0] = getControlRoot();
    Ops[1] = getValue(I.getArgOperand(0));
    SDValue srCall = DAG.getNode(ISD::SRXACC, sdl, nodeTys, Ops);
    DAG.setRoot(srCall.getValue(0));
    return nullptr;
  }

Then, custom legalize it (SparcISelLowering):

static SDValue LowerSRXACC(SDValue Op, SelectionDAG &DAG,
                           const SparcTargetLowering &TLI) {
    SDLoc dl(Op);
    SDValue xacc = DAG.getRegister(SP::XACC, MVT::i32);
    SDVTList nodeTys = DAG.getVTList(MVT::Other, MVT::i32,
                                     MVT::i32);
    SDValue Ops[3];
    Ops[0] = Op.getOperand(0);
    Ops[1] = Op.getOperand(1);
    Ops[2] = xacc;

    return DAG.getNode(ISD::SRXACC, dl, nodeTys, Ops);
}

Then, select it (SparcISelDAGToDAG):

  case ISD::SRXACC: {
    SDVTList nodeTys = CurDAG->getVTList(MVT::i32);

    SDValue Ops[2];
    Ops[0] = N->getOperand(1);
    Ops[1] = N->getOperand(2);
    return CurDAG->SelectNodeTo(N, SP::SRXACC, nodeTys,
                                Ops);
  }

Here you are adding two inputs to an instruction defined as
having only one input. Is N->getOperand(1) supposed to be the
output register?

-Tom