llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-codegen

Author: Dakkshesh (beakthoven)

<details>
<summary>Changes</summary>

Add builtins for nop, sei, cli, sleep, wdr, swap, fmul/fmuls/fmulsu, 
delay_cycles, and nops. The builtins lower to their llvm.avr.* intrinsics, fmul 
variants use inline asm, anddelay_cycles emits inline-asm delay loops.

depends on: https://github.com/llvm/llvm-project/pull/203212

TODO:
**__builtin_avr_insert_bits
__builtin_avr_flash_segment**

---

Patch is 22.94 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/203214.diff


12 Files Affected:

- (added) clang/include/clang/Basic/BuiltinsAVR.def (+39) 
- (modified) clang/include/clang/Basic/TargetBuiltins.h (+11-1) 
- (modified) clang/lib/Basic/Targets/AVR.cpp (+37-3) 
- (modified) clang/lib/Basic/Targets/AVR.h (+1-3) 
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+2) 
- (modified) clang/lib/CodeGen/CMakeLists.txt (+1) 
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+1) 
- (added) clang/lib/CodeGen/TargetBuiltins/AVR.cpp (+247) 
- (modified) clang/lib/Sema/SemaChecking.cpp (+22) 
- (modified) clang/test/CodeGen/avr/avr-builtins.c (+91) 
- (added) clang/test/Preprocessor/avr-builtins.c (+13) 
- (added) clang/test/Sema/avr-builtins.c (+19) 


``````````diff
diff --git a/clang/include/clang/Basic/BuiltinsAVR.def 
b/clang/include/clang/Basic/BuiltinsAVR.def
new file mode 100644
index 0000000000000..c0d883c39d3bc
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsAVR.def
@@ -0,0 +1,39 @@
+//===--- 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")
+
+// 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")
+
+// TODO builtins
+// BUILTIN(__builtin_avr_insert_bits, "UcULiUcUc", "nc")
+// BUILTIN(__builtin_avr_flash_segment, "c*v", "n")
+
+#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..a04fea33997a7 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,17 @@ 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");
+  Builder.defineMacro("__BUILTIN_AVR_FMUL", "1");
+  Builder.defineMacro("__BUILTIN_AVR_FMULS", "1");
+  Builder.defineMacro("__BUILTIN_AVR_FMULSU", "1");
+  Builder.defineMacro("__BUILTIN_AVR_DELAY_CYCLES", "1");
+  Builder.defineMacro("__BUILTIN_AVR_NOPS", "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..3f95806585206
--- /dev/null
+++ b/clang/lib/CodeGen/TargetBuiltins/AVR.cpp
@@ -0,0 +1,247 @@
+//===------ 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;
+
+/// Emit an inline-asm-based fractional multiply (fmul/fmuls/fmulsu).
+/// All three variants share the same shape: two i8 inputs → one i16 output,
+/// with the result collected from R1:R0 via movw, then R1 cleared.
+static Value *EmitAVRFMulInlineAsm(CodeGenFunction &CGF, const CallExpr *E,
+                                   const char *AsmInsn) {
+  Value *Arg0 = CGF.EmitScalarExpr(E->getArg(0));
+  Value *Arg1 = CGF.EmitScalarExpr(E->getArg(1));
+  llvm::LLVMContext &Ctx = CGF.getLLVMContext();
+  llvm::Type *ResTy = llvm::Type::getInt16Ty(Ctx);
+  llvm::Type *ArgTy = llvm::Type::getInt8Ty(Ctx);
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(ResTy, {ArgTy, ArgTy}, false);
+
+  // Build the asm string: "<insn> $1, $2\n\tmovw $0, r0\n\tclr r1"
+  std::string Asm = std::string(AsmInsn) + " $1, $2\n\tmovw $0, r0\n\tclr r1";
+  llvm::InlineAsm *IA =
+      llvm::InlineAsm::get(FTy, Asm, "=r,a,a,~{r0},~{r1}", true);
+  return CGF.Builder.CreateCall(IA, {Arg0, Arg1});
+}
+
+/// Emit __builtin_avr_delay_cycles(N).
+///
+/// Generates an optimal sequence of inline assembly delay loops and NOPs
+/// to consume exactly N clock cycles.
+///
+/// The decomposed N into a sum of contributions from nested loops
+/// of decreasing register width, then fills the remainder with rjmp/.+0
+/// (2 cycles) and nop (1 cycle).
+///
+/// Loop types:
+///   4-byte loop: ldi×4 + (subi + sbci×3 + brne) = 9 setup + 6/iter
+///   3-byte loop: ldi×3 + (subi + sbci×2 + brne) = 7 setup + 5/iter
+///   2-byte loop: ldi×2 + (sbiw + brne)           = 5 setup + 4/iter
+///   1-byte loop: ldi   + (dec  + brne)            = 3/iter (no setup 
overhead)
+static Value *EmitAVRDelayLoops(CodeGenFunction &CGF, uint32_t Cycles) {
+  if (Cycles == 0)
+    return nullptr;
+
+  std::string Asm;
+  std::string Clobbers;
+  unsigned ClobberIdx = 0;
+  unsigned LabelIdx = 1;
+
+  auto AddClobber = [&](unsigned Reg) {
+    if (!Clobbers.empty())
+      Clobbers += ",";
+    Clobbers += "~{r" + std::to_string(Reg) + "}";
+  };
+
+  // 4-byte loop: 9 + 6*(loop_count-1) cycles
+  // ldi×4 + (subi + sbci×3 + brne) per iteration
+  if (Cycles >= 83886082u) {
+    uint32_t LoopCount = ((Cycles - 9) / 6) + 1;
+    uint32_t Used = ((LoopCount - 1) * 6) + 9;
+    unsigned Base = 16 + ClobberIdx;
+    std::string L = std::to_string(LabelIdx++);
+    Asm += "ldi r" + std::to_string(Base) + ", lo8(" +
+           std::to_string(LoopCount) + ")\n\t";
+    Asm += "ldi r" + std::to_string(Base + 1) + ", hi8(" +
+           std::to_string(LoopCount) + ")\n\t";
+    Asm += "ldi r" + std::to_string(Base + 2) + ", hlo8(" +
+           std::to_string(LoopCount) + ")\n\t";
+    Asm += "ldi r" + std::to_string(Base + 3) + ", hhi8(" +
+           std::to_string(LoopCount) + ")\n\t";
+    Asm += L + ": subi r" + std::to_string(Base) + ", 1\n\t";
+    Asm += "sbci r" + std::to_string(Base + 1) + ", 0\n\t";
+    Asm += "sbci r" + std::to_string(Base + 2) + ", 0\n\t";
+    Asm += "sbci r" + std::to_string(Base + 3) + ", 0\n\t";
+    Asm += "brne " + L + "b\n\t";
+    AddClobber(Base);
+    AddClobber(Base + 1);
+    AddClobber(Base + 2);
+    AddClobber(Base + 3);
+    ClobberIdx += 4;
+    Cycles -= Used;
+  }
+
+  // 3-byte loop: 7 + 5*(loop_count-1) cycles
+  // ldi×3 + (subi + sbci×2 + brne) per iteration
+  if (Cycles >= 262145u) {
+    uint32_t LoopCount = ((Cycles - 7) / 5) + 1;
+    if (LoopCount > 0xFFFFFFu)
+      LoopCount = 0xFFFFFFu;
+    uint32_t Used = ((LoopCount - 1) * 5) + 7;
+    unsigned Base = 16 + ClobberIdx;
+    std::string L = std::to_string(LabelIdx++);
+    Asm += "ldi r" + std::to_string(Base) + ", lo8(" +
+           std::to_string(LoopCount) + ")\n\t";
+    Asm += "ldi r" + std::to_string(Base + 1) + ", hi8(" +
+           std::to_string(LoopCount) + ")\n\t";
+    Asm += "ldi r" + std::to_string(Base + 2) + ", hlo8(" +
+           std::to_string(LoopCount) + ")\n\t";
+    Asm += L + ": subi r" + std::to_string(Base) + ", 1\n\t";
+    Asm += "sbci r" + std::to_string(Base + 1) + ", 0\n\t";
+    Asm += "sbci r" + std::to_string(Base + 2) + ", 0\n\t";
+    Asm += "brne " + L + "b\n\t";
+    AddClobber(Base);
+    AddClobber(Base + 1);
+    AddClobber(Base + 2);
+    ClobberIdx += 3;
+    Cycles -= Used;
+  }
+
+  // 2-byte loop: 5 + 4*(loop_count-1) cycles
+  // ldi×2 + (sbiw + brne) per iteration
+  // sbiw requires an even register in {r24, r26, r28, r30}.
+  if (Cycles >= 768u) {
+    uint32_t LoopCount = ((Cycles - 5) / 4) + 1;
+    if (LoopCount > 0xFFFFu)
+      LoopCount = 0xFFFFu;
+    uint32_t Used = ((LoopCount - 1) * 4) + 5;
+    std::string L = std::to_string(LabelIdx++);
+    // Use r24:r25 for sbiw (hardcoded per AVR ISA constraint).
+    Asm += "ldi r24, lo8(" + std::to_string(LoopCount) + ")\n\t";
+    Asm += "ldi r25, hi8(" + std::to_string(LoopCount) + ")\n\t";
+    Asm += L + ": sbiw r24, 1\n\t";
+    Asm += "brne " + L + "b\n\t";
+    AddClobber(24);
+    AddClobber(25);
+    Cycles -= Used;
+  }
+
+  // 1-byte loop: 3*loop_count cycles
+  // ldi + (dec + brne) per iteration
+  if (Cycles >= 6u) {
+    uint32_t LoopCount = Cycles / 3;
+    if (LoopCount > 255u)
+      LoopCount = 255u;
+    uint32_t Used = LoopCount * 3;
+    unsigned Reg = 16 + ClobberIdx;
+    if (Reg > 31)
+      Reg = 31; // safety
+    std::string L = std::to_string(LabelIdx++);
+    Asm += "ldi r" + std::to_string(Reg) + ", " + std::to_string(LoopCount) +
+           "\n\t";
+    Asm += L + ": dec r" + std::to_string(Reg) + "\n\t";
+    Asm += "brne " + L + "b\n\t";
+    AddClobber(Reg);
+    ClobberIdx++;
+    Cycles -= Used;
+  }
+
+  // Fill remaining with rjmp .+0 (2 cycles each)
+  while (Cycles >= 2) {
+    Asm += "rjmp .+0\n\t";
+    Cycles -= 2;
+  }
+
+  // Final single cycle
+  if (Cycles == 1) {
+    Asm += "nop\n\t";
+  }
+
+  if (Asm.empty())
+    return nullptr;
+
+  // Remove trailing \n\t
+  if (Asm.size() >= 3 && Asm.substr(Asm.size() - 3) == "\n\t")
+    Asm.resize(Asm.size() - 3);
+
+  llvm::LLVMContext &Ctx = CGF.getLLVMContext();
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
+  llvm::InlineAsm *IA = llvm::InlineAsm::get(FTy, Asm, Clobbers, true);
+  return CGF.Builder.CreateCall(IA);
+}
+
+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);
+  }
+  case AVR::BI__builtin_avr_fmul:
+    return EmitAVRFMulInlineAsm(*this, E, "fmul");
+  case AVR::BI__builtin_avr_fmuls:
+    return EmitAVRFMulInlineAsm(*this, E, "fmuls");
+  case AVR::BI__builtin_avr_fmulsu:
+    return EmitAVRFMulInlineAsm(*this, E, "fmulsu");
+
+  case AVR::BI__builtin_avr_delay_cycles: {
+    // Argument is validated as a compile time constant in Sema.
+    Expr::EvalResult Result;
+    E->getArg(0)->EvaluateAsInt(Result, getContext());
+    uint32_t Cycles = 
static_cast<uint32_t>(Result.Val.getInt().getZExtValue());
+    if (Cycles == 0) {
+      // Nothing to emit.
+      llvm::FunctionType *FTy = llvm::FunctionType::get(
+          llvm::Type::getVoidTy(getLLVMContext()), false);
+      return Builder.CreateCall(llvm::InlineAsm::get(FTy, "", "", true));
+    }
+    return EmitAVRDelayLoops(*this, Cycles);
+  }
+
+  case AVR::BI__builtin_avr_nops: {
+    // Argument is validated as a compile-time constant in Sema.
+    Expr::EvalResult Result;
+    E->getArg(0)->EvaluateAsInt(Result, getContext());
+    uint32_t N = static_cast<uint32_t>(Result.Val.getInt().getZExtValue());
+    if (N == 0) {
+      // Nothing to emit.
+      llvm::FunctionType *FTy = llvm::FunctionType::get(
+          llvm::Type::getVoidTy(getLLVMContext()), false);
+      return Builder.CreateCall(llvm::InlineAsm::get(FTy, "", "", true));
+    }
+    llvm::Function *NopFn = CGM.getIntrinsic(Intrinsic::avr_nop);
+    Value *Last = nullptr;
+    for (uint32_t I = 0; I < N; ++I)
+      Last = Builder.CreateCall(NopFn);
+    return Last;
+  }
+  }
+}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b8a3f48a32f24..be634f64807c7 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -53,6 +53,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/SyncScope.h"
+#include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TypeTraits.h"
 #include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
@@ -2124,6 +2125,27 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo 
&TI, unsigned BuiltinID,
     // Some builtins don't require additional checking, so just consider these
     // acceptable.
     return false;
+  case llvm::Triple::avr: {
+    switch (BuiltinID) {
+    default:
+      return false;
+    case AVR::BI__builtin_avr_delay_cycles: {
+      llvm::APSInt Result;
+      if (BuiltinConstantArg(TheCall, 0, Result))
+        return true;
+      if (Result.isNegative())
+        return Diag(TheCall->getArg(0)->getBeginLoc(),
+                    diag::err_argument_invalid_range)
+               << toString(Result, 10) << (unsigned)0 << (unsigned)UINT32_MAX
+               << TheCall->getArg(0)->getSourceRange();
+      return false;
+    }
+    case AVR::BI__builtin_avr_nops: {
+      llvm::APSInt Result;
+      return BuiltinConstantArg(TheCall, 0, Result);
+    }
+    }
+  }
   case llvm::Triple::arm:
   case llvm::Triple::armeb:
   case llvm::Triple::thumb:
diff --git a/clang/test/CodeGen/avr/avr-builtins.c 
b/clang/test/CodeGen/avr/avr-builtins.c
index 7c2c424848080..fee56ccadc81e 100644
--- a/clang/test/CodeGen/avr/avr-builtins.c
+++ b/clang/test/CodeGen/avr/avr-builtins.c
@@ -125,3 +125,94 @@ long double powil(long double x, int y) {
 
 // CHECK: define{{.*}} float @powil
 // CHECK: float @llvm.powi.f32.i16(float %0, i16 %1)
+
+// CHECK-LABEL: define{{.*}} void @test_nop()
+void test_nop(void) {
+  // CHECK: call{{.*}} void @llvm.avr.nop()
+  __builtin_avr_nop();
+}
+
+// CHECK-LABEL: define{{.*}} void @test_sei()
+void test_sei(void) {
+  // CHECK: call{{.*}} void @llvm.avr.sei()
+  __builtin_avr_sei();
+}
+
+// CHECK-LABEL: define{{.*}} void @test_cli()
+void test_cli(void) {
+  // CHECK: call{{.*}} void @llvm.avr.cli()
+  __builtin_avr_cli();
+}
+
+// CHECK-LABEL: define{{.*}} void @test_sleep()
+void test_sleep(void) {
+  // CHECK: call{{.*}} void @llvm.avr.sleep()
+  __builtin_avr_sleep();
+}
+
+// CHECK-LABEL: define{{.*}} void @test_wdr()
+void test_wdr(void) {
+  // CHECK: call{{.*}} void @llvm.avr.wdr()
+  __builtin_avr_wdr();
+}
+
+// CHECK-LABEL: define{{.*}} i8 @test_swap
+unsigned char test_swap(unsigned char a) {
+  // CHECK: call{{.*}} i8 @llvm.avr.swap(i8
+  return __builtin_avr_swap(a);
+}
+
+// CHECK-LABEL: define{{.*}} i16 @test_fmul
+unsigned int test_fmul(unsigned char a, unsigned char b) {
+  // CHECK: call{{.*}} i16 asm sideeffect "fmul $1, $2
+  return __builtin_avr_fmul(a, b);
+}
+
+// CHECK-LABEL: define{{.*}} i16 @test_fmuls
+int test_fmuls(signed char a, signed char b) {
+  // CHECK: call{{.*}} i16 asm sideeffect ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/203214
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to