mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-16 14:26:06 +00:00

This commit breaks up CodeGen/TargetInfo.cpp into a set of *.cpp files, one file per target. There are no functional changes, mostly just code moving. Non-code-moving changes are: * A virtual destructor has been added to DefaultABIInfo to pin the vtable to a cpp file. * A few methods of ABIInfo and DefaultABIInfo were split into declaration + definition in order to reduce the number of transitive includes. * Several functions that used to be static have been placed in clang::CodeGen namespace so that they can be accessed from other cpp files. RFC: https://discourse.llvm.org/t/rfc-splitting-clangs-targetinfo-cpp/69883 Reviewed By: efriedma Differential Revision: https://reviews.llvm.org/D148094
155 lines
6.0 KiB
C++
155 lines
6.0 KiB
C++
//===- 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);
|
|
}
|