xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/Targets/AVR.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===- AVR.cpp ------------------------------------------------------------===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric 
9*06c3fb27SDimitry Andric #include "ABIInfoImpl.h"
10*06c3fb27SDimitry Andric #include "TargetInfo.h"
11*06c3fb27SDimitry Andric #include "clang/Basic/DiagnosticFrontend.h"
12*06c3fb27SDimitry Andric 
13*06c3fb27SDimitry Andric using namespace clang;
14*06c3fb27SDimitry Andric using namespace clang::CodeGen;
15*06c3fb27SDimitry Andric 
16*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
17*06c3fb27SDimitry Andric // AVR ABI Implementation. Documented at
18*06c3fb27SDimitry Andric // https://gcc.gnu.org/wiki/avr-gcc#Calling_Convention
19*06c3fb27SDimitry Andric // https://gcc.gnu.org/wiki/avr-gcc#Reduced_Tiny
20*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
21*06c3fb27SDimitry Andric 
22*06c3fb27SDimitry Andric namespace {
23*06c3fb27SDimitry Andric class AVRABIInfo : public DefaultABIInfo {
24*06c3fb27SDimitry Andric private:
25*06c3fb27SDimitry Andric   // The total amount of registers can be used to pass parameters. It is 18 on
26*06c3fb27SDimitry Andric   // AVR, or 6 on AVRTiny.
27*06c3fb27SDimitry Andric   const unsigned ParamRegs;
28*06c3fb27SDimitry Andric   // The total amount of registers can be used to pass return value. It is 8 on
29*06c3fb27SDimitry Andric   // AVR, or 4 on AVRTiny.
30*06c3fb27SDimitry Andric   const unsigned RetRegs;
31*06c3fb27SDimitry Andric 
32*06c3fb27SDimitry Andric public:
AVRABIInfo(CodeGenTypes & CGT,unsigned NPR,unsigned NRR)33*06c3fb27SDimitry Andric   AVRABIInfo(CodeGenTypes &CGT, unsigned NPR, unsigned NRR)
34*06c3fb27SDimitry Andric       : DefaultABIInfo(CGT), ParamRegs(NPR), RetRegs(NRR) {}
35*06c3fb27SDimitry Andric 
classifyReturnType(QualType Ty,bool & LargeRet) const36*06c3fb27SDimitry Andric   ABIArgInfo classifyReturnType(QualType Ty, bool &LargeRet) const {
37*06c3fb27SDimitry Andric     // On AVR, a return struct with size less than or equals to 8 bytes is
38*06c3fb27SDimitry Andric     // returned directly via registers R18-R25. On AVRTiny, a return struct
39*06c3fb27SDimitry Andric     // with size less than or equals to 4 bytes is returned directly via
40*06c3fb27SDimitry Andric     // registers R22-R25.
41*06c3fb27SDimitry Andric     if (isAggregateTypeForABI(Ty) &&
42*06c3fb27SDimitry Andric         getContext().getTypeSize(Ty) <= RetRegs * 8)
43*06c3fb27SDimitry Andric       return ABIArgInfo::getDirect();
44*06c3fb27SDimitry Andric     // A return value (struct or scalar) with larger size is returned via a
45*06c3fb27SDimitry Andric     // stack slot, along with a pointer as the function's implicit argument.
46*06c3fb27SDimitry Andric     if (getContext().getTypeSize(Ty) > RetRegs * 8) {
47*06c3fb27SDimitry Andric       LargeRet = true;
48*06c3fb27SDimitry Andric       return getNaturalAlignIndirect(Ty);
49*06c3fb27SDimitry Andric     }
50*06c3fb27SDimitry Andric     // An i8 return value should not be extended to i16, since AVR has 8-bit
51*06c3fb27SDimitry Andric     // registers.
52*06c3fb27SDimitry Andric     if (Ty->isIntegralOrEnumerationType() && getContext().getTypeSize(Ty) <= 8)
53*06c3fb27SDimitry Andric       return ABIArgInfo::getDirect();
54*06c3fb27SDimitry Andric     // Otherwise we follow the default way which is compatible.
55*06c3fb27SDimitry Andric     return DefaultABIInfo::classifyReturnType(Ty);
56*06c3fb27SDimitry Andric   }
57*06c3fb27SDimitry Andric 
classifyArgumentType(QualType Ty,unsigned & NumRegs) const58*06c3fb27SDimitry Andric   ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegs) const {
59*06c3fb27SDimitry Andric     unsigned TySize = getContext().getTypeSize(Ty);
60*06c3fb27SDimitry Andric 
61*06c3fb27SDimitry Andric     // An int8 type argument always costs two registers like an int16.
62*06c3fb27SDimitry Andric     if (TySize == 8 && NumRegs >= 2) {
63*06c3fb27SDimitry Andric       NumRegs -= 2;
64*06c3fb27SDimitry Andric       return ABIArgInfo::getExtend(Ty);
65*06c3fb27SDimitry Andric     }
66*06c3fb27SDimitry Andric 
67*06c3fb27SDimitry Andric     // If the argument size is an odd number of bytes, round up the size
68*06c3fb27SDimitry Andric     // to the next even number.
69*06c3fb27SDimitry Andric     TySize = llvm::alignTo(TySize, 16);
70*06c3fb27SDimitry Andric 
71*06c3fb27SDimitry Andric     // Any type including an array/struct type can be passed in rgisters,
72*06c3fb27SDimitry Andric     // if there are enough registers left.
73*06c3fb27SDimitry Andric     if (TySize <= NumRegs * 8) {
74*06c3fb27SDimitry Andric       NumRegs -= TySize / 8;
75*06c3fb27SDimitry Andric       return ABIArgInfo::getDirect();
76*06c3fb27SDimitry Andric     }
77*06c3fb27SDimitry Andric 
78*06c3fb27SDimitry Andric     // An argument is passed either completely in registers or completely in
79*06c3fb27SDimitry Andric     // memory. Since there are not enough registers left, current argument
80*06c3fb27SDimitry Andric     // and all other unprocessed arguments should be passed in memory.
81*06c3fb27SDimitry Andric     // However we still need to return `ABIArgInfo::getDirect()` other than
82*06c3fb27SDimitry Andric     // `ABIInfo::getNaturalAlignIndirect(Ty)`, otherwise an extra stack slot
83*06c3fb27SDimitry Andric     // will be allocated, so the stack frame layout will be incompatible with
84*06c3fb27SDimitry Andric     // avr-gcc.
85*06c3fb27SDimitry Andric     NumRegs = 0;
86*06c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
87*06c3fb27SDimitry Andric   }
88*06c3fb27SDimitry Andric 
computeInfo(CGFunctionInfo & FI) const89*06c3fb27SDimitry Andric   void computeInfo(CGFunctionInfo &FI) const override {
90*06c3fb27SDimitry Andric     // Decide the return type.
91*06c3fb27SDimitry Andric     bool LargeRet = false;
92*06c3fb27SDimitry Andric     if (!getCXXABI().classifyReturnType(FI))
93*06c3fb27SDimitry Andric       FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), LargeRet);
94*06c3fb27SDimitry Andric 
95*06c3fb27SDimitry Andric     // Decide each argument type. The total number of registers can be used for
96*06c3fb27SDimitry Andric     // arguments depends on several factors:
97*06c3fb27SDimitry Andric     // 1. Arguments of varargs functions are passed on the stack. This applies
98*06c3fb27SDimitry Andric     //    even to the named arguments. So no register can be used.
99*06c3fb27SDimitry Andric     // 2. Total 18 registers can be used on avr and 6 ones on avrtiny.
100*06c3fb27SDimitry Andric     // 3. If the return type is a struct with too large size, two registers
101*06c3fb27SDimitry Andric     //    (out of 18/6) will be cost as an implicit pointer argument.
102*06c3fb27SDimitry Andric     unsigned NumRegs = ParamRegs;
103*06c3fb27SDimitry Andric     if (FI.isVariadic())
104*06c3fb27SDimitry Andric       NumRegs = 0;
105*06c3fb27SDimitry Andric     else if (LargeRet)
106*06c3fb27SDimitry Andric       NumRegs -= 2;
107*06c3fb27SDimitry Andric     for (auto &I : FI.arguments())
108*06c3fb27SDimitry Andric       I.info = classifyArgumentType(I.type, NumRegs);
109*06c3fb27SDimitry Andric   }
110*06c3fb27SDimitry Andric };
111*06c3fb27SDimitry Andric 
112*06c3fb27SDimitry Andric class AVRTargetCodeGenInfo : public TargetCodeGenInfo {
113*06c3fb27SDimitry Andric public:
AVRTargetCodeGenInfo(CodeGenTypes & CGT,unsigned NPR,unsigned NRR)114*06c3fb27SDimitry Andric   AVRTargetCodeGenInfo(CodeGenTypes &CGT, unsigned NPR, unsigned NRR)
115*06c3fb27SDimitry Andric       : TargetCodeGenInfo(std::make_unique<AVRABIInfo>(CGT, NPR, NRR)) {}
116*06c3fb27SDimitry Andric 
getGlobalVarAddressSpace(CodeGenModule & CGM,const VarDecl * D) const117*06c3fb27SDimitry Andric   LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
118*06c3fb27SDimitry Andric                                   const VarDecl *D) const override {
119*06c3fb27SDimitry Andric     // Check if global/static variable is defined in address space
120*06c3fb27SDimitry Andric     // 1~6 (__flash, __flash1, __flash2, __flash3, __flash4, __flash5)
121*06c3fb27SDimitry Andric     // but not constant.
122*06c3fb27SDimitry Andric     if (D) {
123*06c3fb27SDimitry Andric       LangAS AS = D->getType().getAddressSpace();
124*06c3fb27SDimitry Andric       if (isTargetAddressSpace(AS) && 1 <= toTargetAddressSpace(AS) &&
125*06c3fb27SDimitry Andric           toTargetAddressSpace(AS) <= 6 && !D->getType().isConstQualified())
126*06c3fb27SDimitry Andric         CGM.getDiags().Report(D->getLocation(),
127*06c3fb27SDimitry Andric                               diag::err_verify_nonconst_addrspace)
128*06c3fb27SDimitry Andric             << "__flash*";
129*06c3fb27SDimitry Andric     }
130*06c3fb27SDimitry Andric     return TargetCodeGenInfo::getGlobalVarAddressSpace(CGM, D);
131*06c3fb27SDimitry Andric   }
132*06c3fb27SDimitry Andric 
setTargetAttributes(const Decl * D,llvm::GlobalValue * GV,CodeGen::CodeGenModule & CGM) const133*06c3fb27SDimitry Andric   void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
134*06c3fb27SDimitry Andric                            CodeGen::CodeGenModule &CGM) const override {
135*06c3fb27SDimitry Andric     if (GV->isDeclaration())
136*06c3fb27SDimitry Andric       return;
137*06c3fb27SDimitry Andric     const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
138*06c3fb27SDimitry Andric     if (!FD) return;
139*06c3fb27SDimitry Andric     auto *Fn = cast<llvm::Function>(GV);
140*06c3fb27SDimitry Andric 
141*06c3fb27SDimitry Andric     if (FD->getAttr<AVRInterruptAttr>())
142*06c3fb27SDimitry Andric       Fn->addFnAttr("interrupt");
143*06c3fb27SDimitry Andric 
144*06c3fb27SDimitry Andric     if (FD->getAttr<AVRSignalAttr>())
145*06c3fb27SDimitry Andric       Fn->addFnAttr("signal");
146*06c3fb27SDimitry Andric   }
147*06c3fb27SDimitry Andric };
148*06c3fb27SDimitry Andric }
149*06c3fb27SDimitry Andric 
150*06c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
createAVRTargetCodeGenInfo(CodeGenModule & CGM,unsigned NPR,unsigned NRR)151*06c3fb27SDimitry Andric CodeGen::createAVRTargetCodeGenInfo(CodeGenModule &CGM, unsigned NPR,
152*06c3fb27SDimitry Andric                                     unsigned NRR) {
153*06c3fb27SDimitry Andric   return std::make_unique<AVRTargetCodeGenInfo>(CGM.getTypes(), NPR, NRR);
154*06c3fb27SDimitry Andric }
155