Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/CodeGen/Targets/CSKY.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- CSKY.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
12
using namespace clang;
13
using namespace clang::CodeGen;
14
15
//===----------------------------------------------------------------------===//
16
// CSKY ABI Implementation
17
//===----------------------------------------------------------------------===//
18
namespace {
19
class CSKYABIInfo : public DefaultABIInfo {
20
  static const int NumArgGPRs = 4;
21
  static const int NumArgFPRs = 4;
22
23
  static const unsigned XLen = 32;
24
  unsigned FLen;
25
26
public:
27
  CSKYABIInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
28
0
      : DefaultABIInfo(CGT), FLen(FLen) {}
29
30
  void computeInfo(CGFunctionInfo &FI) const override;
31
  ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
32
                                  int &ArgFPRsLeft,
33
                                  bool isReturnType = false) const;
34
  ABIArgInfo classifyReturnType(QualType RetTy) const;
35
36
  Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
37
                    QualType Ty) const override;
38
};
39
40
} // end anonymous namespace
41
42
0
void CSKYABIInfo::computeInfo(CGFunctionInfo &FI) const {
43
0
  QualType RetTy = FI.getReturnType();
44
0
  if (!getCXXABI().classifyReturnType(FI))
45
0
    FI.getReturnInfo() = classifyReturnType(RetTy);
46
47
0
  bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
48
49
  // We must track the number of GPRs used in order to conform to the CSKY
50
  // ABI, as integer scalars passed in registers should have signext/zeroext
51
  // when promoted.
52
0
  int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
53
0
  int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
54
55
0
  for (auto &ArgInfo : FI.arguments()) {
56
0
    ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft);
57
0
  }
58
0
}
59
60
Address CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
61
0
                               QualType Ty) const {
62
0
  CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8);
63
64
  // Empty records are ignored for parameter passing purposes.
65
0
  if (isEmptyRecord(getContext(), Ty, true)) {
66
0
    return Address(CGF.Builder.CreateLoad(VAListAddr),
67
0
                   CGF.ConvertTypeForMem(Ty), SlotSize);
68
0
  }
69
70
0
  auto TInfo = getContext().getTypeInfoInChars(Ty);
71
72
0
  return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TInfo, SlotSize,
73
0
                          /*AllowHigherAlign=*/true);
74
0
}
75
76
ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
77
                                             int &ArgFPRsLeft,
78
0
                                             bool isReturnType) const {
79
0
  assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
80
0
  Ty = useFirstFieldIfTransparentUnion(Ty);
81
82
  // Structures with either a non-trivial destructor or a non-trivial
83
  // copy constructor are always passed indirectly.
84
0
  if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
85
0
    if (ArgGPRsLeft)
86
0
      ArgGPRsLeft -= 1;
87
0
    return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
88
0
                                           CGCXXABI::RAA_DirectInMemory);
89
0
  }
90
91
  // Ignore empty structs/unions.
92
0
  if (isEmptyRecord(getContext(), Ty, true))
93
0
    return ABIArgInfo::getIgnore();
94
95
0
  if (!Ty->getAsUnionType())
96
0
    if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
97
0
      return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
98
99
0
  uint64_t Size = getContext().getTypeSize(Ty);
100
  // Pass floating point values via FPRs if possible.
101
0
  if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size &&
102
0
      ArgFPRsLeft) {
103
0
    ArgFPRsLeft--;
104
0
    return ABIArgInfo::getDirect();
105
0
  }
106
107
  // Complex types for the hard float ABI must be passed direct rather than
108
  // using CoerceAndExpand.
109
0
  if (Ty->isComplexType() && FLen && !isReturnType) {
110
0
    QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
111
0
    if (getContext().getTypeSize(EltTy) <= FLen) {
112
0
      ArgFPRsLeft -= 2;
113
0
      return ABIArgInfo::getDirect();
114
0
    }
115
0
  }
116
117
0
  if (!isAggregateTypeForABI(Ty)) {
118
    // Treat an enum type as its underlying type.
119
0
    if (const EnumType *EnumTy = Ty->getAs<EnumType>())
120
0
      Ty = EnumTy->getDecl()->getIntegerType();
121
122
    // All integral types are promoted to XLen width, unless passed on the
123
    // stack.
124
0
    if (Size < XLen && Ty->isIntegralOrEnumerationType())
125
0
      return ABIArgInfo::getExtend(Ty);
126
127
0
    if (const auto *EIT = Ty->getAs<BitIntType>()) {
128
0
      if (EIT->getNumBits() < XLen)
129
0
        return ABIArgInfo::getExtend(Ty);
130
0
    }
131
132
0
    return ABIArgInfo::getDirect();
133
0
  }
134
135
  // For argument type, the first 4*XLen parts of aggregate will be passed
136
  // in registers, and the rest will be passed in stack.
137
  // So we can coerce to integers directly and let backend handle it correctly.
138
  // For return type, aggregate which <= 2*XLen will be returned in registers.
139
  // Otherwise, aggregate will be returned indirectly.
140
0
  if (!isReturnType || (isReturnType && Size <= 2 * XLen)) {
141
0
    if (Size <= XLen) {
142
0
      return ABIArgInfo::getDirect(
143
0
          llvm::IntegerType::get(getVMContext(), XLen));
144
0
    } else {
145
0
      return ABIArgInfo::getDirect(llvm::ArrayType::get(
146
0
          llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen));
147
0
    }
148
0
  }
149
0
  return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
150
0
}
151
152
0
ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const {
153
0
  if (RetTy->isVoidType())
154
0
    return ABIArgInfo::getIgnore();
155
156
0
  int ArgGPRsLeft = 2;
157
0
  int ArgFPRsLeft = FLen ? 1 : 0;
158
159
  // The rules for return and argument types are the same, so defer to
160
  // classifyArgumentType.
161
0
  return classifyArgumentType(RetTy, ArgGPRsLeft, ArgFPRsLeft, true);
162
0
}
163
164
namespace {
165
class CSKYTargetCodeGenInfo : public TargetCodeGenInfo {
166
public:
167
  CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
168
0
      : TargetCodeGenInfo(std::make_unique<CSKYABIInfo>(CGT, FLen)) {}
169
};
170
} // end anonymous namespace
171
172
std::unique_ptr<TargetCodeGenInfo>
173
0
CodeGen::createCSKYTargetCodeGenInfo(CodeGenModule &CGM, unsigned FLen) {
174
0
  return std::make_unique<CSKYTargetCodeGenInfo>(CGM.getTypes(), FLen);
175
0
}