diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -2071,6 +2071,9 @@ TARGET_HEADER_BUILTIN(_ReadBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_WriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__cpuid, "vi*i", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__cpuidex, "vi*ii", "nh", "intrin.h", ALL_MS_LANGUAGES, "") + TARGET_HEADER_BUILTIN(__emul, "LLiii", "nch", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__emulu, "ULLiUiUi", "nch", "intrin.h", ALL_MS_LANGUAGES, "") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -14912,6 +14912,45 @@ return EmitX86Select(*this, Ops[2], Res, Ops[1]); } + case X86::BI__cpuid: + case X86::BI__cpuidex: { + Value *FuncIdArg = EmitScalarExpr(E->getArg(1)); + Value *SubFuncIdArg = BuiltinID == X86::BI__cpuidex + ? EmitScalarExpr(E->getArg(2)) + : llvm::ConstantInt::get(Int32Ty, 0); + + // Build the assembly for the cpuid instruction + SmallString<5> Asm("cpuid"); + std::string Constraints = "={ax},={bx},={cx},={dx},{ax},{cx}"; + std::string MachineClobbers = getTarget().getClobbers(); + if (!MachineClobbers.empty()) { + Constraints += ','; + Constraints += MachineClobbers; + } + + llvm::StructType *CpuidRetTy = + llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty, Int32Ty); + llvm::FunctionType *FTy = + llvm::FunctionType::get(CpuidRetTy, {Int32Ty, Int32Ty}, false); + + llvm::InlineAsm *IA = + llvm::InlineAsm::get(FTy, Asm, Constraints, /*hasSideEffects=*/true); + llvm::Value *IACall = Builder.CreateCall(IA, {FuncIdArg, SubFuncIdArg}); + + Value *BasePtr = EmitScalarExpr(E->getArg(0)); + + for (uint32_t i = 0; i < 4; i++) { + Value *Extracted = Builder.CreateExtractValue(IACall, {i}); + Value *StorePtr = + i == 0 ? BasePtr + : Builder.CreateInBoundsGEP( + Int32Ty, BasePtr, llvm::ConstantInt::get(Int32Ty, i)); + Builder.CreateAlignedStore(Extracted, StorePtr, getIntAlign()); + } + + return nullptr; + } + case X86::BI__emul: case X86::BI__emulu: { llvm::Type *Int64Ty = llvm::IntegerType::get(getLLVMContext(), 64); diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h --- a/clang/lib/Headers/intrin.h +++ b/clang/lib/Headers/intrin.h @@ -548,13 +548,6 @@ : "=a"(__eax), "=r"(__ebx), "=c"(__ecx), "=d"(__edx) \ : "0"(__leaf), "2"(__count)) #endif -static __inline__ void __DEFAULT_FN_ATTRS __cpuid(int __info[4], int __level) { - __cpuid_count(__level, 0, __info[0], __info[1], __info[2], __info[3]); -} -static __inline__ void __DEFAULT_FN_ATTRS __cpuidex(int __info[4], int __level, - int __ecx) { - __cpuid_count(__level, __ecx, __info[0], __info[1], __info[2], __info[3]); -} static __inline__ void __DEFAULT_FN_ATTRS __halt(void) { __asm__ volatile("hlt"); } diff --git a/clang/test/CodeGen/X86/ms-x86-intrinsics.c b/clang/test/CodeGen/X86/ms-x86-intrinsics.c --- a/clang/test/CodeGen/X86/ms-x86-intrinsics.c +++ b/clang/test/CodeGen/X86/ms-x86-intrinsics.c @@ -63,6 +63,14 @@ // CHECK: [[RES:%[0-9]+]] = mul nuw i64 [[Y]], [[X]] // CHECK: ret i64 [[RES]] +void test__cpuid(int cpuInfo[4], int function_id) { + return __cpuid(cpuInfo, function_id); +} + +void test__cpuidex(int cpuInfo[4], int function_id, int subfunction_id) { + return __cpuidex(cpuInfo, function_id, subfunction_id); +} + #if defined(__x86_64__) char test__readgsbyte(unsigned long Offset) {