Dead Code During Manual ISel

Dead Code During Manual ISel

During (manual) instruction selection (ISel) for my target with a non RISC instruction set I generate dead code. Manual ISel is required because multiple values are returned by the instruction.

Description

Example C code:

void postinc(volatile int *dst, volatile int *src1, volatile int *src2) {
  int rhs = *src2++;
  int dummy1 = *src2++; // create long chain
  int dummy2 = *src1++; // create long chain
  int lhs = *src1++;

  *dst++ = lhs - rhs; // should gen SUB (Adst)++,(Alhs)++,Rrhs

  // consume incremented pointers
  int src1_1 = *src1++;
  int src2_1 = *src2++;
  *dst = src1_1 + src2_1;
}

The optimal instruction SUB (Adst)++,(Alhs)++,Rrhs loads the value from memory, subtracts the values, writes the result into memory and returns two results: the incremented pointers for the destination and source operand.

During ISel I generate the correct SUB instruction and rewire all results:

  1. incremented destination pointer
  2. incremented source pointer
  3. new output chain
  4. LOAD out-chain (to kill the LOAD)

After that:

  1. STORE has no uses (it’s dead as wished)
  2. SUB is used by STORE only
  3. LOAD (lhs) is used by SUB only

BUT dead code is generated for the remaining LOAD and SUB operations! There is a second SUB instruction generated!

Work-Around

As far as I can see SelectionDAGISel::DoInstructionSelection() skips operations that are not used. STORE does not have uses and is skipped. But LOAD and SUB in my example have uses, and therefore code is generated for them.

My work-around is to mark the replaced nodes STORE, LOAD and SUB by X->setNodeId(-1); and to skip ISEL for these node in my Target::Select(SDNode *N) method (if (-1 == N->getNodeId()) return;).

I do not like my work-around. Is there another solution?

I’m not sure what did you mean by “manual”, but IIRC the TableGen-ed (SelectionDAG) instruction selector actively cleans up dead nodes after each transformation (e.g. MorphNode).

Assuming you’re not using the TableGen-ed selector, maybe you can override SelectionDAGISel::PostprocessISelDAG and call SelectionDAG::RemoveDeadNodes there.

Thanks @mshockwave.
I’m using SelectionDAG::RemoveDeadNode() now.