[clang] [clang][AVR] Add AVR-specific builtin functions (PR #203214)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 11 23:07:53 PDT 2026
https://github.com/beakthoven updated https://github.com/llvm/llvm-project/pull/203214
>From 332868c021c7531cb15ab3d19d3ec47e3f4e7def Mon Sep 17 00:00:00 2001
From: Dakkshesh <beakthoven at gmail.com>
Date: Thu, 11 Jun 2026 11:50:55 +0530
Subject: [PATCH 1/2] [clang][AVR] Add AVR-specific builtin functions
Add builtins for nop, sei, cli, sleep, wdr, swap, fmul/fmuls/fmulsu,
delay_cycles, nops, insert_bits, and flash_segment.
The builtins lower to their llvm.avr.* intrinsics, fmul variants use
inline asm, delay_cycles emits inline-asm delay loops, insert_bits
expands to bitwise shifts and masks based on a compile-time map, and
flash_segment resolves to a constant based on the pointer address space.
Signed-off-by: Dakkshesh <beakthoven at gmail.com>
---
clang/include/clang/Basic/BuiltinsAVR.def | 47 ++++
clang/include/clang/Basic/TargetBuiltins.h | 12 +-
clang/lib/Basic/Targets/AVR.cpp | 42 ++-
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 | 303 +++++++++++++++++++++
clang/lib/Sema/SemaChecking.cpp | 23 ++
clang/test/CodeGen/avr/avr-builtins.c | 131 +++++++++
clang/test/Preprocessor/avr-builtins.c | 15 +
clang/test/Sema/avr-builtins.c | 32 +++
12 files changed, 606 insertions(+), 7 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
create mode 100644 clang/test/Sema/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..e157ebff8159a
--- /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")
+
+// 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")
+
+// TODO
+// __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..e4d174c43e775 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,19 @@ 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");
+ Builder.defineMacro("__BUILTIN_AVR_FLASH_SEGMENT", "1");
+ Builder.defineMacro("__BUILTIN_AVR_INSERT_BITS", "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..bb7b4fc459479
--- /dev/null
+++ b/clang/lib/CodeGen/TargetBuiltins/AVR.cpp
@@ -0,0 +1,303 @@
+//===------ 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;
+ }
+ case AVR::BI__builtin_avr_insert_bits: {
+ // Map is a compile-time constant (validated in Sema).
+ Expr::EvalResult MapResult;
+ E->getArg(0)->EvaluateAsInt(MapResult, getContext());
+ uint32_t Map =
+ static_cast<uint32_t>(MapResult.Val.getInt().getZExtValue());
+ Value *Bits = EmitScalarExpr(E->getArg(1));
+ Value *Val = EmitScalarExpr(E->getArg(2));
+
+ llvm::Type *I8Ty = Builder.getInt8Ty();
+ Value *Result = llvm::ConstantInt::get(I8Ty, 0);
+
+ for (unsigned I = 0; I < 8; ++I) {
+ unsigned Nibble = (Map >> (I * 4)) & 0xF;
+ Value *Bit;
+ if (Nibble < 8) {
+ // Extract bit 'Nibble' from 'Bits' and place it at position 'I'.
+ Bit = Builder.CreateAnd(
+ Builder.CreateLShr(Bits, llvm::ConstantInt::get(I8Ty, Nibble)),
+ llvm::ConstantInt::get(I8Ty, 1));
+ } else if (Nibble == 0xF) {
+ // Keep bit 'I' from 'Val'.
+ Bit = Builder.CreateAnd(
+ Builder.CreateLShr(Val, llvm::ConstantInt::get(I8Ty, I)),
+ llvm::ConstantInt::get(I8Ty, 1));
+ } else {
+ // Nibble 8-14: undefined per GCC docs, treat as 0.
+ continue;
+ }
+ Value *Shifted =
+ Builder.CreateShl(Bit, llvm::ConstantInt::get(I8Ty, I));
+ Result = Builder.CreateOr(Result, Shifted);
+ }
+ return Result;
+ }
+
+ case AVR::BI__builtin_avr_flash_segment: {
+ // Extract the address space from the pointer argument's type.
+ // __flash = addrspace(1) -> segment 0
+ // __flash1 = addrspace(2) -> segment 1
+ // ...
+ // __flash5 = addrspace(6) -> segment 5
+ // Non-flash (addrspace 0 or >6) -> -1
+ QualType ArgTy = E->getArg(0)->getType();
+ int8_t Segment = -1;
+ if (ArgTy->isPointerType()) {
+ LangAS AS = ArgTy->getPointeeType().getAddressSpace();
+ if (isTargetAddressSpace(AS)) {
+ unsigned TargetAS = toTargetAddressSpace(AS);
+ if (TargetAS >= 1 && TargetAS <= 6)
+ Segment = static_cast<int8_t>(TargetAS - 1);
+ }
+ }
+ return llvm::ConstantInt::get(Builder.getInt8Ty(), Segment,
+ /*IsSigned=*/true);
+ }
+ }
+}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b8a3f48a32f24..c467f7165b723 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,28 @@ 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_insert_bits:
+ 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..3af77f1cae7d0 100644
--- a/clang/test/CodeGen/avr/avr-builtins.c
+++ b/clang/test/CodeGen/avr/avr-builtins.c
@@ -125,3 +125,134 @@ 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 "fmuls $1, $2
+ return __builtin_avr_fmuls(a, b);
+}
+
+// CHECK-LABEL: define{{.*}} i16 @test_fmulsu
+int test_fmulsu(signed char a, unsigned char b) {
+ // CHECK: call{{.*}} i16 asm sideeffect "fmulsu $1, $2
+ return __builtin_avr_fmulsu(a, b);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_nops()
+void test_nops(void) {
+ // CHECK: call{{.*}} void @llvm.avr.nop()
+ // CHECK-NEXT: call{{.*}} void @llvm.avr.nop()
+ // CHECK-NEXT: call{{.*}} void @llvm.avr.nop()
+ __builtin_avr_nops(3);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_delay_cycles_small()
+void test_delay_cycles_small(void) {
+ // 1 cycle = 1 nop
+ // CHECK: call{{.*}} void asm sideeffect "nop
+ __builtin_avr_delay_cycles(1);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_delay_cycles_two()
+void test_delay_cycles_two(void) {
+ // 2 cycles = rjmp .+0
+ // CHECK: call{{.*}} void asm sideeffect "rjmp .+0
+ __builtin_avr_delay_cycles(2);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_delay_cycles_loop()
+void test_delay_cycles_loop(void) {
+ // 12 cycles: 1-byte loop (4 iters = 12 cycles)
+ // CHECK: call{{.*}} void asm sideeffect "ldi{{.*}}dec{{.*}}brne
+ __builtin_avr_delay_cycles(12);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_delay_cycles_zero()
+void test_delay_cycles_zero(void) {
+ // 0 cycles = empty inline asm
+ // CHECK: call{{.*}} void asm sideeffect "", ""()
+ __builtin_avr_delay_cycles(0);
+}
+
+// CHECK-LABEL: define{{.*}} i8 @test_insert_bits_identity
+unsigned char test_insert_bits_identity(unsigned char bits, unsigned char val) {
+ // Identity map: 0x76543210 — each nibble N maps bit N from 'bits'
+ // CHECK: lshr
+ // CHECK: and
+ // CHECK: or
+ return __builtin_avr_insert_bits(0x76543210UL, bits, val);
+}
+
+// CHECK-LABEL: define{{.*}} i8 @test_insert_bits_reverse
+unsigned char test_insert_bits_reverse(unsigned char bits) {
+ // Reverse map: 0x01234567 — reverses the bit order
+ // CHECK: lshr
+ // CHECK: and
+ return __builtin_avr_insert_bits(0x01234567UL, bits, 0);
+}
+
+// CHECK-LABEL: define{{.*}} i8 @test_insert_bits_keep_val
+unsigned char test_insert_bits_keep_val(unsigned char val) {
+ // 0xFFFFFFFF — all nibbles are 0xF, keep all bits from 'val'
+ // CHECK: lshr
+ // CHECK: and
+ return __builtin_avr_insert_bits(0xFFFFFFFFUL, 0, val);
+}
+
+// CHECK-LABEL: define{{.*}} i8 @test_flash_segment_flash
+signed char test_flash_segment_flash(void) {
+ const __attribute__((address_space(1))) unsigned char *p = 0;
+ // __flash = addrspace(1), segment 0
+ // CHECK: ret i8 0
+ return __builtin_avr_flash_segment(p);
+}
+
+// CHECK-LABEL: define{{.*}} i8 @test_flash_segment_ram
+signed char test_flash_segment_ram(void) {
+ const unsigned char *p = 0;
+ // RAM = addrspace(0), segment -1
+ // CHECK: ret i8 -1
+ return __builtin_avr_flash_segment(p);
+}
diff --git a/clang/test/Preprocessor/avr-builtins.c b/clang/test/Preprocessor/avr-builtins.c
new file mode 100644
index 0000000000000..6b82a30401716
--- /dev/null
+++ b/clang/test/Preprocessor/avr-builtins.c
@@ -0,0 +1,15 @@
+// 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_DELAY_CYCLES 1
+// CHECK: #define __BUILTIN_AVR_FLASH_SEGMENT 1
+// CHECK: #define __BUILTIN_AVR_FMUL 1
+// CHECK: #define __BUILTIN_AVR_FMULS 1
+// CHECK: #define __BUILTIN_AVR_FMULSU 1
+// CHECK: #define __BUILTIN_AVR_INSERT_BITS 1
+// CHECK: #define __BUILTIN_AVR_NOP 1
+// CHECK: #define __BUILTIN_AVR_NOPS 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
diff --git a/clang/test/Sema/avr-builtins.c b/clang/test/Sema/avr-builtins.c
new file mode 100644
index 0000000000000..e389a03a38f96
--- /dev/null
+++ b/clang/test/Sema/avr-builtins.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple avr-unknown-unknown -fsyntax-only -verify %s
+
+void test_delay_cycles_variable(unsigned long n) {
+ __builtin_avr_delay_cycles(n); // expected-error {{argument to '__builtin_avr_delay_cycles' must be a constant integer}}
+}
+
+void test_delay_cycles_ok(void) {
+ __builtin_avr_delay_cycles(100); // ok
+ __builtin_avr_delay_cycles(0); // ok
+}
+
+void test_nops_variable(unsigned int n) {
+ __builtin_avr_nops(n); // expected-error {{argument to '__builtin_avr_nops' must be a constant integer}}
+}
+
+void test_nops_ok(void) {
+ __builtin_avr_nops(5); // ok
+ __builtin_avr_nops(0); // ok
+}
+
+void test_insert_bits_variable(unsigned long map, unsigned char bits,
+ unsigned char val) {
+ __builtin_avr_insert_bits(map, bits, val); // expected-error {{argument to '__builtin_avr_insert_bits' must be a constant integer}}
+}
+
+unsigned char test_insert_bits_ok(unsigned char bits, unsigned char val) {
+ unsigned char r;
+ r = __builtin_avr_insert_bits(0x76543210UL, bits, val); // ok
+ r = __builtin_avr_insert_bits(0xFFFFFFFFUL, 0, val); // ok
+ r = __builtin_avr_insert_bits(0x01234567UL, bits, 0); // ok
+ return r;
+}
>From f603008ce9c91ea552c72d8e2d487a7272c7dba8 Mon Sep 17 00:00:00 2001
From: Dakkshesh <beakthoven at gmail.com>
Date: Fri, 12 Jun 2026 11:37:13 +0530
Subject: [PATCH 2/2] [clang][AVR] Format test files
Signed-off-by: Dakkshesh <beakthoven at gmail.com>
---
clang/test/CodeGen/avr/avr-builtins.c | 528 ++++++++++++++++++++++----
clang/test/Sema/avr-builtins.c | 1 +
2 files changed, 449 insertions(+), 80 deletions(-)
diff --git a/clang/test/CodeGen/avr/avr-builtins.c b/clang/test/CodeGen/avr/avr-builtins.c
index 3af77f1cae7d0..d393c4f81ac6c 100644
--- a/clang/test/CodeGen/avr/avr-builtins.c
+++ b/clang/test/CodeGen/avr/avr-builtins.c
@@ -1,258 +1,626 @@
+// 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{{.*}} void @test_nop()
+// 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) {
- // CHECK: call{{.*}} void @llvm.avr.nop()
__builtin_avr_nop();
}
-// CHECK-LABEL: define{{.*}} void @test_sei()
+// 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) {
- // CHECK: call{{.*}} void @llvm.avr.sei()
__builtin_avr_sei();
}
-// CHECK-LABEL: define{{.*}} void @test_cli()
+// 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) {
- // CHECK: call{{.*}} void @llvm.avr.cli()
__builtin_avr_cli();
}
-// CHECK-LABEL: define{{.*}} void @test_sleep()
+// 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) {
- // CHECK: call{{.*}} void @llvm.avr.sleep()
__builtin_avr_sleep();
}
-// CHECK-LABEL: define{{.*}} void @test_wdr()
+// 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) {
- // CHECK: call{{.*}} void @llvm.avr.wdr()
__builtin_avr_wdr();
}
-// CHECK-LABEL: define{{.*}} i8 @test_swap
+// 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) {
- // CHECK: call{{.*}} i8 @llvm.avr.swap(i8
return __builtin_avr_swap(a);
}
-// CHECK-LABEL: define{{.*}} i16 @test_fmul
+// CHECK-LABEL: define dso_local i16 @test_fmul(
+// CHECK-SAME: i8 noundef zeroext [[A:%.*]], i8 noundef zeroext [[B:%.*]]) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: store i8 [[A]], ptr [[A_ADDR]], align 1
+// CHECK-NEXT: store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1
+// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT: [[TMP2:%.*]] = call addrspace(0) i16 asm sideeffect "fmul $1, $2\0A\09movw $0, r0\0A\09clr r1", "=r,a,a,~{r0},~{r1}"(i8 [[TMP0]], i8 [[TMP1]])
+// CHECK-NEXT: ret i16 [[TMP2]]
+//
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
+// CHECK-LABEL: define dso_local i16 @test_fmuls(
+// CHECK-SAME: i8 noundef signext [[A:%.*]], i8 noundef signext [[B:%.*]]) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: store i8 [[A]], ptr [[A_ADDR]], align 1
+// CHECK-NEXT: store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1
+// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT: [[TMP2:%.*]] = call addrspace(0) i16 asm sideeffect "fmuls $1, $2\0A\09movw $0, r0\0A\09clr r1", "=r,a,a,~{r0},~{r1}"(i8 [[TMP0]], i8 [[TMP1]])
+// CHECK-NEXT: ret i16 [[TMP2]]
+//
int test_fmuls(signed char a, signed char b) {
- // CHECK: call{{.*}} i16 asm sideeffect "fmuls $1, $2
return __builtin_avr_fmuls(a, b);
}
-// CHECK-LABEL: define{{.*}} i16 @test_fmulsu
+// CHECK-LABEL: define dso_local i16 @test_fmulsu(
+// CHECK-SAME: i8 noundef signext [[A:%.*]], i8 noundef zeroext [[B:%.*]]) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: store i8 [[A]], ptr [[A_ADDR]], align 1
+// CHECK-NEXT: store i8 [[B]], ptr [[B_ADDR]], align 1
+// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1
+// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
+// CHECK-NEXT: [[TMP2:%.*]] = call addrspace(0) i16 asm sideeffect "fmulsu $1, $2\0A\09movw $0, r0\0A\09clr r1", "=r,a,a,~{r0},~{r1}"(i8 [[TMP0]], i8 [[TMP1]])
+// CHECK-NEXT: ret i16 [[TMP2]]
+//
int test_fmulsu(signed char a, unsigned char b) {
- // CHECK: call{{.*}} i16 asm sideeffect "fmulsu $1, $2
return __builtin_avr_fmulsu(a, b);
}
-// CHECK-LABEL: define{{.*}} void @test_nops()
+// CHECK-LABEL: define dso_local void @test_nops(
+// CHECK-SAME: ) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: call addrspace(1) void @llvm.avr.nop()
+// CHECK-NEXT: call addrspace(1) void @llvm.avr.nop()
+// CHECK-NEXT: call addrspace(1) void @llvm.avr.nop()
+// CHECK-NEXT: ret void
+//
void test_nops(void) {
- // CHECK: call{{.*}} void @llvm.avr.nop()
- // CHECK-NEXT: call{{.*}} void @llvm.avr.nop()
- // CHECK-NEXT: call{{.*}} void @llvm.avr.nop()
__builtin_avr_nops(3);
}
-// CHECK-LABEL: define{{.*}} void @test_delay_cycles_small()
+// CHECK-LABEL: define dso_local void @test_delay_cycles_small(
+// CHECK-SAME: ) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: call addrspace(0) void asm sideeffect "nop\0A\09", ""()
+// CHECK-NEXT: ret void
+//
void test_delay_cycles_small(void) {
// 1 cycle = 1 nop
- // CHECK: call{{.*}} void asm sideeffect "nop
__builtin_avr_delay_cycles(1);
}
-// CHECK-LABEL: define{{.*}} void @test_delay_cycles_two()
+// CHECK-LABEL: define dso_local void @test_delay_cycles_two(
+// CHECK-SAME: ) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: call addrspace(0) void asm sideeffect "rjmp .+0\0A\09", ""()
+// CHECK-NEXT: ret void
+//
void test_delay_cycles_two(void) {
// 2 cycles = rjmp .+0
- // CHECK: call{{.*}} void asm sideeffect "rjmp .+0
__builtin_avr_delay_cycles(2);
}
-// CHECK-LABEL: define{{.*}} void @test_delay_cycles_loop()
+// CHECK-LABEL: define dso_local void @test_delay_cycles_loop(
+// CHECK-SAME: ) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: call addrspace(0) void asm sideeffect "ldi r16, 4\0A\091: dec r16\0A\09brne 1b\0A\09", "~{r16}"()
+// CHECK-NEXT: ret void
+//
void test_delay_cycles_loop(void) {
// 12 cycles: 1-byte loop (4 iters = 12 cycles)
- // CHECK: call{{.*}} void asm sideeffect "ldi{{.*}}dec{{.*}}brne
__builtin_avr_delay_cycles(12);
}
-// CHECK-LABEL: define{{.*}} void @test_delay_cycles_zero()
+// CHECK-LABEL: define dso_local void @test_delay_cycles_zero(
+// CHECK-SAME: ) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: call addrspace(0) void asm sideeffect "", ""()
+// CHECK-NEXT: ret void
+//
void test_delay_cycles_zero(void) {
// 0 cycles = empty inline asm
- // CHECK: call{{.*}} void asm sideeffect "", ""()
__builtin_avr_delay_cycles(0);
}
-// CHECK-LABEL: define{{.*}} i8 @test_insert_bits_identity
+// CHECK-LABEL: define dso_local i8 @test_insert_bits_identity(
+// CHECK-SAME: i8 noundef zeroext [[BITS:%.*]], i8 noundef zeroext [[VAL:%.*]]) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[BITS_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: store i8 [[BITS]], ptr [[BITS_ADDR]], align 1
+// CHECK-NEXT: store i8 [[VAL]], ptr [[VAL_ADDR]], align 1
+// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[BITS_ADDR]], align 1
+// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[VAL_ADDR]], align 1
+// CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP0]], 0
+// CHECK-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 1
+// CHECK-NEXT: [[TMP4:%.*]] = shl i8 [[TMP3]], 0
+// CHECK-NEXT: [[TMP5:%.*]] = or i8 0, [[TMP4]]
+// CHECK-NEXT: [[TMP6:%.*]] = lshr i8 [[TMP0]], 1
+// CHECK-NEXT: [[TMP7:%.*]] = and i8 [[TMP6]], 1
+// CHECK-NEXT: [[TMP8:%.*]] = shl i8 [[TMP7]], 1
+// CHECK-NEXT: [[TMP9:%.*]] = or i8 [[TMP5]], [[TMP8]]
+// CHECK-NEXT: [[TMP10:%.*]] = lshr i8 [[TMP0]], 2
+// CHECK-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 1
+// CHECK-NEXT: [[TMP12:%.*]] = shl i8 [[TMP11]], 2
+// CHECK-NEXT: [[TMP13:%.*]] = or i8 [[TMP9]], [[TMP12]]
+// CHECK-NEXT: [[TMP14:%.*]] = lshr i8 [[TMP0]], 3
+// CHECK-NEXT: [[TMP15:%.*]] = and i8 [[TMP14]], 1
+// CHECK-NEXT: [[TMP16:%.*]] = shl i8 [[TMP15]], 3
+// CHECK-NEXT: [[TMP17:%.*]] = or i8 [[TMP13]], [[TMP16]]
+// CHECK-NEXT: [[TMP18:%.*]] = lshr i8 [[TMP0]], 4
+// CHECK-NEXT: [[TMP19:%.*]] = and i8 [[TMP18]], 1
+// CHECK-NEXT: [[TMP20:%.*]] = shl i8 [[TMP19]], 4
+// CHECK-NEXT: [[TMP21:%.*]] = or i8 [[TMP17]], [[TMP20]]
+// CHECK-NEXT: [[TMP22:%.*]] = lshr i8 [[TMP0]], 5
+// CHECK-NEXT: [[TMP23:%.*]] = and i8 [[TMP22]], 1
+// CHECK-NEXT: [[TMP24:%.*]] = shl i8 [[TMP23]], 5
+// CHECK-NEXT: [[TMP25:%.*]] = or i8 [[TMP21]], [[TMP24]]
+// CHECK-NEXT: [[TMP26:%.*]] = lshr i8 [[TMP0]], 6
+// CHECK-NEXT: [[TMP27:%.*]] = and i8 [[TMP26]], 1
+// CHECK-NEXT: [[TMP28:%.*]] = shl i8 [[TMP27]], 6
+// CHECK-NEXT: [[TMP29:%.*]] = or i8 [[TMP25]], [[TMP28]]
+// CHECK-NEXT: [[TMP30:%.*]] = lshr i8 [[TMP0]], 7
+// CHECK-NEXT: [[TMP31:%.*]] = and i8 [[TMP30]], 1
+// CHECK-NEXT: [[TMP32:%.*]] = shl i8 [[TMP31]], 7
+// CHECK-NEXT: [[TMP33:%.*]] = or i8 [[TMP29]], [[TMP32]]
+// CHECK-NEXT: ret i8 [[TMP33]]
+//
unsigned char test_insert_bits_identity(unsigned char bits, unsigned char val) {
// Identity map: 0x76543210 — each nibble N maps bit N from 'bits'
- // CHECK: lshr
- // CHECK: and
- // CHECK: or
return __builtin_avr_insert_bits(0x76543210UL, bits, val);
}
-// CHECK-LABEL: define{{.*}} i8 @test_insert_bits_reverse
+// CHECK-LABEL: define dso_local i8 @test_insert_bits_reverse(
+// CHECK-SAME: i8 noundef zeroext [[BITS:%.*]]) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[BITS_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: store i8 [[BITS]], ptr [[BITS_ADDR]], align 1
+// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[BITS_ADDR]], align 1
+// CHECK-NEXT: [[TMP1:%.*]] = lshr i8 [[TMP0]], 7
+// CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], 1
+// CHECK-NEXT: [[TMP3:%.*]] = shl i8 [[TMP2]], 0
+// CHECK-NEXT: [[TMP4:%.*]] = or i8 0, [[TMP3]]
+// CHECK-NEXT: [[TMP5:%.*]] = lshr i8 [[TMP0]], 6
+// CHECK-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 1
+// CHECK-NEXT: [[TMP7:%.*]] = shl i8 [[TMP6]], 1
+// CHECK-NEXT: [[TMP8:%.*]] = or i8 [[TMP4]], [[TMP7]]
+// CHECK-NEXT: [[TMP9:%.*]] = lshr i8 [[TMP0]], 5
+// CHECK-NEXT: [[TMP10:%.*]] = and i8 [[TMP9]], 1
+// CHECK-NEXT: [[TMP11:%.*]] = shl i8 [[TMP10]], 2
+// CHECK-NEXT: [[TMP12:%.*]] = or i8 [[TMP8]], [[TMP11]]
+// CHECK-NEXT: [[TMP13:%.*]] = lshr i8 [[TMP0]], 4
+// CHECK-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], 1
+// CHECK-NEXT: [[TMP15:%.*]] = shl i8 [[TMP14]], 3
+// CHECK-NEXT: [[TMP16:%.*]] = or i8 [[TMP12]], [[TMP15]]
+// CHECK-NEXT: [[TMP17:%.*]] = lshr i8 [[TMP0]], 3
+// CHECK-NEXT: [[TMP18:%.*]] = and i8 [[TMP17]], 1
+// CHECK-NEXT: [[TMP19:%.*]] = shl i8 [[TMP18]], 4
+// CHECK-NEXT: [[TMP20:%.*]] = or i8 [[TMP16]], [[TMP19]]
+// CHECK-NEXT: [[TMP21:%.*]] = lshr i8 [[TMP0]], 2
+// CHECK-NEXT: [[TMP22:%.*]] = and i8 [[TMP21]], 1
+// CHECK-NEXT: [[TMP23:%.*]] = shl i8 [[TMP22]], 5
+// CHECK-NEXT: [[TMP24:%.*]] = or i8 [[TMP20]], [[TMP23]]
+// CHECK-NEXT: [[TMP25:%.*]] = lshr i8 [[TMP0]], 1
+// CHECK-NEXT: [[TMP26:%.*]] = and i8 [[TMP25]], 1
+// CHECK-NEXT: [[TMP27:%.*]] = shl i8 [[TMP26]], 6
+// CHECK-NEXT: [[TMP28:%.*]] = or i8 [[TMP24]], [[TMP27]]
+// CHECK-NEXT: [[TMP29:%.*]] = lshr i8 [[TMP0]], 0
+// CHECK-NEXT: [[TMP30:%.*]] = and i8 [[TMP29]], 1
+// CHECK-NEXT: [[TMP31:%.*]] = shl i8 [[TMP30]], 7
+// CHECK-NEXT: [[TMP32:%.*]] = or i8 [[TMP28]], [[TMP31]]
+// CHECK-NEXT: ret i8 [[TMP32]]
+//
unsigned char test_insert_bits_reverse(unsigned char bits) {
// Reverse map: 0x01234567 — reverses the bit order
- // CHECK: lshr
- // CHECK: and
return __builtin_avr_insert_bits(0x01234567UL, bits, 0);
}
-// CHECK-LABEL: define{{.*}} i8 @test_insert_bits_keep_val
+// CHECK-LABEL: define dso_local i8 @test_insert_bits_keep_val(
+// CHECK-SAME: i8 noundef zeroext [[VAL:%.*]]) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT: store i8 [[VAL]], ptr [[VAL_ADDR]], align 1
+// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[VAL_ADDR]], align 1
+// CHECK-NEXT: [[TMP1:%.*]] = lshr i8 [[TMP0]], 0
+// CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], 1
+// CHECK-NEXT: [[TMP3:%.*]] = shl i8 [[TMP2]], 0
+// CHECK-NEXT: [[TMP4:%.*]] = or i8 0, [[TMP3]]
+// CHECK-NEXT: [[TMP5:%.*]] = lshr i8 [[TMP0]], 1
+// CHECK-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 1
+// CHECK-NEXT: [[TMP7:%.*]] = shl i8 [[TMP6]], 1
+// CHECK-NEXT: [[TMP8:%.*]] = or i8 [[TMP4]], [[TMP7]]
+// CHECK-NEXT: [[TMP9:%.*]] = lshr i8 [[TMP0]], 2
+// CHECK-NEXT: [[TMP10:%.*]] = and i8 [[TMP9]], 1
+// CHECK-NEXT: [[TMP11:%.*]] = shl i8 [[TMP10]], 2
+// CHECK-NEXT: [[TMP12:%.*]] = or i8 [[TMP8]], [[TMP11]]
+// CHECK-NEXT: [[TMP13:%.*]] = lshr i8 [[TMP0]], 3
+// CHECK-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], 1
+// CHECK-NEXT: [[TMP15:%.*]] = shl i8 [[TMP14]], 3
+// CHECK-NEXT: [[TMP16:%.*]] = or i8 [[TMP12]], [[TMP15]]
+// CHECK-NEXT: [[TMP17:%.*]] = lshr i8 [[TMP0]], 4
+// CHECK-NEXT: [[TMP18:%.*]] = and i8 [[TMP17]], 1
+// CHECK-NEXT: [[TMP19:%.*]] = shl i8 [[TMP18]], 4
+// CHECK-NEXT: [[TMP20:%.*]] = or i8 [[TMP16]], [[TMP19]]
+// CHECK-NEXT: [[TMP21:%.*]] = lshr i8 [[TMP0]], 5
+// CHECK-NEXT: [[TMP22:%.*]] = and i8 [[TMP21]], 1
+// CHECK-NEXT: [[TMP23:%.*]] = shl i8 [[TMP22]], 5
+// CHECK-NEXT: [[TMP24:%.*]] = or i8 [[TMP20]], [[TMP23]]
+// CHECK-NEXT: [[TMP25:%.*]] = lshr i8 [[TMP0]], 6
+// CHECK-NEXT: [[TMP26:%.*]] = and i8 [[TMP25]], 1
+// CHECK-NEXT: [[TMP27:%.*]] = shl i8 [[TMP26]], 6
+// CHECK-NEXT: [[TMP28:%.*]] = or i8 [[TMP24]], [[TMP27]]
+// CHECK-NEXT: [[TMP29:%.*]] = lshr i8 [[TMP0]], 7
+// CHECK-NEXT: [[TMP30:%.*]] = and i8 [[TMP29]], 1
+// CHECK-NEXT: [[TMP31:%.*]] = shl i8 [[TMP30]], 7
+// CHECK-NEXT: [[TMP32:%.*]] = or i8 [[TMP28]], [[TMP31]]
+// CHECK-NEXT: ret i8 [[TMP32]]
+//
unsigned char test_insert_bits_keep_val(unsigned char val) {
// 0xFFFFFFFF — all nibbles are 0xF, keep all bits from 'val'
- // CHECK: lshr
- // CHECK: and
return __builtin_avr_insert_bits(0xFFFFFFFFUL, 0, val);
}
-// CHECK-LABEL: define{{.*}} i8 @test_flash_segment_flash
+// CHECK-LABEL: define dso_local i8 @test_flash_segment_flash(
+// CHECK-SAME: ) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[P:%.*]] = alloca ptr addrspace(1), align 1
+// CHECK-NEXT: store ptr addrspace(1) null, ptr [[P]], align 1
+// CHECK-NEXT: ret i8 0
+//
signed char test_flash_segment_flash(void) {
const __attribute__((address_space(1))) unsigned char *p = 0;
// __flash = addrspace(1), segment 0
- // CHECK: ret i8 0
return __builtin_avr_flash_segment(p);
}
-// CHECK-LABEL: define{{.*}} i8 @test_flash_segment_ram
+// CHECK-LABEL: define dso_local i8 @test_flash_segment_ram(
+// CHECK-SAME: ) addrspace(1) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[P:%.*]] = alloca ptr, align 1
+// CHECK-NEXT: store ptr null, ptr [[P]], align 1
+// CHECK-NEXT: ret i8 -1
+//
signed char test_flash_segment_ram(void) {
const unsigned char *p = 0;
// RAM = addrspace(0), segment -1
- // CHECK: ret i8 -1
return __builtin_avr_flash_segment(p);
}
diff --git a/clang/test/Sema/avr-builtins.c b/clang/test/Sema/avr-builtins.c
index e389a03a38f96..f501354e951cf 100644
--- a/clang/test/Sema/avr-builtins.c
+++ b/clang/test/Sema/avr-builtins.c
@@ -1,3 +1,4 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
// RUN: %clang_cc1 -triple avr-unknown-unknown -fsyntax-only -verify %s
void test_delay_cycles_variable(unsigned long n) {
More information about the cfe-commits
mailing list