Branch-like intrinsic

Is there a way to implement an intrinsic that looks like a conditional
branch so that it has 2 edges to 2 basic blocks?

Taking a step back, I'm trying to make a special branch where Passes
treat it just like a regular conditional branch except that it's
condition is opaque to everyone, so it isn't removed by optimizations.
Additionally, the special branch would codegen (to x86) to something
other than the regular branch instructions.

Otherwise, I would need to implement the intrinsic as something that
returns its opaque value, and I would add a conditional branch that
consumes the value right away.

Ed

Is there a way to implement an intrinsic that looks like a conditional
branch so that it has 2 edges to 2 basic blocks?

No. All control flow operators must be terminator instructions.

Taking a step back, I'm trying to make a special branch where Passes
treat it just like a regular conditional branch except that it's
condition is opaque to everyone, so it isn't removed by optimizations.
Additionally, the special branch would codegen (to x86) to something
other than the regular branch instructions.

Why not something like:

   %x = llvm.myintrinsic()
   br i1 %x, label %T, label %F

?

-Chris

Right. That's exactly what I meant in the last paragraph of the
original message.

The reason for not wanting this is that %x actually always turns out
to be 1 (on architectures that support it), so %T is always taken. But
this unnecessarily adds overheads with the branch check. However, I do
want the semantics of the code to be a conditional branch, so that
optimization passes still know about the data flow going into %F.

But it wouldn't be the end of the world if I went with this approach. :slight_smile:

Ed

The code generator does CFG simplification to handle cases where blocks become dead during lowering.

-Chris

Oh... is there a way to prevent that from happening? While %x is
always 1 and %T is always taken, %F isn't actually dead. There would
be a way (with another intrinsic) for control to flow into %F at the
point of..
br i1 %x, label %T, label %F

That's why I wanted the rest of the compiler to still know about the
potential flow into %F.

Ed

Then that flow would be explicit in the CFG, right? Then %F wouldn't
be dead, I'm assuming.

-bw

You can change the code generator or not run the block layout pass.

-Chris

Then that flow would be explicit in the CFG, right? Then %F wouldn't
be dead, I'm assuming.

Right. That's why I used a conditional branch after the intrinsic, but
it sounds like the CFG simplification pass after lowering will
optimize it away and no longer have the flow explicit. (To the rest of
the compiler, the only flow into %F is from the branch, but actual
execution can have flow enter %F from elsewhere with the *same* flow
behavior as if it entered from the branch.)

You can change the code generator or not run the block layout pass.

Ok thanks for the help. I'll try finding where to twiddle this.
Perhaps explicitly check if the branch's condition is the call to my
intrinsic.

Or is there another way for me to have my intrinsic return a Value
that causes the codegen to emit an unconditional jump yet keep the CFG
intact?

Ed

No.

-Chris

After thinking about it a bit more, if I choose not to Lower the
intrinsic, I can emit x86 code by changing Target/X86/...td. If I'm
understanding the codebase correctly, LLVM will basically treat the
intrinsic as a black box and emit whatever I tell it to emit.

So for "my_intrinsic : Intrinsic<llvm_i1_ty>", I can "X86Inst<bits I
want in binary>". Where bits is actually 2 x86 instructions: The
special opcode sequence I want followed by a load immediate of 1 into
the output register.

I suppose the other possibility based on Chris' suggestion is to Lower
the intrinsic and specially handle the block layout to not kill the
edge. I would then lower the intrinsic into an inline asm call for the
special opcode followed by an a ConstantInt 1. (Could I get a pointer
to a file/method to modify for block layout/CFG optimization?)

Ed