https://llvm.org/bugs/show_bug.cgi?id=24226

            Bug ID: 24226
           Summary: Constant not propagated into inline assembly, results
                    in "constraint 'I' expects an integer constant
                    expression"
           Product: clang
           Version: 3.6
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: Driver
          Assignee: [email protected]
          Reporter: [email protected]
                CC: [email protected]
    Classification: Unclassified

Attempting to compile the following program using the integrated assembler
results in:

$ clang++ -g2 -O3 clang-test.cpp -o clang-test.exe
clang-test.cpp:16:11: error: invalid operand for inline asm constraint 'I'
        __asm__ ("rorl %1, %0" : "+mq" (value) : "I" ((unsigned char)(rot...
                 ^
1 error generated.

It appears the integrated assembler does not receive the const value "2". Even
2%32 is constant because the preprocessor can perform the math.

The program is OK on other Linux OS's using GCC/GAS.

**********

// clang++ -g2 -O3 clang-test.cpp -o clang-test.exe
unsigned int RightRotate(unsigned int value, unsigned int rotate);

int main(int argc, char* argv[])
{
    return RightRotate(argc, 2);
}

unsigned int RightRotate(unsigned int value, unsigned int rotate)
{
    // x = value; y = rotate
    // The I constraint ensures we use the immediate-8 variant of the
    // rotate amount y. However, y must be in [0, 31] inclusive. We
    // rely on the preprocessor to propagate the constant and perform
    // the modular reduction so the assembler generates the instruction.
    __asm__ ("rorl %1, %0" : "+mq" (value) : "I" ((unsigned char)(rotate%32)));
    return value;
}

**********

Applies to both:

$ /usr/local/bin/clang++ -v
clang version 3.6.0 (tags/RELEASE_360/final)
Target: x86_64-apple-darwin12.6.0


And

$ clang++ -v
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin12.6.0

**********

We are jumping through these hoops because the cryptographers often call out
specs that are not sympathetic to hardware and standards.


**********

The real code is hairier, and it involves a well defined template
implementations that avoids branching (i.e., all instructions always execute
and it C/C++ avoids undefined behavior):

// Well defined for all y, near constant time
template <class T> inline T rotrImmediateMod(T x, unsigned int y)
{
    static const unsigned int THIS_SIZE = sizeof(T)*8;
    y %= THIS_SIZE;
    return T((x>>y) | (x<<((THIS_SIZE-y) % THIS_SIZE)));
}

Combined with specializations:

template<> inline word32 rotrImmediateMod<word32>(word32 x, unsigned int y)
{
    __asm__ ("rorl %1, %0" : "+g" (x) : "I" ((unsigned char)(y%32)));
    return x;
}

**********

I'll send a case of Heinekens anywhere in the world to the first person who
provides a near constant time intrinsic for left- and right-rotate. I'm amazed
Clang does not provide one
(http://llvm.org/docs/LangRef.html#intrinsic-functions).

With the intrinsic, we avoid all the C/C++ undefined behavior, we avoid the
branching, we get the 1 ASM instruction speedup, and we avoid all the hassles
of inline assembly.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
_______________________________________________
LLVMbugs mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/llvmbugs

Reply via email to