Coverage Report

Created: 2024-01-17 10:31

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