Author: Martin Storsjö Date: 2021-08-19T11:29:55+03:00 New Revision: cc3affd8b02091bf475f9dd083802e1b6a232be1
URL: https://github.com/llvm/llvm-project/commit/cc3affd8b02091bf475f9dd083802e1b6a232be1 DIFF: https://github.com/llvm/llvm-project/commit/cc3affd8b02091bf475f9dd083802e1b6a232be1.diff LOG: [clang] [MSVC] Implement __mulh and __umulh builtins for aarch64 The code is based on the same __mulh and __umulh intrinsics for x86. This should fix PR51128. Differential Revision: https://reviews.llvm.org/D106721 Added: Modified: clang/include/clang/Basic/BuiltinsAArch64.def clang/lib/CodeGen/CGBuiltin.cpp clang/lib/Headers/intrin.h clang/test/CodeGen/arm64-microsoft-intrinsics.c Removed: ################################################################################ diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def index 1dac5d2371d4..634bcaed20a6 100644 --- a/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/clang/include/clang/Basic/BuiltinsAArch64.def @@ -243,6 +243,9 @@ TARGET_HEADER_BUILTIN(_ReadStatusReg, "LLii", "nh", "intrin.h", ALL_MS_LANGUAG TARGET_HEADER_BUILTIN(_WriteStatusReg, "viLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_AddressOfReturnAddress, "v*", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__mulh, "SLLiSLLiSLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") + #undef BUILTIN #undef LANGBUILTIN #undef TARGET_HEADER_BUILTIN diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e172fc493a25..d74209ae27a4 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -9712,6 +9712,29 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F); } + if (BuiltinID == AArch64::BI__mulh || BuiltinID == AArch64::BI__umulh) { + llvm::Type *ResType = ConvertType(E->getType()); + llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128); + + bool IsSigned = BuiltinID == AArch64::BI__mulh; + Value *LHS = + Builder.CreateIntCast(EmitScalarExpr(E->getArg(0)), Int128Ty, IsSigned); + Value *RHS = + Builder.CreateIntCast(EmitScalarExpr(E->getArg(1)), Int128Ty, IsSigned); + + Value *MulResult, *HigherBits; + if (IsSigned) { + MulResult = Builder.CreateNSWMul(LHS, RHS); + HigherBits = Builder.CreateAShr(MulResult, 64); + } else { + MulResult = Builder.CreateNUWMul(LHS, RHS); + HigherBits = Builder.CreateLShr(MulResult, 64); + } + HigherBits = Builder.CreateIntCast(HigherBits, ResType, IsSigned); + + return HigherBits; + } + // Handle MSVC intrinsics before argument evaluation to prevent double // evaluation. if (Optional<MSVCIntrin> MsvcIntId = translateAarch64ToMsvcIntrin(BuiltinID)) diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h index ff8eb8fca268..34ec79d6acbc 100644 --- a/clang/lib/Headers/intrin.h +++ b/clang/lib/Headers/intrin.h @@ -574,6 +574,9 @@ void _WriteStatusReg(int, __int64); unsigned short __cdecl _byteswap_ushort(unsigned short val); unsigned long __cdecl _byteswap_ulong (unsigned long val); unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 val); + +__int64 __mulh(__int64 __a, __int64 __b); +unsigned __int64 __umulh(unsigned __int64 __a, unsigned __int64 __b); #endif /*----------------------------------------------------------------------------*\ diff --git a/clang/test/CodeGen/arm64-microsoft-intrinsics.c b/clang/test/CodeGen/arm64-microsoft-intrinsics.c index ca8f270bd4f3..36f182433edd 100644 --- a/clang/test/CodeGen/arm64-microsoft-intrinsics.c +++ b/clang/test/CodeGen/arm64-microsoft-intrinsics.c @@ -81,6 +81,28 @@ void check_ReadWriteBarrier() { // CHECK-MSVC: fence syncscope("singlethread") // CHECK-LINUX: error: implicit declaration of function '_ReadWriteBarrier' +long long check_mulh(long long a, long long b) { + return __mulh(a, b); +} + +// CHECK-MSVC: %[[ARG1:.*]] = sext i64 {{.*}} to i128 +// CHECK-MSVC: %[[ARG2:.*]] = sext i64 {{.*}} to i128 +// CHECK-MSVC: %[[PROD:.*]] = mul nsw i128 %[[ARG1]], %[[ARG2]] +// CHECK-MSVC: %[[HIGH:.*]] = ashr i128 %[[PROD]], 64 +// CHECK-MSVC: %[[RES:.*]] = trunc i128 %[[HIGH]] to i64 +// CHECK-LINUX: error: implicit declaration of function '__mulh' + +unsigned long long check_umulh(unsigned long long a, unsigned long long b) { + return __umulh(a, b); +} + +// CHECK-MSVC: %[[ARG1:.*]] = zext i64 {{.*}} to i128 +// CHECK-MSVC: %[[ARG2:.*]] = zext i64 {{.*}} to i128 +// CHECK-MSVC: %[[PROD:.*]] = mul nuw i128 %[[ARG1]], %[[ARG2]] +// CHECK-MSVC: %[[HIGH:.*]] = lshr i128 %[[PROD]], 64 +// CHECK-MSVC: %[[RES:.*]] = trunc i128 %[[HIGH]] to i64 +// CHECK-LINUX: error: implicit declaration of function '__umulh' + unsigned __int64 check__getReg() { unsigned volatile __int64 reg; reg = __getReg(18); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits