https://github.com/beakthoven updated https://github.com/llvm/llvm-project/pull/203214
>From a5a1033523a66d68cff0c904415cd102e68d4fed Mon Sep 17 00:00:00 2001 From: Dakkshesh <[email protected]> Date: Thu, 11 Jun 2026 11:50:55 +0530 Subject: [PATCH] [clang][AVR] Add basic AVR builtin functions Add builtins for nop, sei, cli, sleep, wdr, swap. These builtins lower to their llvm.avr.* intrinsics. Remaining builtins are marked as TODO. Signed-off-by: Dakkshesh <[email protected]> --- clang/include/clang/Basic/BuiltinsAVR.def | 47 ++++ clang/include/clang/Basic/TargetBuiltins.h | 12 +- clang/lib/Basic/Targets/AVR.cpp | 35 ++- clang/lib/Basic/Targets/AVR.h | 4 +- clang/lib/CodeGen/CGBuiltin.cpp | 2 + clang/lib/CodeGen/CMakeLists.txt | 1 + clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/lib/CodeGen/TargetBuiltins/AVR.cpp | 42 +++ clang/test/CodeGen/avr/avr-builtins.c | 303 ++++++++++++++++++--- clang/test/Preprocessor/avr-builtins.c | 8 + 10 files changed, 412 insertions(+), 43 deletions(-) create mode 100644 clang/include/clang/Basic/BuiltinsAVR.def create mode 100644 clang/lib/CodeGen/TargetBuiltins/AVR.cpp create mode 100644 clang/test/Preprocessor/avr-builtins.c diff --git a/clang/include/clang/Basic/BuiltinsAVR.def b/clang/include/clang/Basic/BuiltinsAVR.def new file mode 100644 index 0000000000000..78b8daefef934 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsAVR.def @@ -0,0 +1,47 @@ +//===--- BuiltinsAVR.def - AVR Builtin function database --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the AVR-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// Void instructions +BUILTIN(__builtin_avr_nop, "v", "n") +BUILTIN(__builtin_avr_sei, "v", "n") +BUILTIN(__builtin_avr_cli, "v", "n") +BUILTIN(__builtin_avr_sleep, "v", "n") +BUILTIN(__builtin_avr_wdr, "v", "n") + +// Swap nibbles +BUILTIN(__builtin_avr_swap, "UcUc", "nc") + +// TODO: +// Fractional multiply +// BUILTIN(__builtin_avr_fmul, "UiUcUc", "nc") +// BUILTIN(__builtin_avr_fmuls, "SiScSc", "nc") +// BUILTIN(__builtin_avr_fmulsu, "SiScUc", "nc") + +// Delay cycles +// BUILTIN(__builtin_avr_delay_cycles, "vULi", "n") + +// Emit N NOP instructions +// BUILTIN(__builtin_avr_nops, "vUi", "n") + +// Bit manipulation +// BUILTIN(__builtin_avr_insert_bits, "UcULiUcUc", "nc") + +// Flash segment query +// BUILTIN(__builtin_avr_flash_segment, "ScvC*", "nc") + +// __builtin_avr_mask1 +// __builtin_avr_strlen_flash +// __builtin_avr_strlen_flashx +// __builtin_avr_strlen_memx + +#undef BUILTIN diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h index 9b4613c853206..2c6d007e45ead 100644 --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -476,12 +476,22 @@ namespace clang { }; } + /// AVR builtins + namespace AVR { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsAVR.def" + LastTSBuiltin + }; + } + static constexpr uint64_t LargestBuiltinID = std::max<uint64_t>( {ARM::LastTSBuiltin, AArch64::LastTSBuiltin, BPF::LastTSBuiltin, PPC::LastTSBuiltin, NVPTX::LastTSBuiltin, AMDGPU::LastTSBuiltin, X86::LastTSBuiltin, VE::LastTSBuiltin, RISCV::LastTSBuiltin, Hexagon::LastTSBuiltin, Mips::LastTSBuiltin, XCore::LastTSBuiltin, - SystemZ::LastTSBuiltin, WebAssembly::LastTSBuiltin}); + SystemZ::LastTSBuiltin, WebAssembly::LastTSBuiltin, AVR::LastTSBuiltin}); } // end namespace clang. diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp index 75144099b2bdd..227651a2ab6fa 100644 --- a/clang/lib/Basic/Targets/AVR.cpp +++ b/clang/lib/Basic/Targets/AVR.cpp @@ -11,12 +11,28 @@ //===----------------------------------------------------------------------===// #include "AVR.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; using namespace clang::targets; +static constexpr int NumBuiltins = AVR::LastTSBuiltin - Builtin::FirstTSBuiltin; + +static constexpr llvm::StringTable BuiltinStrings = + CLANG_BUILTIN_STR_TABLE_START +#define BUILTIN CLANG_BUILTIN_STR_TABLE +#include "clang/Basic/BuiltinsAVR.def" + ; + +static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({ +#define BUILTIN CLANG_BUILTIN_ENTRY +#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY +#include "clang/Basic/BuiltinsAVR.def" +}); + namespace clang { namespace targets { @@ -471,8 +487,13 @@ static bool ArchHas3BytePC(StringRef Arch) { } bool AVRTargetInfo::isValidCPUName(StringRef Name) const { - return llvm::any_of( - AVRMcus, [&](const MCUInfo &Info) { return Info.Name == Name; }); + return llvm::any_of(AVRMcus, + [&](const MCUInfo &Info) { return Info.Name == Name; }); +} + +llvm::SmallVector<Builtin::InfosShard> +AVRTargetInfo::getTargetBuiltins() const { + return {{&BuiltinStrings, BuiltinInfos}}; } void AVRTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { @@ -524,7 +545,7 @@ void AVRTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__AVR_TINY__", "1"); if (DefineName.size() != 0) - Builder.defineMacro(DefineName); + Builder.defineMacro(DefineName); Builder.defineMacro("__AVR_ARCH__", Arch); @@ -564,4 +585,12 @@ void AVRTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__flash4", "__attribute__((__address_space__(5)))"); if (NumFlashBanks >= 6) Builder.defineMacro("__flash5", "__attribute__((__address_space__(6)))"); + + // Define macros for builtins + Builder.defineMacro("__BUILTIN_AVR_NOP", "1"); + Builder.defineMacro("__BUILTIN_AVR_SEI", "1"); + Builder.defineMacro("__BUILTIN_AVR_CLI", "1"); + Builder.defineMacro("__BUILTIN_AVR_WDR", "1"); + Builder.defineMacro("__BUILTIN_AVR_SLEEP", "1"); + Builder.defineMacro("__BUILTIN_AVR_SWAP", "1"); } diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h index f6fed1d97c9ea..211cf90fe9fb2 100644 --- a/clang/lib/Basic/Targets/AVR.h +++ b/clang/lib/Basic/Targets/AVR.h @@ -63,9 +63,7 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override { - return {}; - } + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; bool allowsLargerPreferedTypeAlignment() const override { return false; } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 682b125890fe1..509ab4245d99a 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -133,6 +133,8 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF, [[fallthrough]]; case llvm::Triple::spirv: return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E); + case llvm::Triple::avr: + return CGF->EmitAVRBuiltinExpr(BuiltinID, E); default: return nullptr; } diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 75b2f5826f863..479967ee0a230 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -122,6 +122,7 @@ add_clang_library(clangCodeGen SanitizerMetadata.cpp SwiftCallingConv.cpp TargetBuiltins/ARM.cpp + TargetBuiltins/AVR.cpp TargetBuiltins/AMDGPU.cpp TargetBuiltins/DirectX.cpp TargetBuiltins/Hexagon.cpp diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 6bb9f285ebcfd..e1af1d281764a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4965,6 +4965,7 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitHexagonBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitAVRBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); diff --git a/clang/lib/CodeGen/TargetBuiltins/AVR.cpp b/clang/lib/CodeGen/TargetBuiltins/AVR.cpp new file mode 100644 index 0000000000000..a9860c03a091f --- /dev/null +++ b/clang/lib/CodeGen/TargetBuiltins/AVR.cpp @@ -0,0 +1,42 @@ +//===------ AVR.cpp - Emit LLVM Code for AVR builtins ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Builtin calls as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CGBuiltin.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/IntrinsicsAVR.h" + +using namespace clang; +using namespace CodeGen; +using namespace llvm; + +Value *CodeGenFunction::EmitAVRBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + switch (BuiltinID) { + default: + return nullptr; + case AVR::BI__builtin_avr_nop: + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::avr_nop)); + case AVR::BI__builtin_avr_sei: + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::avr_sei)); + case AVR::BI__builtin_avr_cli: + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::avr_cli)); + case AVR::BI__builtin_avr_sleep: + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::avr_sleep)); + case AVR::BI__builtin_avr_wdr: + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::avr_wdr)); + case AVR::BI__builtin_avr_swap: { + Value *Arg0 = EmitScalarExpr(E->getArg(0)); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::avr_swap), Arg0); + } + } +} diff --git a/clang/test/CodeGen/avr/avr-builtins.c b/clang/test/CodeGen/avr/avr-builtins.c index 7c2c424848080..cd844d85a005f 100644 --- a/clang/test/CodeGen/avr/avr-builtins.c +++ b/clang/test/CodeGen/avr/avr-builtins.c @@ -1,127 +1,358 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 // RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm -o - %s | FileCheck %s // Check that the parameter types match. This verifies pr43309. // RUN: %clang_cc1 -triple avr-unknown-unknown -Wconversion -verify %s // expected-no-diagnostics +// CHECK-LABEL: define dso_local i8 @bitrev8( +// CHECK-SAME: i8 noundef zeroext [[DATA:%.*]]) addrspace(1) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[DATA_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[DATA]], ptr [[DATA_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[DATA_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = call addrspace(1) i8 @llvm.bitreverse.i8(i8 [[TMP0]]) +// CHECK-NEXT: ret i8 [[TMP1]] +// unsigned char bitrev8(unsigned char data) { return __builtin_bitreverse8(data); } -// CHECK: define{{.*}} i8 @bitrev8 -// CHECK: i8 @llvm.bitreverse.i8(i8 +// CHECK-LABEL: define dso_local i16 @bitrev16( +// CHECK-SAME: i16 noundef [[DATA:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[DATA_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: store i16 [[DATA]], ptr [[DATA_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[DATA_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = call addrspace(1) i16 @llvm.bitreverse.i16(i16 [[TMP0]]) +// CHECK-NEXT: ret i16 [[TMP1]] +// unsigned int bitrev16(unsigned int data) { return __builtin_bitreverse16(data); } -// CHECK: define{{.*}} i16 @bitrev16 -// CHECK: i16 @llvm.bitreverse.i16(i16 +// CHECK-LABEL: define dso_local i32 @bitrev32( +// CHECK-SAME: i32 noundef [[DATA:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[DATA_ADDR:%.*]] = alloca i32, align 1 +// CHECK-NEXT: store i32 [[DATA]], ptr [[DATA_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[DATA_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = call addrspace(1) i32 @llvm.bitreverse.i32(i32 [[TMP0]]) +// CHECK-NEXT: ret i32 [[TMP1]] +// unsigned long bitrev32(unsigned long data) { return __builtin_bitreverse32(data); } -// CHECK: define{{.*}} i32 @bitrev32 -// CHECK: i32 @llvm.bitreverse.i32(i32 +// CHECK-LABEL: define dso_local i64 @bitrev64( +// CHECK-SAME: i64 noundef [[DATA:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[DATA_ADDR:%.*]] = alloca i64, align 1 +// CHECK-NEXT: store i64 [[DATA]], ptr [[DATA_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[DATA_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = call addrspace(1) i64 @llvm.bitreverse.i64(i64 [[TMP0]]) +// CHECK-NEXT: ret i64 [[TMP1]] +// unsigned long long bitrev64(unsigned long long data) { return __builtin_bitreverse64(data); } -// CHECK: define{{.*}} i64 @bitrev64 -// CHECK: i64 @llvm.bitreverse.i64(i64 +// CHECK-LABEL: define dso_local i8 @rotleft8( +// CHECK-SAME: i8 noundef zeroext [[X:%.*]], i8 noundef zeroext [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i8 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = urem i8 [[TMP1]], 8 +// CHECK-NEXT: [[TMP3:%.*]] = call addrspace(1) i8 @llvm.fshl.i8(i8 [[TMP0]], i8 [[TMP0]], i8 [[TMP2]]) +// CHECK-NEXT: ret i8 [[TMP3]] +// unsigned char rotleft8(unsigned char x, unsigned char y) { return __builtin_rotateleft8(x, y); } -// CHECK: define{{.*}} i8 @rotleft8 -// CHECK: i8 @llvm.fshl.i8(i8 +// CHECK-LABEL: define dso_local i16 @rotleft16( +// CHECK-SAME: i16 noundef [[X:%.*]], i16 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i16 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = urem i16 [[TMP1]], 16 +// CHECK-NEXT: [[TMP3:%.*]] = call addrspace(1) i16 @llvm.fshl.i16(i16 [[TMP0]], i16 [[TMP0]], i16 [[TMP2]]) +// CHECK-NEXT: ret i16 [[TMP3]] +// unsigned int rotleft16(unsigned int x, unsigned int y) { return __builtin_rotateleft16(x, y); } -// CHECK: define{{.*}} i16 @rotleft16 -// CHECK: i16 @llvm.fshl.i16(i16 +// CHECK-LABEL: define dso_local i32 @rotleft32( +// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i32, align 1 +// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i32 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 32 +// CHECK-NEXT: [[TMP3:%.*]] = call addrspace(1) i32 @llvm.fshl.i32(i32 [[TMP0]], i32 [[TMP0]], i32 [[TMP2]]) +// CHECK-NEXT: ret i32 [[TMP3]] +// unsigned long rotleft32(unsigned long x, unsigned long y) { return __builtin_rotateleft32(x, y); } -// CHECK: define{{.*}} i32 @rotleft32 -// CHECK: i32 @llvm.fshl.i32(i32 +// CHECK-LABEL: define dso_local i64 @rotleft64( +// CHECK-SAME: i64 noundef [[X:%.*]], i64 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i64, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i64, align 1 +// CHECK-NEXT: store i64 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i64 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = urem i64 [[TMP1]], 64 +// CHECK-NEXT: [[TMP3:%.*]] = call addrspace(1) i64 @llvm.fshl.i64(i64 [[TMP0]], i64 [[TMP0]], i64 [[TMP2]]) +// CHECK-NEXT: ret i64 [[TMP3]] +// unsigned long long rotleft64(unsigned long long x, unsigned long long y) { return __builtin_rotateleft64(x, y); } -// CHECK: define{{.*}} i64 @rotleft64 -// CHECK: i64 @llvm.fshl.i64(i64 +// CHECK-LABEL: define dso_local i8 @rotright8( +// CHECK-SAME: i8 noundef zeroext [[X:%.*]], i8 noundef zeroext [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i8 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = urem i8 [[TMP1]], 8 +// CHECK-NEXT: [[TMP3:%.*]] = call addrspace(1) i8 @llvm.fshr.i8(i8 [[TMP0]], i8 [[TMP0]], i8 [[TMP2]]) +// CHECK-NEXT: ret i8 [[TMP3]] +// unsigned char rotright8(unsigned char x, unsigned char y) { return __builtin_rotateright8(x, y); } -// CHECK: define{{.*}} i8 @rotright8 -// CHECK: i8 @llvm.fshr.i8(i8 +// CHECK-LABEL: define dso_local i16 @rotright16( +// CHECK-SAME: i16 noundef [[X:%.*]], i16 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i16 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = urem i16 [[TMP1]], 16 +// CHECK-NEXT: [[TMP3:%.*]] = call addrspace(1) i16 @llvm.fshr.i16(i16 [[TMP0]], i16 [[TMP0]], i16 [[TMP2]]) +// CHECK-NEXT: ret i16 [[TMP3]] +// unsigned int rotright16(unsigned int x, unsigned int y) { return __builtin_rotateright16(x, y); } -// CHECK: define{{.*}} i16 @rotright16 -// CHECK: i16 @llvm.fshr.i16(i16 +// CHECK-LABEL: define dso_local i32 @rotright32( +// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i32, align 1 +// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i32 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 32 +// CHECK-NEXT: [[TMP3:%.*]] = call addrspace(1) i32 @llvm.fshr.i32(i32 [[TMP0]], i32 [[TMP0]], i32 [[TMP2]]) +// CHECK-NEXT: ret i32 [[TMP3]] +// unsigned long rotright32(unsigned long x, unsigned long y) { return __builtin_rotateright32(x, y); } -// CHECK: define{{.*}} i32 @rotright32 -// CHECK: i32 @llvm.fshr.i32(i32 +// CHECK-LABEL: define dso_local i64 @rotright64( +// CHECK-SAME: i64 noundef [[X:%.*]], i64 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i64, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i64, align 1 +// CHECK-NEXT: store i64 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i64 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = urem i64 [[TMP1]], 64 +// CHECK-NEXT: [[TMP3:%.*]] = call addrspace(1) i64 @llvm.fshr.i64(i64 [[TMP0]], i64 [[TMP0]], i64 [[TMP2]]) +// CHECK-NEXT: ret i64 [[TMP3]] +// unsigned long long rotright64(unsigned long long x, unsigned long long y) { return __builtin_rotateright64(x, y); } -// CHECK: define{{.*}} i64 @rotright64 -// CHECK: i64 @llvm.fshr.i64(i64 +// CHECK-LABEL: define dso_local i16 @byteswap16( +// CHECK-SAME: i16 noundef [[X:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = call addrspace(1) i16 @llvm.bswap.i16(i16 [[TMP0]]) +// CHECK-NEXT: ret i16 [[TMP1]] +// unsigned int byteswap16(unsigned int x) { return __builtin_bswap16(x); } -// CHECK: define{{.*}} i16 @byteswap16 -// CHECK: i16 @llvm.bswap.i16(i16 +// CHECK-LABEL: define dso_local i32 @byteswap32( +// CHECK-SAME: i32 noundef [[X:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 1 +// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = call addrspace(1) i32 @llvm.bswap.i32(i32 [[TMP0]]) +// CHECK-NEXT: ret i32 [[TMP1]] +// unsigned long byteswap32(unsigned long x) { return __builtin_bswap32(x); } -// CHECK: define{{.*}} i32 @byteswap32 -// CHECK: i32 @llvm.bswap.i32(i32 +// CHECK-LABEL: define dso_local i64 @byteswap64( +// CHECK-SAME: i64 noundef [[X:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i64, align 1 +// CHECK-NEXT: store i64 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = call addrspace(1) i64 @llvm.bswap.i64(i64 [[TMP0]]) +// CHECK-NEXT: ret i64 [[TMP1]] +// unsigned long long byteswap64(unsigned long long x) { return __builtin_bswap64(x); } -// CHECK: define{{.*}} i64 @byteswap64 -// CHECK: i64 @llvm.bswap.i64(i64 +// CHECK-LABEL: define dso_local float @powi( +// CHECK-SAME: float noundef [[X:%.*]], i16 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i16 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = call addrspace(1) float @llvm.powi.f32.i16(float [[TMP0]], i16 [[TMP1]]) +// CHECK-NEXT: ret float [[TMP2]] +// double powi(double x, int y) { return __builtin_powi(x, y); } -// CHECK: define{{.*}} float @powi -// CHECK: float @llvm.powi.f32.i16(float %0, i16 %1) +// CHECK-LABEL: define dso_local float @powif( +// CHECK-SAME: float noundef [[X:%.*]], i16 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i16 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = call addrspace(1) float @llvm.powi.f32.i16(float [[TMP0]], i16 [[TMP1]]) +// CHECK-NEXT: ret float [[TMP2]] +// float powif(float x, int y) { return __builtin_powif(x, y); } -// CHECK: define{{.*}} float @powif -// CHECK: float @llvm.powi.f32.i16(float %0, i16 %1) +// CHECK-LABEL: define dso_local float @powil( +// CHECK-SAME: float noundef [[X:%.*]], i16 noundef [[Y:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 1 +// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i16, align 1 +// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: store i16 [[Y]], ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[Y_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = call addrspace(1) float @llvm.powi.f32.i16(float [[TMP0]], i16 [[TMP1]]) +// CHECK-NEXT: ret float [[TMP2]] +// long double powil(long double x, int y) { return __builtin_powil(x, y); } -// CHECK: define{{.*}} float @powil -// CHECK: float @llvm.powi.f32.i16(float %0, i16 %1) + +// CHECK-LABEL: define dso_local void @test_nop( +// CHECK-SAME: ) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: call addrspace(1) void @llvm.avr.nop() +// CHECK-NEXT: ret void +// +void test_nop(void) { + __builtin_avr_nop(); +} + +// CHECK-LABEL: define dso_local void @test_sei( +// CHECK-SAME: ) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: call addrspace(1) void @llvm.avr.sei() +// CHECK-NEXT: ret void +// +void test_sei(void) { + __builtin_avr_sei(); +} + +// CHECK-LABEL: define dso_local void @test_cli( +// CHECK-SAME: ) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: call addrspace(1) void @llvm.avr.cli() +// CHECK-NEXT: ret void +// +void test_cli(void) { + __builtin_avr_cli(); +} + +// CHECK-LABEL: define dso_local void @test_sleep( +// CHECK-SAME: ) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: call addrspace(1) void @llvm.avr.sleep() +// CHECK-NEXT: ret void +// +void test_sleep(void) { + __builtin_avr_sleep(); +} + +// CHECK-LABEL: define dso_local void @test_wdr( +// CHECK-SAME: ) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: call addrspace(1) void @llvm.avr.wdr() +// CHECK-NEXT: ret void +// +void test_wdr(void) { + __builtin_avr_wdr(); +} + +// CHECK-LABEL: define dso_local i8 @test_swap( +// CHECK-SAME: i8 noundef zeroext [[A:%.*]]) addrspace(1) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[A]], ptr [[A_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = call addrspace(1) i8 @llvm.avr.swap(i8 [[TMP0]]) +// CHECK-NEXT: ret i8 [[TMP1]] +// +unsigned char test_swap(unsigned char a) { + return __builtin_avr_swap(a); +} \ No newline at end of file diff --git a/clang/test/Preprocessor/avr-builtins.c b/clang/test/Preprocessor/avr-builtins.c new file mode 100644 index 0000000000000..8a0190bde08b3 --- /dev/null +++ b/clang/test/Preprocessor/avr-builtins.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -E -dM -triple avr-unknown-unknown -target-cpu atmega328p %s | FileCheck %s + +// CHECK: #define __BUILTIN_AVR_CLI 1 +// CHECK: #define __BUILTIN_AVR_NOP 1 +// CHECK: #define __BUILTIN_AVR_SEI 1 +// CHECK: #define __BUILTIN_AVR_SLEEP 1 +// CHECK: #define __BUILTIN_AVR_SWAP 1 +// CHECK: #define __BUILTIN_AVR_WDR 1 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
