1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 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);
}
|