Skip to content
Snippets Groups Projects
Commit b6a11acb authored by Albert Gutowski's avatar Albert Gutowski
Browse files

Implement MS _rot intrinsics

Reviewers: thakis, Prazek, compnerd, rnk

Subscribers: majnemer, cfe-commits

Differential Revision: https://reviews.llvm.org/D24311

llvm-svn: 280997
parent dec39493
No related branches found
No related tags found
No related merge requests found
...@@ -725,6 +725,16 @@ LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES) ...@@ -725,6 +725,16 @@ LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl8, "UcUcUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl16, "UsUsUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl, "UiUii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_lrotl, "ULiULii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr8, "UcUcUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr16, "UsUsUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr, "UiUii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_lrotr, "ULiULii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES) LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
// Microsoft library builtins. // Microsoft library builtins.
......
...@@ -696,6 +696,58 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, ...@@ -696,6 +696,58 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
"cast"); "cast");
return RValue::get(Result); return RValue::get(Result);
} }
case Builtin::BI_rotr8:
case Builtin::BI_rotr16:
case Builtin::BI_rotr:
case Builtin::BI_lrotr:
case Builtin::BI_rotr64: {
Value *Val = EmitScalarExpr(E->getArg(0));
Value *Shift = EmitScalarExpr(E->getArg(1));
llvm::Type *ArgType = Val->getType();
Shift = Builder.CreateIntCast(Shift, ArgType, false);
unsigned ArgWidth = cast<llvm::IntegerType>(ArgType)->getBitWidth();
Value *ArgTypeSize = llvm::ConstantInt::get(ArgType, ArgWidth);
Value *ArgZero = llvm::Constant::getNullValue(ArgType);
Value *Mask = llvm::ConstantInt::get(ArgType, ArgWidth - 1);
Shift = Builder.CreateAnd(Shift, Mask);
Value *LeftShift = Builder.CreateSub(ArgTypeSize, Shift);
Value *RightShifted = Builder.CreateLShr(Val, Shift);
Value *LeftShifted = Builder.CreateShl(Val, LeftShift);
Value *Rotated = Builder.CreateOr(LeftShifted, RightShifted);
Value *ShiftIsZero = Builder.CreateICmpEQ(Shift, ArgZero);
Value *Result = Builder.CreateSelect(ShiftIsZero, Val, Rotated);
return RValue::get(Result);
}
case Builtin::BI_rotl8:
case Builtin::BI_rotl16:
case Builtin::BI_rotl:
case Builtin::BI_lrotl:
case Builtin::BI_rotl64: {
Value *Val = EmitScalarExpr(E->getArg(0));
Value *Shift = EmitScalarExpr(E->getArg(1));
llvm::Type *ArgType = Val->getType();
Shift = Builder.CreateIntCast(Shift, ArgType, false);
unsigned ArgWidth = cast<llvm::IntegerType>(ArgType)->getBitWidth();
Value *ArgTypeSize = llvm::ConstantInt::get(ArgType, ArgWidth);
Value *ArgZero = llvm::Constant::getNullValue(ArgType);
Value *Mask = llvm::ConstantInt::get(ArgType, ArgWidth - 1);
Shift = Builder.CreateAnd(Shift, Mask);
Value *RightShift = Builder.CreateSub(ArgTypeSize, Shift);
Value *LeftShifted = Builder.CreateShl(Val, Shift);
Value *RightShifted = Builder.CreateLShr(Val, RightShift);
Value *Rotated = Builder.CreateOr(LeftShifted, RightShifted);
Value *ShiftIsZero = Builder.CreateICmpEQ(Shift, ArgZero);
Value *Result = Builder.CreateSelect(ShiftIsZero, Val, Rotated);
return RValue::get(Result);
}
case Builtin::BI__builtin_unpredictable: { case Builtin::BI__builtin_unpredictable: {
// Always return the argument of __builtin_unpredictable. LLVM does not // Always return the argument of __builtin_unpredictable. LLVM does not
// handle this builtin. Metadata for this builtin should be added directly // handle this builtin. Metadata for this builtin should be added directly
......
...@@ -447,61 +447,6 @@ __emulu(unsigned int __in1, unsigned int __in2) { ...@@ -447,61 +447,6 @@ __emulu(unsigned int __in1, unsigned int __in2) {
return (unsigned __int64)__in1 * (unsigned __int64)__in2; return (unsigned __int64)__in1 * (unsigned __int64)__in2;
} }
/*----------------------------------------------------------------------------*\ /*----------------------------------------------------------------------------*\
|* Bit Twiddling
\*----------------------------------------------------------------------------*/
static __inline__ unsigned char __DEFAULT_FN_ATTRS
_rotl8(unsigned char _Value, unsigned char _Shift) {
_Shift &= 0x7;
return _Shift ? (_Value << _Shift) | (_Value >> (8 - _Shift)) : _Value;
}
static __inline__ unsigned char __DEFAULT_FN_ATTRS
_rotr8(unsigned char _Value, unsigned char _Shift) {
_Shift &= 0x7;
return _Shift ? (_Value >> _Shift) | (_Value << (8 - _Shift)) : _Value;
}
static __inline__ unsigned short __DEFAULT_FN_ATTRS
_rotl16(unsigned short _Value, unsigned char _Shift) {
_Shift &= 0xf;
return _Shift ? (_Value << _Shift) | (_Value >> (16 - _Shift)) : _Value;
}
static __inline__ unsigned short __DEFAULT_FN_ATTRS
_rotr16(unsigned short _Value, unsigned char _Shift) {
_Shift &= 0xf;
return _Shift ? (_Value >> _Shift) | (_Value << (16 - _Shift)) : _Value;
}
static __inline__ unsigned int __DEFAULT_FN_ATTRS
_rotl(unsigned int _Value, int _Shift) {
_Shift &= 0x1f;
return _Shift ? (_Value << _Shift) | (_Value >> (32 - _Shift)) : _Value;
}
static __inline__ unsigned int __DEFAULT_FN_ATTRS
_rotr(unsigned int _Value, int _Shift) {
_Shift &= 0x1f;
return _Shift ? (_Value >> _Shift) | (_Value << (32 - _Shift)) : _Value;
}
static __inline__ unsigned long __DEFAULT_FN_ATTRS
_lrotl(unsigned long _Value, int _Shift) {
_Shift &= 0x1f;
return _Shift ? (_Value << _Shift) | (_Value >> (32 - _Shift)) : _Value;
}
static __inline__ unsigned long __DEFAULT_FN_ATTRS
_lrotr(unsigned long _Value, int _Shift) {
_Shift &= 0x1f;
return _Shift ? (_Value >> _Shift) | (_Value << (32 - _Shift)) : _Value;
}
static
__inline__ unsigned __int64 __DEFAULT_FN_ATTRS
_rotl64(unsigned __int64 _Value, int _Shift) {
_Shift &= 0x3f;
return _Shift ? (_Value << _Shift) | (_Value >> (64 - _Shift)) : _Value;
}
static
__inline__ unsigned __int64 __DEFAULT_FN_ATTRS
_rotr64(unsigned __int64 _Value, int _Shift) {
_Shift &= 0x3f;
return _Shift ? (_Value >> _Shift) | (_Value << (64 - _Shift)) : _Value;
}
/*----------------------------------------------------------------------------*\
|* Bit Counting and Testing |* Bit Counting and Testing
\*----------------------------------------------------------------------------*/ \*----------------------------------------------------------------------------*/
static __inline__ unsigned char __DEFAULT_FN_ATTRS static __inline__ unsigned char __DEFAULT_FN_ATTRS
......
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple i686--windows -emit-llvm %s -o - \
// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple thumbv7--windows -emit-llvm %s -o - \
// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple x86_64--windows -emit-llvm %s -o - \
// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple i686--linux -emit-llvm %s -o - \
// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple x86_64--linux -emit-llvm %s -o - \
// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-64BIT-LONG
// rotate left
unsigned char test_rotl8(unsigned char value, unsigned char shift) {
return _rotl8(value, shift);
}
// CHECK: i8 @test_rotl8
// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE]], [[NEGSHIFT]]
// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
// CHECK: ret i8 [[RESULT]]
// CHECK }
unsigned short test_rotl16(unsigned short value, unsigned char shift) {
return _rotl16(value, shift);
}
// CHECK: i16 @test_rotl16
// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE]], [[NEGSHIFT]]
// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
// CHECK: ret i16 [[RESULT]]
// CHECK }
unsigned int test_rotl(unsigned int value, int shift) {
return _rotl(value, shift);
}
// CHECK: i32 @test_rotl
// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
// CHECK: ret i32 [[RESULT]]
// CHECK }
unsigned long test_lrotl(unsigned long value, int shift) {
return _lrotl(value, shift);
}
// CHECK-32BIT-LONG: i32 @test_lrotl
// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
// CHECK-32BIT-LONG: ret i32 [[RESULT]]
// CHECK-32BIT-LONG }
// CHECK-64BIT-LONG: i64 @test_lrotl
// CHECK-64BIT-LONG: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
// CHECK-64BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
// CHECK-64BIT-LONG: [[HIGH:%[0-9]+]] = shl i64 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK-64BIT-LONG: [[LOW:%[0-9]+]] = lshr i64 [[VALUE]], [[NEGSHIFT]]
// CHECK-64BIT-LONG: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
// CHECK-64BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
// CHECK-64BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
// CHECK-64BIT-LONG: ret i64 [[RESULT]]
// CHECK-64BIT-LONG }
unsigned __int64 test_rotl64(unsigned __int64 value, int shift) {
return _rotl64(value, shift);
}
// CHECK: i64 @test_rotl64
// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE]], [[NEGSHIFT]]
// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
// CHECK: ret i64 [[RESULT]]
// CHECK }
// rotate right
unsigned char test_rotr8(unsigned char value, unsigned char shift) {
return _rotr8(value, shift);
}
// CHECK: i8 @test_rotr8
// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE]], [[NEGSHIFT]]
// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
// CHECK: ret i8 [[RESULT]]
// CHECK }
unsigned short test_rotr16(unsigned short value, unsigned char shift) {
return _rotr16(value, shift);
}
// CHECK: i16 @test_rotr16
// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE]], [[NEGSHIFT]]
// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
// CHECK: ret i16 [[RESULT]]
// CHECK }
unsigned int test_rotr(unsigned int value, int shift) {
return _rotr(value, shift);
}
// CHECK: i32 @test_rotr
// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
// CHECK: ret i32 [[RESULT]]
// CHECK }
unsigned long test_lrotr(unsigned long value, int shift) {
return _lrotr(value, shift);
}
// CHECK-32BIT-LONG: i32 @test_lrotr
// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
// CHECK-32BIT-LONG: ret i32 [[RESULT]]
// CHECK-32BIT-LONG }
// CHECK-64BIT-LONG: i64 @test_lrotr
// CHECK-64BIT-LONG: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
// CHECK-64BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
// CHECK-64BIT-LONG: [[LOW:%[0-9]+]] = lshr i64 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK-64BIT-LONG: [[HIGH:%[0-9]+]] = shl i64 [[VALUE]], [[NEGSHIFT]]
// CHECK-64BIT-LONG: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
// CHECK-64BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
// CHECK-64BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
// CHECK-64BIT-LONG: ret i64 [[RESULT]]
// CHECK-64BIT-LONG }
unsigned __int64 test_rotr64(unsigned __int64 value, int shift) {
return _rotr64(value, shift);
}
// CHECK: i64 @test_rotr64
// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE:%[0-9]+]], [[SHIFT]]
// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE]], [[NEGSHIFT]]
// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
// CHECK: ret i64 [[RESULT]]
// CHECK }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment