Help understanding and lowering LLVM IDS conditional codes correctly

Note: Question is written after describing what I have coded.

Hello LLVMDevs,

I am trying to impliment floating point comparsion for an architecture which
supports following type of floating point comparision if FPU is available:
fcmp.un → true if one of the operand is NaN
fcmp.lt → ordered less than, if any input NaN then return false
fcmp.eq → ordered equal, if any input NaN then return false
fcmp.le → ordered less equal, if any input NaN then return false
fcmp.gt → ordered grater than, if any input NaN then return false
fcmp.ne → ordered not equal, if any input NaN then return true
fcmp.ge → ordered grater equal, if any input NaN then return false

When FPU is not present I need to generate a library call,

so I have added following code in LowerBR_CC function in XXXISelLowering.cpp

const XXXSubtarget &STI = static_cast<const XXXSubtarget&>
(DAG.getSubtarget());
XXXCC::CondCodes TCC;
getFPCCtoXXCC(CC,TCC);
TargetCC = DAG.getConstant(TCC, dl, MVT::i8);
if (STI.useHardFloat()) {
// if fcmp instruction is available use it
SDValue Flag = DAG.getNode(XXXISD::FCMP, dl, MVT::Glue, LHS, RHS,
TargetCC);
return DAG.getNode(XXXISD::BR_CC, dl, Op.getValueType(),
Chain, Dest, TargetCC, Flag);
}
else {
// else generate library call
DAG.getTargetLoweringInfo().softenSetCCOperands(DAG, MVT::f32, LHS, RHS,
CC, dl);

SDValue Flag = DAG.getNode(XXXISD::CMP, dl, MVT::Glue, LHS, RHS);

if (!RHS.getNode()) {
RHS = DAG.getConstant(0, dl, LHS.getValueType());
TargetCC = DAG.getConstant(XXXCC::COND_NE, dl, MVT::i8);
}
return DAG.getNode(XXXISD::BR_CC, dl, MVT::Other,
Chain, Dest, TargetCC, Flag);
}

and code for getFPCCtoXXCC() is as following:

static void getFPCCtoXXCC(ISD::CondCode CC, XXXCC::CondCodes &CondCode) {
switch (CC) {
default:
llvm_unreachable(“Unknown FP condition!”);
case ISD::SETEQ:
case ISD::SETOEQ:
CondCode = XXXCC::COND_E;
break;
case ISD::SETGT:
case ISD::SETOGT:
CondCode = XXXCC::COND_GT;
break;
case ISD::SETGE:
case ISD::SETOGE:
CondCode = XXXCC::COND_GE;
break;
case ISD::SETOLT:
case ISD::SETLT:
CondCode = XXXCC::COND_LT;
break;
case ISD::SETOLE:
case ISD::SETLE:
CondCode = XXXCC::COND_LE;
break;
case ISD::SETONE:
case ISD::SETNE:
CondCode = XXXCC::COND_NE;
break;
case ISD::SETUO:
CondCode = XXXCC::COND_UN;
break;
case ISD::SETO:
case ISD::SETUEQ:
case ISD::SETUGT:
case ISD::SETUGE:
case ISD::SETULT:
case ISD::SETULE:
case ISD::SETUNE:
CC = getSetCCInverse(CC,false);
getFPCCtoMBCC(CC,CondCode);
break;
}
}

I am generating wrong code when using floating point library call for
comparions. For the following simple case:
float branchTest(float a, float b) {
float retVal;
if (a == b) {
retVal = a / b + 22.34;
}
return retVal;
}
I am getting:
brlid r15,__nesf2
nop
beqi r3,.LBB0_2 ; r3 is return regsiter

Now I want to understand difference between three different version of Condition
Codes for same operation and how according to my target I should handle them.
For example let’s consider SETNE, SETONE and SETUNE so for my architecture
I think for floating point all three are same so do I need to use
getSetCCInverse() ? Also when I look at the code of
TargetLowering::softenSetCCOperands I see that for some condition code it uses
getSetCCInverse() and also I am not able to understand the way it groups
condition code in switch case for example :
case ISD::SETEQ:
case ISD::SETOEQ:
LC1 = (VT == MVT::f32) ? RTLIB::OEQ_F32 :
(VT == MVT::f64) ? RTLIB::OEQ_F64 : RTLIB::OEQ_F128;
break;
case ISD::SETNE:
case ISD::SETUNE:
LC1 = (VT == MVT::f32) ? RTLIB::UNE_F32 :
(VT == MVT::f64) ? RTLIB::UNE_F64 : RTLIB::UNE_F128;
break;
here why SETNE and SETUNE is considered same, why SETONE is considered
differently. Is there any guideline to lower conditional code properly?

Sincerely,
Vivek

No, they’re not the same. Please see: which explains the difference between SETONE (one) and SETUNE (une). Regarding how SETNE is interpreted for FP, see the comment in the definition of CondCode in include/llvm/CodeGen/ISDOpcodes.h which explains, “// Don’t care operations: undefined if the input is a nan.”. To support the unordered comparisons, if your FPU has only ordered comparisons, then you might need to do the underlying comparison, and a NaN check, and then OR the results. I think that using setCondCodeAction will cause the expansions for the hardware-unsupported variants to happen for you. -Hal

Note: Question is written after describing what I have coded.

Hello LLVMDevs,

I am trying to impliment floating point comparsion for an architecture
which
supports following type of floating point comparision if FPU is available:
fcmp.un --> true if one of the operand is NaN
fcmp.lt --> ordered less than, if any input NaN then return false
fcmp.eq --> ordered equal, if any input NaN then return false
fcmp.le --> ordered less equal, if any input NaN then return false
fcmp.gt --> ordered grater than, if any input NaN then return false
fcmp.ne --> ordered not equal, if any input NaN then return true
fcmp.ge --> ordered grater equal, if any input NaN then return false

When FPU is not present I need to generate a library call,

so I have added following code in LowerBR_CC function in
XXXISelLowering.cpp

const XXXSubtarget &STI = static_cast<const XXXSubtarget&>
                                             (DAG.getSubtarget());
XXXCC::CondCodes TCC;
getFPCCtoXXCC(CC,TCC);
TargetCC = DAG.getConstant(TCC, dl, MVT::i8);
if (STI.useHardFloat()) {
    // if fcmp instruction is available use it
   SDValue Flag = DAG.getNode(XXXISD::FCMP, dl, MVT::Glue, LHS, RHS,
                      TargetCC);
   return DAG.getNode(XXXISD::BR_CC, dl, Op.getValueType(),
                  Chain, Dest, TargetCC, Flag);
}
else {
    // else generate library call
   DAG.getTargetLoweringInfo().softenSetCCOperands(DAG, MVT::f32, LHS,
RHS,
                                                   CC, dl);

   SDValue Flag = DAG.getNode(XXXISD::CMP, dl, MVT::Glue, LHS, RHS);

   if (!RHS.getNode()) {
     RHS = DAG.getConstant(0, dl, LHS.getValueType());
     TargetCC = DAG.getConstant(XXXCC::COND_NE, dl, MVT::i8);
   }
   return DAG.getNode(XXXISD::BR_CC, dl, MVT::Other,
                  Chain, Dest, TargetCC, Flag);
}

and code for getFPCCtoXXCC() is as following:

static void getFPCCtoXXCC(ISD::CondCode CC, XXXCC::CondCodes &CondCode) {
  switch (CC) {
    default:
      llvm_unreachable("Unknown FP condition!");
    case ISD::SETEQ:
    case ISD::SETOEQ:
      CondCode = XXXCC::COND_E;
      break;
    case ISD::SETGT:
    case ISD::SETOGT:
      CondCode = XXXCC::COND_GT;
      break;
    case ISD::SETGE:
    case ISD::SETOGE:
      CondCode = XXXCC::COND_GE;
      break;
    case ISD::SETOLT:
    case ISD::SETLT:
      CondCode = XXXCC::COND_LT;
      break;
    case ISD::SETOLE:
    case ISD::SETLE:
      CondCode = XXXCC::COND_LE;
      break;
    case ISD::SETONE:
    case ISD::SETNE:
      CondCode = XXXCC::COND_NE;
      break;
    case ISD::SETUO:
      CondCode = XXXCC::COND_UN;
      break;
    case ISD::SETO:
    case ISD::SETUEQ:
    case ISD::SETUGT:
    case ISD::SETUGE:
    case ISD::SETULT:
    case ISD::SETULE:
    case ISD::SETUNE:
      CC = getSetCCInverse(CC,false);
      getFPCCtoMBCC(CC,CondCode);
      break;
  }
}

I am generating wrong code when using floating point library call for
comparions. For the following simple case:
float branchTest(float a, float b) {
float retVal;
if (a == b) {
retVal = a / b + 22.34;
}
return retVal;
}
I am getting:
brlid r15,__nesf2
nop
beqi r3,.LBB0_2 ; r3 is return regsiter

Now I want to understand difference between three different version of
Condition
Codes for same operation and how according to my target I should handle
them.
For example let's consider SETNE, SETONE and SETUNE so for my architecture
I think for floating point all three are same

No, they're not the same. Please see:

  http://llvm.org/docs/LangRef.html#id290

which explains the difference between SETONE (one) and SETUNE (une).
Regarding how SETNE is interpreted for FP, see the comment in the
definition of CondCode in include/llvm/CodeGen/ISDOpcodes.h which
explains, "// Don't care operations: undefined if the input is a nan.".

To support the unordered comparisons, if your FPU has only ordered
comparisons, then you might need to do the underlying comparison, and a NaN
check, and then OR the results. I think that using setCondCodeAction will
cause the expansions for the hardware-unsupported variants to happen for
you.

-Hal

Thanks Hal for the guidance !

-Vivek

Hello Hal,
setCondCodeAction(expand) for un ordered comparison generates semantically wrong code for me for example SETUNE gets converted to SETOE that causes infinite loops.

What is ideal place where I can convert unordered comparison to un comparison + OR + ordered comparison ?
Can I do it by adding required SDNodes ?
for example I am trying to do it in LowerBR_CC as shown below:

getFPCCtoMBCC(CC,TCC);
TargetCC = DAG.getConstant(TCC, dl, MVT::i8);
Flag = DAG.getNode(XXXISD::FCMP, dl, MVT::Glue, LHS, RHS,
TargetCC);
if (isUnordered) {
TCC = XXX::COND_UN;
TargetCC = DAG.getConstant(TCC, dl, MVT::i8);
SDValue UnComp = DAG.getNode(XXX::FCMP, dl, MVT::Glue, LHS, RHS,
TargetCC);
Flag = DAG.getNode(ISD::OR, dl, MVT::Glue, Flag, UnComp);
}

but here I can’t OR 2 MVT::Glue value.
How can I compare results of two fcmp SDValue objs?

Please provide some guidance.

Sincerely,
Vivek

Can you please explain what is happening? It sounds like a bug we should fix. If your FCMP node sets some register, you’d need to read it (DAG.getCopyFromReg). -Hal

Hello Hal,
setCondCodeAction(expand) for un ordered comparison generates semantically
wrong code for me for example SETUNE gets converted to SETOE that causes
infinite loops.

Can you please explain what is happening? It sounds like a bug we should
fix.

I don't think it is LLVM bug but I am missing some thing or I have not

implemented something related properly.
But I will experiment it with and let you my findings.

What is ideal place where I can convert unordered comparison to un
comparison + OR + ordered comparison ?
Can I do it by adding required SDNodes ?
for example I am trying to do it in LowerBR_CC as shown below:
      getFPCCtoMBCC(CC,TCC);
      TargetCC = DAG.getConstant(TCC, dl, MVT::i8);
      Flag = DAG.getNode(XXXISD::FCMP, dl, MVT::Glue, LHS, RHS,
                         TargetCC);
      if (isUnordered) {
      TCC = XXX::COND_UN;
      TargetCC = DAG.getConstant(TCC, dl, MVT::i8);
      SDValue UnComp = DAG.getNode(XXX::FCMP, dl, MVT::Glue, LHS, RHS,
                                   TargetCC);
      Flag = DAG.getNode(ISD::OR, dl, MVT::Glue, Flag, UnComp);
      }
but here I can't OR 2 MVT::Glue value.
How can I compare results of two fcmp SDValue objs?

If your FCMP node sets some register, you'd need to read it
(DAG.getCopyFromReg).

Ok I will see some examples for getCopyFromReg().

Thanks,
Vivek

Hello Hal,
setCondCodeAction(expand) for un ordered comparison generates
semantically wrong code for me for example SETUNE gets converted to SETOE
that causes infinite loops.

Can you please explain what is happening? It sounds like a bug we should
fix.

I don't think it is LLVM bug but I am missing some thing or I have not

implemented something related properly.
But I will experiment it with and let you my findings.

What is ideal place where I can convert unordered comparison to un
comparison + OR + ordered comparison ?
Can I do it by adding required SDNodes ?
for example I am trying to do it in LowerBR_CC as shown below:
      getFPCCtoMBCC(CC,TCC);
      TargetCC = DAG.getConstant(TCC, dl, MVT::i8);
      Flag = DAG.getNode(XXXISD::FCMP, dl, MVT::Glue, LHS, RHS,
                         TargetCC);
      if (isUnordered) {
      TCC = XXX::COND_UN;
      TargetCC = DAG.getConstant(TCC, dl, MVT::i8);
      SDValue UnComp = DAG.getNode(XXX::FCMP, dl, MVT::Glue, LHS, RHS,
                                   TargetCC);
      Flag = DAG.getNode(ISD::OR, dl, MVT::Glue, Flag, UnComp);
      }
but here I can't OR 2 MVT::Glue value.
How can I compare results of two fcmp SDValue objs?

If your FCMP node sets some register, you'd need to read it
(DAG.getCopyFromReg).

Hey Hal,

I have few questions here,
Do you here mean FCMP sets any physical register ? Because as per my
understanding getCopyFromReg() requires a reg operand to copy from.
What if it set some virtual register? Then how to use getCopyFromReg()
method?

getCopyFromReg() requires a Chain operand so I have to make FCMP both Chain
and Glue (by using SDVTList
<http://llvm.org/docs/doxygen/html/structllvm_1_1SDVTList.html&gt; VTs =
getVTList
<http://llvm.org/docs/doxygen/html/classllvm_1_1SelectionDAG.html#a196c23d6cb4d768d037970f1f35bbf66&gt;
(MVT::Other
<http://llvm.org/docs/doxygen/html/classllvm_1_1MVT.html#afd69b4f2dff97a2d7c0192cc769ef50ca62a222acce6360abd2726719fabc2797&gt;,
MVT::Glue
<http://llvm.org/docs/doxygen/html/classllvm_1_1MVT.html#afd69b4f2dff97a2d7c0192cc769ef50ca59a1908cf136662bcfdc11ed49515ca9&gt;
)) right ?

Sincerely,
Vivek

Yes. You wouldn’t. If your FCMP node sets a virtual register, then it should be one of the return values of the node (i.e. there should be a some value type (MVT::i8 or whatever) in the value-type list for the FCMP node). -Hal