brintos

brintos / llvm-project-archived public Read only

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