diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def index 1f2f9a3840..9091ad4d75 100644 --- a/include/clang/Basic/BuiltinsARM.def +++ b/include/clang/Basic/BuiltinsARM.def @@ -85,6 +85,8 @@ BUILTIN(__builtin_arm_isb, "vUi", "nc") BUILTIN(__builtin_arm_prefetch, "vvC*UiUi", "nc") // MSVC +LANGBUILTIN(__emit, "vIUiC", "", ALL_MS_LANGUAGES) + LANGBUILTIN(__yield, "v", "", ALL_MS_LANGUAGES) LANGBUILTIN(__wfe, "v", "", ALL_MS_LANGUAGES) LANGBUILTIN(__wfi, "v", "", ALL_MS_LANGUAGES) diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 155545d4c9..fca60d50c5 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -20,7 +20,9 @@ #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" using namespace clang; @@ -3165,6 +3167,26 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, if (auto Hint = GetValueForARMHint(BuiltinID)) return Hint; + if (BuiltinID == ARM::BI__emit) { + bool IsThumb = getTarget().getTriple().getArch() == llvm::Triple::thumb; + llvm::FunctionType *FTy = + llvm::FunctionType::get(VoidTy, /*Variadic=*/false); + + APSInt Value; + if (!E->getArg(0)->EvaluateAsInt(Value, CGM.getContext())) + llvm_unreachable("Sema will ensure that the parameter is constant"); + + uint64_t ZExtValue = Value.zextOrTrunc(IsThumb ? 16 : 32).getZExtValue(); + + llvm::InlineAsm *Emit = + IsThumb ? InlineAsm::get(FTy, ".inst.n 0x" + utohexstr(ZExtValue), "", + /*SideEffects=*/true) + : InlineAsm::get(FTy, ".inst 0x" + utohexstr(ZExtValue), "", + /*SideEffects=*/true); + + return Builder.CreateCall(Emit); + } + if (BuiltinID == ARM::BI__builtin_arm_dbg) { Value *Option = EmitScalarExpr(E->getArg(0)); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_dbg), Option); diff --git a/test/CodeGen/builtins-arm-msvc-compat-error.c b/test/CodeGen/builtins-arm-msvc-compat-error.c new file mode 100644 index 0000000000..29469deb6a --- /dev/null +++ b/test/CodeGen/builtins-arm-msvc-compat-error.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple thumbv7-windows -fms-extensions -verify %s + +void emit_error(unsigned int opcode) { + __emit(opcode); // expected-error {{argument to '__emit' must be a constant integer}} +} + diff --git a/test/CodeGen/builtins-arm-msvc-compat-only.c b/test/CodeGen/builtins-arm-msvc-compat-only.c new file mode 100644 index 0000000000..db82ca4066 --- /dev/null +++ b/test/CodeGen/builtins-arm-msvc-compat-only.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple thumbv7-windows -fms-extensions -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefix CHECK-MSVC +// RUN: %clang_cc1 -triple armv7-eabi -emit-llvm %s -o /dev/null 2>&1 \ +// RUN: | FileCheck %s -check-prefix CHECK-EABI +// REQUIRES: arm-registered-target + +void emit() { + __emit(0xdefe); +} + +// CHECK-MSVC: call void asm sideeffect ".inst.n 0xDEFE", ""() +// CHECK-EABI: warning: implicit declaration of function '__emit' is invalid in C99 + +void emit_truncated() { + __emit(0x11110000); // movs r0, r0 +} + +// CHECK-MSVC: call void asm sideeffect ".inst.n 0x0", ""() +