https://github.com/beakthoven updated https://github.com/llvm/llvm-project/pull/203214
>From 332868c021c7531cb15ab3d19d3ec47e3f4e7def Mon Sep 17 00:00:00 2001 From: Dakkshesh <[email protected]> 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 <[email protected]> --- 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 <[email protected]> Date: Fri, 12 Jun 2026 11:37:13 +0530 Subject: [PATCH 2/2] [clang][AVR] Format test files Signed-off-by: Dakkshesh <[email protected]> --- 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) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
