Skip to content

Commit 03c698a

Browse files
authored
[MSVC, ARM64] Add _Copy* and _Count* intrinsics (#66554)
Implement the _Count* and _Copy* Windows ARM intrinsics: ``` double _CopyDoubleFromInt64(__int64) float _CopyFloatFromInt32(__int32) __int32 _CopyInt32FromFloat(float) __int64 _CopyInt64FromDouble(double) unsigned int _CountLeadingOnes(unsigned long) unsigned int _CountLeadingOnes64(unsigned __int64) unsigned int _CountLeadingSigns(long) unsigned int _CountLeadingSigns64(__int64) unsigned int _CountLeadingZeros(unsigned long) unsigned int _CountLeadingZeros64(unsigned __int64) unsigned int _CountOneBits(unsigned long) unsigned int _CountOneBits64(unsigned __int64) ``` Full list of intrinsics here: [https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics](https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics) Bug: [65405](#65405)
1 parent 21e84e6 commit 03c698a

File tree

4 files changed

+221
-1
lines changed

4 files changed

+221
-1
lines changed

clang/include/clang/Basic/BuiltinsAArch64.def

+14-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
259259

260260
TARGET_HEADER_BUILTIN(__break, "vi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
261261

262-
263262
TARGET_HEADER_BUILTIN(__writex18byte, "vUNiUc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
264263
TARGET_HEADER_BUILTIN(__writex18word, "vUNiUs", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
265264
TARGET_HEADER_BUILTIN(__writex18dword, "vUNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
@@ -270,6 +269,20 @@ TARGET_HEADER_BUILTIN(__readx18word, "UsUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
270269
TARGET_HEADER_BUILTIN(__readx18dword, "UNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
271270
TARGET_HEADER_BUILTIN(__readx18qword, "ULLiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
272271

272+
TARGET_HEADER_BUILTIN(_CopyDoubleFromInt64, "dSLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
273+
TARGET_HEADER_BUILTIN(_CopyFloatFromInt32, "fSi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
274+
TARGET_HEADER_BUILTIN(_CopyInt32FromFloat, "Sif", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
275+
TARGET_HEADER_BUILTIN(_CopyInt64FromDouble, "SLLid", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
276+
277+
TARGET_HEADER_BUILTIN(_CountLeadingOnes, "UiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
278+
TARGET_HEADER_BUILTIN(_CountLeadingOnes64, "UiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
279+
TARGET_HEADER_BUILTIN(_CountLeadingSigns, "UiSNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
280+
TARGET_HEADER_BUILTIN(_CountLeadingSigns64, "UiSLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
281+
TARGET_HEADER_BUILTIN(_CountLeadingZeros, "UiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
282+
TARGET_HEADER_BUILTIN(_CountLeadingZeros64, "UiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
283+
TARGET_HEADER_BUILTIN(_CountOneBits, "UiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
284+
TARGET_HEADER_BUILTIN(_CountOneBits64, "UiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
285+
273286
#undef BUILTIN
274287
#undef LANGBUILTIN
275288
#undef TARGET_BUILTIN

clang/lib/CodeGen/CGBuiltin.cpp

+55
Original file line numberDiff line numberDiff line change
@@ -10779,6 +10779,61 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
1077910779
return Load;
1078010780
}
1078110781

10782+
if (BuiltinID == AArch64::BI_CopyDoubleFromInt64 ||
10783+
BuiltinID == AArch64::BI_CopyFloatFromInt32 ||
10784+
BuiltinID == AArch64::BI_CopyInt32FromFloat ||
10785+
BuiltinID == AArch64::BI_CopyInt64FromDouble) {
10786+
Value *Arg = EmitScalarExpr(E->getArg(0));
10787+
llvm::Type *RetTy = ConvertType(E->getType());
10788+
return Builder.CreateBitCast(Arg, RetTy);
10789+
}
10790+
10791+
if (BuiltinID == AArch64::BI_CountLeadingOnes ||
10792+
BuiltinID == AArch64::BI_CountLeadingOnes64 ||
10793+
BuiltinID == AArch64::BI_CountLeadingZeros ||
10794+
BuiltinID == AArch64::BI_CountLeadingZeros64) {
10795+
Value *Arg = EmitScalarExpr(E->getArg(0));
10796+
llvm::Type *ArgType = Arg->getType();
10797+
10798+
if (BuiltinID == AArch64::BI_CountLeadingOnes ||
10799+
BuiltinID == AArch64::BI_CountLeadingOnes64)
10800+
Arg = Builder.CreateXor(Arg, Constant::getAllOnesValue(ArgType));
10801+
10802+
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
10803+
Value *Result = Builder.CreateCall(F, {Arg, Builder.getInt1(false)});
10804+
10805+
if (BuiltinID == AArch64::BI_CountLeadingOnes64 ||
10806+
BuiltinID == AArch64::BI_CountLeadingZeros64)
10807+
Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
10808+
return Result;
10809+
}
10810+
10811+
if (BuiltinID == AArch64::BI_CountLeadingSigns ||
10812+
BuiltinID == AArch64::BI_CountLeadingSigns64) {
10813+
Value *Arg = EmitScalarExpr(E->getArg(0));
10814+
10815+
Function *F = (BuiltinID == AArch64::BI_CountLeadingSigns)
10816+
? CGM.getIntrinsic(Intrinsic::aarch64_cls)
10817+
: CGM.getIntrinsic(Intrinsic::aarch64_cls64);
10818+
10819+
Value *Result = Builder.CreateCall(F, Arg, "cls");
10820+
if (BuiltinID == AArch64::BI_CountLeadingSigns64)
10821+
Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
10822+
return Result;
10823+
}
10824+
10825+
if (BuiltinID == AArch64::BI_CountOneBits ||
10826+
BuiltinID == AArch64::BI_CountOneBits64) {
10827+
Value *ArgValue = EmitScalarExpr(E->getArg(0));
10828+
llvm::Type *ArgType = ArgValue->getType();
10829+
Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
10830+
10831+
Value *Result = Builder.CreateCall(F, ArgValue);
10832+
if (BuiltinID == AArch64::BI_CountOneBits64)
10833+
Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
10834+
return Result;
10835+
}
10836+
1078210837
// Handle MSVC intrinsics before argument evaluation to prevent double
1078310838
// evaluation.
1078410839
if (std::optional<MSVCIntrin> MsvcIntId =

clang/lib/Headers/intrin.h

+14
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,20 @@ unsigned char __readx18byte(unsigned long offset);
572572
unsigned short __readx18word(unsigned long offset);
573573
unsigned long __readx18dword(unsigned long offset);
574574
unsigned __int64 __readx18qword(unsigned long offset);
575+
576+
double _CopyDoubleFromInt64(__int64);
577+
float _CopyFloatFromInt32(__int32);
578+
__int32 _CopyInt32FromFloat(float);
579+
__int64 _CopyInt64FromDouble(double);
580+
581+
unsigned int _CountLeadingOnes(unsigned long);
582+
unsigned int _CountLeadingOnes64(unsigned __int64);
583+
unsigned int _CountLeadingSigns(long);
584+
unsigned int _CountLeadingSigns64(__int64);
585+
unsigned int _CountLeadingZeros(unsigned long);
586+
unsigned int _CountLeadingZeros64(unsigned _int64);
587+
unsigned int _CountOneBits(unsigned long);
588+
unsigned int _CountOneBits64(unsigned __int64);
575589
#endif
576590

577591
/*----------------------------------------------------------------------------*\

clang/test/CodeGen/arm64-microsoft-intrinsics.c

+138
Original file line numberDiff line numberDiff line change
@@ -265,5 +265,143 @@ unsigned __int64 check__readx18qword(unsigned LONG offset) {
265265
// CHECK-MSCOMPAT: %[[RETVAL:.*]] = load i64, ptr %[[PTR]], align 1
266266
// CHECK-MSCOMPAT: ret i64 %[[RETVAL]]
267267

268+
double check__CopyDoubleFromInt64(__int64 arg1) {
269+
return _CopyDoubleFromInt64(arg1);
270+
}
271+
272+
// CHECK-MSCOMPAT: %[[ARG:.*]].addr = alloca i64, align 8
273+
// CHECK-MSCOMPAT: store i64 %[[ARG]], ptr %[[ARG]].addr, align 8
274+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i64, ptr %[[ARG]].addr, align 8
275+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = bitcast i64 %[[VAR0]] to double
276+
// CHECK-MSCOMPAT: ret double %[[VAR1]]
277+
// CHECK-LINUX: error: call to undeclared function '_CopyDoubleFromInt64'
278+
279+
float check__CopyFloatFromInt32(__int32 arg1) {
280+
return _CopyFloatFromInt32(arg1);
281+
}
282+
283+
// CHECK-MSCOMPAT: %[[ARG:.*]].addr = alloca i32, align 4
284+
// CHECK-MSCOMPAT: store i32 %[[ARG]], ptr %[[ARG]].addr, align 4
285+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i32, ptr %[[ARG]].addr, align 4
286+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = bitcast i32 %[[VAR0]] to float
287+
// CHECK-MSCOMPAT: ret float %[[VAR1]]
288+
// CHECK-LINUX: error: call to undeclared function '_CopyFloatFromInt32'
289+
290+
__int32 check__CopyInt32FromFloat(float arg1) {
291+
return _CopyInt32FromFloat(arg1);
292+
}
293+
294+
// CHECK-MSCOMPAT: %[[ARG:.*]].addr = alloca float, align 4
295+
// CHECK-MSCOMPAT: store float %[[ARG]], ptr %[[ARG]].addr, align 4
296+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load float, ptr %[[ARG]].addr, align 4
297+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = bitcast float %[[VAR0]] to i32
298+
// CHECK-MSCOMPAT: ret i32 %[[VAR1]]
299+
// CHECK-LINUX: error: call to undeclared function '_CopyInt32FromFloat'
300+
301+
__int64 check__CopyInt64FromDouble(double arg1) {
302+
return _CopyInt64FromDouble(arg1);
303+
}
304+
305+
// CHECK-MSCOMPAT: %[[ARG:.*]].addr = alloca double, align 8
306+
// CHECK-MSCOMPAT: store double %[[ARG]], ptr %[[ARG]].addr, align 8
307+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load double, ptr %[[ARG]].addr, align 8
308+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = bitcast double %[[VAR0]] to i64
309+
// CHECK-MSCOMPAT: ret i64 %[[VAR1]]
310+
// CHECK-LINUX: error: call to undeclared function '_CopyInt64FromDouble'
311+
312+
unsigned int check__CountLeadingOnes(unsigned LONG arg1) {
313+
return _CountLeadingOnes(arg1);
314+
}
315+
316+
// CHECK-MSCOMPAT: %[[ARG1:.*]].addr = alloca i32, align 4
317+
// CHECK-MSCOMPAT: store i32 %[[ARG1]], ptr %[[ARG1]].addr, align 4
318+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i32, ptr %[[ARG1]].addr, align 4
319+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = xor i32 %[[VAR0]], -1
320+
// CHECK-MSCOMPAT: %[[VAR2:.*]] = call i32 @llvm.ctlz.i32(i32 %1, i1 false)
321+
// CHECK-MSCOMPAT: ret i32 %[[VAR2]]
322+
// CHECK-LINUX: error: call to undeclared function '_CountLeadingOnes'
323+
324+
unsigned int check__CountLeadingOnes64(unsigned __int64 arg1) {
325+
return _CountLeadingOnes64(arg1);
326+
}
327+
328+
// CHECK-MSCOMPAT: %[[ARG1:.*]].addr = alloca i64, align 8
329+
// CHECK-MSCOMPAT: store i64 %[[ARG1]], ptr %[[ARG1]].addr, align 8
330+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i64, ptr %[[ARG1]].addr, align 8
331+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = xor i64 %[[VAR0]], -1
332+
// CHECK-MSCOMPAT: %[[VAR2:.*]] = call i64 @llvm.ctlz.i64(i64 %1, i1 false)
333+
// CHECK-MSCOMPAT: %[[VAR3:.*]] = trunc i64 %2 to i32
334+
// CHECK-MSCOMPAT: ret i32 %[[VAR3]]
335+
// CHECK-LINUX: error: call to undeclared function '_CountLeadingOnes64'
336+
337+
unsigned int check__CountLeadingSigns(__int32 arg1) {
338+
return _CountLeadingSigns(arg1);
339+
}
340+
341+
// CHECK-MSCOMPAT: %[[ARG1:.*]].addr = alloca i32, align 4
342+
// CHECK-MSCOMPAT: store i32 %[[ARG1]], ptr %[[ARG1]].addr, align 4
343+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i32, ptr %[[ARG1]].addr, align 4
344+
// CHECK-MSCOMPAT: %[[CLS:.*]] = call i32 @llvm.aarch64.cls(i32 %[[VAR0]])
345+
// CHECK-MSCOMPAT: ret i32 %[[CLS]]
346+
// CHECK-LINUX: error: call to undeclared function '_CountLeadingSigns'
347+
348+
unsigned int check__CountLeadingSigns64(__int64 arg1) {
349+
return _CountLeadingSigns64(arg1);
350+
}
351+
352+
// CHECK-MSCOMPAT: %[[ARG1:.*]].addr = alloca i64, align 8
353+
// CHECK-MSCOMPAT: store i64 %[[ARG1]], ptr %[[ARG1]].addr, align 8
354+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i64, ptr %[[ARG1]].addr, align 8
355+
// CHECK-MSCOMPAT: %[[CLS:.*]] = call i32 @llvm.aarch64.cls64(i64 %[[VAR0]])
356+
// CHECK-MSCOMPAT: ret i32 %[[CLS]]
357+
// CHECK-LINUX: error: call to undeclared function '_CountLeadingSigns64'
358+
359+
unsigned int check__CountLeadingZeros(__int32 arg1) {
360+
return _CountLeadingZeros(arg1);
361+
}
362+
363+
// CHECK-MSCOMPAT: %[[ARG1:.*]].addr = alloca i32, align 4
364+
// CHECK-MSCOMPAT: store i32 %[[ARG1]], ptr %[[ARG1]].addr, align 4
365+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i32, ptr %[[ARG1]].addr, align 4
366+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = call i32 @llvm.ctlz.i32(i32 %[[VAR0]], i1 false)
367+
// CHECK-MSCOMPAT: ret i32 %[[VAR1]]
368+
// CHECK-LINUX: error: call to undeclared function '_CountLeadingZeros'
369+
370+
unsigned int check__CountLeadingZeros64(__int64 arg1) {
371+
return _CountLeadingZeros64(arg1);
372+
}
373+
374+
// CHECK-MSCOMPAT: %[[ARG1:.*]].addr = alloca i64, align 8
375+
// CHECK-MSCOMPAT: store i64 %[[ARG1]], ptr %[[ARG1]].addr, align 8
376+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i64, ptr %[[ARG1]].addr, align 8
377+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = call i64 @llvm.ctlz.i64(i64 %[[VAR0]], i1 false)
378+
// CHECK-MSCOMPAT: %[[VAR2:.*]] = trunc i64 %[[VAR1]] to i32
379+
// CHECK-MSCOMPAT: ret i32 %[[VAR2]]
380+
// CHECK-LINUX: error: call to undeclared function '_CountLeadingZeros64'
381+
382+
unsigned int check_CountOneBits(unsigned LONG arg1) {
383+
return _CountOneBits(arg1);
384+
}
385+
386+
// CHECK-MSCOMPAT: %[[ARG1:.*]].addr = alloca i32, align 4
387+
// CHECK-MSCOMPAT: store i32 %[[ARG1]], ptr %[[ARG1]].addr, align 4
388+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i32, ptr %[[ARG1]].addr, align 4
389+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = call i32 @llvm.ctpop.i32(i32 %0)
390+
// CHECK-MSCOMPAT: ret i32 %[[VAR1]]
391+
// CHECK-LINUX: error: call to undeclared function '_CountOneBits'
392+
393+
unsigned int check_CountOneBits64(unsigned __int64 arg1) {
394+
return _CountOneBits64(arg1);
395+
}
396+
397+
// CHECK-MSCOMPAT: %[[ARG1:.*]].addr = alloca i64, align 8
398+
// CHECK-MSCOMPAT: store i64 %[[ARG1]], ptr %[[ARG1]].addr, align 8
399+
// CHECK-MSCOMPAT: %[[VAR0:.*]] = load i64, ptr %[[ARG1]].addr, align 8
400+
// CHECK-MSCOMPAT: %[[VAR1:.*]] = call i64 @llvm.ctpop.i64(i64 %0)
401+
// CHECK-MSCOMPAT: %[[VAR2:.*]] = trunc i64 %1 to i32
402+
// CHECK-MSCOMPAT: ret i32 %[[VAR2]]
403+
// CHECK-LINUX: error: call to undeclared function '_CountOneBits64'
404+
405+
268406
// CHECK-MSCOMPAT: ![[MD2]] = !{!"x18"}
269407
// CHECK-MSCOMPAT: ![[MD3]] = !{!"sp"}

0 commit comments

Comments
 (0)