diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/CodeGen/Targets/AVR.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/CodeGen/Targets/AVR.cpp | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/CodeGen/Targets/AVR.cpp b/contrib/llvm-project/clang/lib/CodeGen/Targets/AVR.cpp new file mode 100644 index 000000000000..50547dd6dec5 --- /dev/null +++ b/contrib/llvm-project/clang/lib/CodeGen/Targets/AVR.cpp @@ -0,0 +1,154 @@ +//===- AVR.cpp ------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "ABIInfoImpl.h" +#include "TargetInfo.h" +#include "clang/Basic/DiagnosticFrontend.h" + +using namespace clang; +using namespace clang::CodeGen; + +//===----------------------------------------------------------------------===// +// AVR ABI Implementation. Documented at +// https://gcc.gnu.org/wiki/avr-gcc#Calling_Convention +// https://gcc.gnu.org/wiki/avr-gcc#Reduced_Tiny +//===----------------------------------------------------------------------===// + +namespace { +class AVRABIInfo : public DefaultABIInfo { +private: + // The total amount of registers can be used to pass parameters. It is 18 on + // AVR, or 6 on AVRTiny. + const unsigned ParamRegs; + // The total amount of registers can be used to pass return value. It is 8 on + // AVR, or 4 on AVRTiny. + const unsigned RetRegs; + +public: + AVRABIInfo(CodeGenTypes &CGT, unsigned NPR, unsigned NRR) + : DefaultABIInfo(CGT), ParamRegs(NPR), RetRegs(NRR) {} + + ABIArgInfo classifyReturnType(QualType Ty, bool &LargeRet) const { + // On AVR, a return struct with size less than or equals to 8 bytes is + // returned directly via registers R18-R25. On AVRTiny, a return struct + // with size less than or equals to 4 bytes is returned directly via + // registers R22-R25. + if (isAggregateTypeForABI(Ty) && + getContext().getTypeSize(Ty) <= RetRegs * 8) + return ABIArgInfo::getDirect(); + // A return value (struct or scalar) with larger size is returned via a + // stack slot, along with a pointer as the function's implicit argument. + if (getContext().getTypeSize(Ty) > RetRegs * 8) { + LargeRet = true; + return getNaturalAlignIndirect(Ty); + } + // An i8 return value should not be extended to i16, since AVR has 8-bit + // registers. + if (Ty->isIntegralOrEnumerationType() && getContext().getTypeSize(Ty) <= 8) + return ABIArgInfo::getDirect(); + // Otherwise we follow the default way which is compatible. + return DefaultABIInfo::classifyReturnType(Ty); + } + + ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegs) const { + unsigned TySize = getContext().getTypeSize(Ty); + + // An int8 type argument always costs two registers like an int16. + if (TySize == 8 && NumRegs >= 2) { + NumRegs -= 2; + return ABIArgInfo::getExtend(Ty); + } + + // If the argument size is an odd number of bytes, round up the size + // to the next even number. + TySize = llvm::alignTo(TySize, 16); + + // Any type including an array/struct type can be passed in rgisters, + // if there are enough registers left. + if (TySize <= NumRegs * 8) { + NumRegs -= TySize / 8; + return ABIArgInfo::getDirect(); + } + + // An argument is passed either completely in registers or completely in + // memory. Since there are not enough registers left, current argument + // and all other unprocessed arguments should be passed in memory. + // However we still need to return `ABIArgInfo::getDirect()` other than + // `ABIInfo::getNaturalAlignIndirect(Ty)`, otherwise an extra stack slot + // will be allocated, so the stack frame layout will be incompatible with + // avr-gcc. + NumRegs = 0; + return ABIArgInfo::getDirect(); + } + + void computeInfo(CGFunctionInfo &FI) const override { + // Decide the return type. + bool LargeRet = false; + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), LargeRet); + + // Decide each argument type. The total number of registers can be used for + // arguments depends on several factors: + // 1. Arguments of varargs functions are passed on the stack. This applies + // even to the named arguments. So no register can be used. + // 2. Total 18 registers can be used on avr and 6 ones on avrtiny. + // 3. If the return type is a struct with too large size, two registers + // (out of 18/6) will be cost as an implicit pointer argument. + unsigned NumRegs = ParamRegs; + if (FI.isVariadic()) + NumRegs = 0; + else if (LargeRet) + NumRegs -= 2; + for (auto &I : FI.arguments()) + I.info = classifyArgumentType(I.type, NumRegs); + } +}; + +class AVRTargetCodeGenInfo : public TargetCodeGenInfo { +public: + AVRTargetCodeGenInfo(CodeGenTypes &CGT, unsigned NPR, unsigned NRR) + : TargetCodeGenInfo(std::make_unique<AVRABIInfo>(CGT, NPR, NRR)) {} + + LangAS getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const override { + // Check if global/static variable is defined in address space + // 1~6 (__flash, __flash1, __flash2, __flash3, __flash4, __flash5) + // but not constant. + if (D) { + LangAS AS = D->getType().getAddressSpace(); + if (isTargetAddressSpace(AS) && 1 <= toTargetAddressSpace(AS) && + toTargetAddressSpace(AS) <= 6 && !D->getType().isConstQualified()) + CGM.getDiags().Report(D->getLocation(), + diag::err_verify_nonconst_addrspace) + << "__flash*"; + } + return TargetCodeGenInfo::getGlobalVarAddressSpace(CGM, D); + } + + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &CGM) const override { + if (GV->isDeclaration()) + return; + const auto *FD = dyn_cast_or_null<FunctionDecl>(D); + if (!FD) return; + auto *Fn = cast<llvm::Function>(GV); + + if (FD->getAttr<AVRInterruptAttr>()) + Fn->addFnAttr("interrupt"); + + if (FD->getAttr<AVRSignalAttr>()) + Fn->addFnAttr("signal"); + } +}; +} + +std::unique_ptr<TargetCodeGenInfo> +CodeGen::createAVRTargetCodeGenInfo(CodeGenModule &CGM, unsigned NPR, + unsigned NRR) { + return std::make_unique<AVRTargetCodeGenInfo>(CGM.getTypes(), NPR, NRR); +} |
