Bug 20871 -- is there a fix or work around?

Looks like I have run into the same issue reported in:


Is there a fix or work-around for it? The bug report seems to be still open.

Is there a switch (other than -O0) that can be used to work around this? Currently, our 32-bit compilation is broken with clang (undefined reference to __multi3) when we changed the type of some variables from unsigned to uint64_t. There are some loops in the code that are getting optimized by clang and ending up with calls to __multi3. Somebody wrote in the existing bug report that indvars is responsible for this. Is there a way to turn it off?

I got no responses to my earlier emails. Since I was stuck, I looked into this further and I tried the following change in my LLVM (4.0.1) sandbox and it seems to address the problem.

I handled only __multi3 for now but a complete fix would handle other 128-bit functions as well. Further, the guard that I am using (isArch32Bit)… is it appropriate? Should

I check for something else instead?

diff --git a/lib/CodeGen/TargetLoweringBase.cpp b/lib/CodeGen/TargetLoweringBase.cpp

index 003311b…05582fe 100644

— a/lib/CodeGen/TargetLoweringBase.cpp

+++ b/lib/CodeGen/TargetLoweringBase.cpp

@@ -83,7 +83,9 @@ static void InitLibcallNames(const char **Names, const Triple &TT) {

Names[RTLIB::MUL_I16] = “__mulhi3”;

Names[RTLIB::MUL_I32] = “__mulsi3”;

Names[RTLIB::MUL_I64] = “__muldi3”;

  • Names[RTLIB::MUL_I128] = “__multi3”;
  • if (!TT.isArch32Bit()) {

  • Names[RTLIB::MUL_I128] = “__multi3”;

  • }

Names[RTLIB::MULO_I32] = “__mulosi4”;

Names[RTLIB::MULO_I64] = “__mulodi4”;

Names[RTLIB::MULO_I128] = “__muloti4”;

Anyone familiar with this stuff, please comment. I know the above code has changed in the master and I may have to add the following instead:

  • if (TT.isArch32Bit()) {

  • Names[RTLIB::MUL_I128] = nullptr;

  • }



Ignore the suggested fix in my earlier post. How about this?

diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp

index 20c81c3…b8ebf42 100644

— a/lib/Target/X86/X86ISelLowering.cpp

+++ b/lib/Target/X86/X86ISelLowering.cpp

@@ -1632,10 +1632,11 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,

if (!Subtarget.is64Bit()) {

// These libcalls are not available in 32-bit.

setLibcallName(RTLIB::SHL_I128, nullptr);

setLibcallName(RTLIB::SRL_I128, nullptr);

setLibcallName(RTLIB::SRA_I128, nullptr);

+ setLibcallName(RTLIB::MUL_I128, nullptr);


// Combine sin / cos into one node or libcall if possible.

if (Subtarget.hasSinCos()) {

setLibcallName(RTLIB::SINCOS_F32, “sincosf”);

This will make the Legalizer choose the brute force approach below:

void DAGTypeLegalizer::ExpandIntRes_MUL(SDNode *N,

SDValue &Lo, SDValue &Hi) {

if (LC == RTLIB::UNKNOWN_LIBCALL || !TLI.getLibcallName(LC)) {

// We’ll expand the multiplication by brute force because we have no other

// options. This is a trivially-generalized version of the code from

// Hacker’s Delight (itself derived from Knuth’s Algorithm M from section

// 4.3.1).

That seems like a valid fix to me.

Thanks. Looks like we can do this for only __multi3. Other TImode functions (e.g. __divti3, __modti3, etc.) are not defined on 32-bit. I am not sure if any optimizations could cause those to be generated. AFAICT there is no fall back support (like what is there for MUL) in the Legalizer for wide SDIV, etc. See below:

void DAGTypeLegalizer::ExpandIntRes_SDIV(SDNode *N,

SDValue &Lo, SDValue &Hi) {

EVT VT = N->getValueType(0);

SDLoc dl(N);

SDValue Ops[2] = { N->getOperand(0), N->getOperand(1) };

if (TLI.getOperationAction(ISD::SDIVREM, VT) == TargetLowering::Custom) {

SDValue Res = DAG.getNode(ISD::SDIVREM, dl, DAG.getVTList(VT, VT), Ops);

SplitInteger(Res.getValue(0), Lo, Hi);




if (VT == MVT::i16)


else if (VT == MVT::i32)


else if (VT == MVT::i64)


else if (VT == MVT::i128)


assert(LC != RTLIB::UNKNOWN_LIBCALL && “Unsupported SDIV!”);

SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, true, dl).first, Lo, Hi);