Index: cfe/trunk/include/clang/Basic/Builtins.def =================================================================== --- cfe/trunk/include/clang/Basic/Builtins.def +++ cfe/trunk/include/clang/Basic/Builtins.def @@ -725,6 +725,16 @@ LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__noop, "i.", "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) // Microsoft library builtins. Index: cfe/trunk/lib/CodeGen/CGBuiltin.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp @@ -696,6 +696,58 @@ "cast"); 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(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(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: { // Always return the argument of __builtin_unpredictable. LLVM does not // handle this builtin. Metadata for this builtin should be added directly Index: cfe/trunk/lib/Headers/intrin.h =================================================================== --- cfe/trunk/lib/Headers/intrin.h +++ cfe/trunk/lib/Headers/intrin.h @@ -447,61 +447,6 @@ 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 \*----------------------------------------------------------------------------*/ static __inline__ unsigned char __DEFAULT_FN_ATTRS Index: cfe/trunk/test/CodeGen/ms-intrinsics-rotations.c =================================================================== --- cfe/trunk/test/CodeGen/ms-intrinsics-rotations.c +++ cfe/trunk/test/CodeGen/ms-intrinsics-rotations.c @@ -0,0 +1,181 @@ +// 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 }