Assert in VerifySDNode

We are syncing to 2.9 and we are hitting an with our backend in VerifySDNode in SelectionDAG.cpp.

The first assert here is failing

assert(!isa(N) && “Bad MemSDNode!”);

Now, this is new to 2.9 and I am trying to understand what is invalid about what I am generating.

What I generate has worked fine from LLVM version 2.4 until now without causing any issues.

This is occuring while I am attempting to lower a vector extract elt to a custom SDNode that my backend understands.

I am creating the instruction like as follows:

Op = DAG.getNode(AMDILISD::VEXTRACT,

Op.getDebugLoc(), Op.getValueType(),

Op.getOperand(0),

DAG.getTargetConstant(dyn_cast(Op.getOperand(1)->getZExtValue() + 1), MVT::i32));

The custom backend instruction is defined as follows:

def SDTIL_GenVecExtract : SDTypeProfile<1, 2, [

SDTCisEltOfVec<0, 1>, SDTCisVT<2, i32>

]>;

def IL_vextract : SDNode<“AMDILISD::VEXTRACT”, SDTIL_GenVecExtract>;

defm VEXTRACT : VectorExtract<IL_vextract>;

// Class that handles the various vector extract patterns

multiclass VectorExtract {

def _v4i32 : ExtractVectorClass<GPRI32, GPRV4I32, OpNode>;

}

class ExtractVectorClass<RegisterClass DReg, RegisterClass SReg, SDNode OpNode>

: ILFormat<IL_OP_MOV, (outs DReg:$dst), (ins SReg:$src0, i32imm:$src1),

“mov $dst, $src0”,

[(set DReg:$dst, (OpNode SReg:$src0, timm:$src1))]>;

class ILFormat<ILOpCode op, dag outs, dag ins, string asmstr, list pattern>

: Instruction {

let Namespace = “AMDIL”;

dag OutOperandList = outs;

dag InOperandList = ins;

ILOpCode operation = op;

let Pattern = pattern;

let AsmString = !strconcat(asmstr, “\n”);

bit hasIEEEFlag = 0;

bit hasZeroOpFlag = 0;

}

I cannot see how I am doing anything wrong here. I’ve looked at the equivalent x86 shuffle

instructions and they don’t look that much different. The big difference is they do not

specify the SDTCisEltOfVec constraint.

Any ideas?

Thanks,

Micah

So I have debugged into my problem w/ VerifySDNode more to try to figure out why this is occuring and I ran across another peculiarity.

I have a intrinsic that reads from a special register a vec4 i32 value.

The intrinsic is specified as:

def int_AMDIL_get_global_id : GCCBuiltin<"__amdil_get_global_id_int">,

Intrinsic<[llvm_v4i32_ty], [], []>;

My pattern for the intrinsic is:

def GET_GLOBAL_ID : ILFormat<IL_OP_MOV, (outs GPRV4I32:$dst),

(ins), !strconcat(IL_OP_MOV.Text, " $dst, r1021.xyz0"),

[(set GPRV4I32:$dst, (int_AMDIL_get_global_id))]>;

There is no problem here and works fine.

However if I do this:

def int_AMDIL_get_global_id : GCCBuiltin<"__amdil_get_global_id_int">,

Intrinsic<[llvm_v4i32_ty], [], [IntrNoMem]>;

Then my pattern fails and my intrinsic has two extra arguments(Entry Token and some constant value which I am guessing is the intrinsic opcode).

Does anyone have an idea of what would cause IntroNoMem to stop my pattern from being matched? It isn’t just this intrinsic, any intrinsic I add it to no longer matches. If I remove the field, it matches correctly.

Thanks,

Micah

Hi Micah,

assert(!isa<MemSDNode>(N) && "Bad MemSDNode!");

you can't use getNode to allocate a MemSDNode because it does not allocate
enough memory (MemSDNode has extra fields beyond the operands).

Ciao, Duncan.

From: llvmdev-bounces@cs.uiuc.edu [mailto:llvmdev-bounces@cs.uiuc.edu]
On Behalf Of Duncan Sands
Sent: Thursday, March 31, 2011 7:43 PM
To: llvmdev@cs.uiuc.edu
Subject: Re: [LLVMdev] Assert in VerifySDNode

Hi Micah,

> assert(!isa<MemSDNode>(N) && "Bad MemSDNode!");

you can't use getNode to allocate a MemSDNode because it does not
allocate
enough memory (MemSDNode has extra fields beyond the operands).

[Villmow, Micah] Duncan, thanks for the reply. But I don't see how I am generating a MemSDNode with this instruction.

Hi Micah,

assert(!isa<MemSDNode>(N)&& "Bad MemSDNode!");

you can't use getNode to allocate a MemSDNode because it does not
allocate
enough memory (MemSDNode has extra fields beyond the operands).

[Villmow, Micah] Duncan, thanks for the reply. But I don't see how I am generating a MemSDNode with this instruction.

well either a MemSDNode or one of the other cases checked for. Assuming it
was a MemSDNode, then isa<MemSDNode> evaluates to true if you are in one of
the following cases:

   static bool classof(const SDNode *N) {
     // For some targets, we lower some target intrinsics to a MemIntrinsicNode
     // with either an intrinsic or a target opcode.
     return N->getOpcode() == ISD::LOAD ||
            N->getOpcode() == ISD::STORE ||
            N->getOpcode() == ISD::PREFETCH ||
            N->getOpcode() == ISD::ATOMIC_CMP_SWAP ||
            N->getOpcode() == ISD::ATOMIC_SWAP ||
            N->getOpcode() == ISD::ATOMIC_LOAD_ADD ||
            N->getOpcode() == ISD::ATOMIC_LOAD_SUB ||
            N->getOpcode() == ISD::ATOMIC_LOAD_AND ||
            N->getOpcode() == ISD::ATOMIC_LOAD_OR ||
            N->getOpcode() == ISD::ATOMIC_LOAD_XOR ||
            N->getOpcode() == ISD::ATOMIC_LOAD_NAND ||
            N->getOpcode() == ISD::ATOMIC_LOAD_MIN ||
            N->getOpcode() == ISD::ATOMIC_LOAD_MAX ||
            N->getOpcode() == ISD::ATOMIC_LOAD_UMIN ||
            N->getOpcode() == ISD::ATOMIC_LOAD_UMAX ||
            N->isTargetMemoryOpcode();
   }

Probably it is isTargetMemoryOpcode. For X86 there are a lot of these starting
with

       // ATOMADD64_DAG, ATOMSUB64_DAG, ATOMOR64_DAG, ATOMAND64_DAG,
       // ATOMXOR64_DAG, ATOMNAND64_DAG, ATOMSWAP64_DAG -
       // Atomic 64-bit binary operations.
       ATOMADD64_DAG = ISD::FIRST_TARGET_MEMORY_OPCODE,
       ATOMSUB64_DAG,
       ATOMOR64_DAG,
       ATOMXOR64_DAG,
       ATOMAND64_DAG,
       ATOMNAND64_DAG,
       ATOMSWAP64_DAG,

       // LCMPXCHG_DAG, LCMPXCHG8_DAG - Compare and swap.
       LCMPXCHG_DAG,
       LCMPXCHG8_DAG,

       // VZEXT_LOAD - Load, scalar_to_vector, and zero extend.
       VZEXT_LOAD,

       // FNSTCW16m - Store FP control world into i16 memory.
       FNSTCW16m,

       /// FP_TO_INT*_IN_MEM - This instruction implements FP_TO_SINT with the
       /// integer destination in memory and a FP reg source. This corresponds
       /// to the X86::FIST*m instructions and the rounding mode change stuff. It
       /// has two inputs (token chain and address) and two outputs (int value
       /// and token chain).
       FP_TO_INT16_IN_MEM,
...

Is your opcode one of them?

Ciao, Duncan.

Probably it is isTargetMemoryOpcode. For X86 there are a lot of these starting
with

Yeah, I once was fooled with this as well. Basically target opcodes
can be there in two different forms - as pure TargetOpcode or as
TargetMemoryOpcode.
Adding stuff to the end of the enumeration will yield memory opcode by default.