1//===- Lanai.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
12using namespace clang;
13using namespace clang::CodeGen;
14
15//===----------------------------------------------------------------------===//
16// Lanai ABI Implementation
17//===----------------------------------------------------------------------===//
18
19namespace {
20class LanaiABIInfo : public DefaultABIInfo {
21  struct CCState {
22    unsigned FreeRegs;
23  };
24
25public:
26  LanaiABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
27
28  bool shouldUseInReg(QualType Ty, CCState &State) const;
29
30  void computeInfo(CGFunctionInfo &FI) const override {
31    CCState State;
32    // Lanai uses 4 registers to pass arguments unless the function has the
33    // regparm attribute set.
34    if (FI.getHasRegParm()) {
35      State.FreeRegs = FI.getRegParm();
36    } else {
37      State.FreeRegs = 4;
38    }
39
40    if (!getCXXABI().classifyReturnType(FI))
41      FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
42    for (auto &I : FI.arguments())
43      I.info = classifyArgumentType(I.type, State);
44  }
45
46  ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const;
47  ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
48};
49} // end anonymous namespace
50
51bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const {
52  unsigned Size = getContext().getTypeSize(Ty);
53  unsigned SizeInRegs = llvm::alignTo(Size, 32U) / 32U;
54
55  if (SizeInRegs == 0)
56    return false;
57
58  if (SizeInRegs > State.FreeRegs) {
59    State.FreeRegs = 0;
60    return false;
61  }
62
63  State.FreeRegs -= SizeInRegs;
64
65  return true;
66}
67
68ABIArgInfo LanaiABIInfo::getIndirectResult(QualType Ty, bool ByVal,
69                                           CCState &State) const {
70  if (!ByVal) {
71    if (State.FreeRegs) {
72      --State.FreeRegs; // Non-byval indirects just use one pointer.
73      return getNaturalAlignIndirectInReg(Ty);
74    }
75    return getNaturalAlignIndirect(Ty, false);
76  }
77
78  // Compute the byval alignment.
79  const unsigned MinABIStackAlignInBytes = 4;
80  unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
81  return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true,
82                                 /*Realign=*/TypeAlign >
83                                     MinABIStackAlignInBytes);
84}
85
86ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty,
87                                              CCState &State) const {
88  // Check with the C++ ABI first.
89  const RecordType *RT = Ty->getAs<RecordType>();
90  if (RT) {
91    CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
92    if (RAA == CGCXXABI::RAA_Indirect) {
93      return getIndirectResult(Ty, /*ByVal=*/false, State);
94    } else if (RAA == CGCXXABI::RAA_DirectInMemory) {
95      return getNaturalAlignIndirect(Ty, /*ByVal=*/true);
96    }
97  }
98
99  if (isAggregateTypeForABI(Ty)) {
100    // Structures with flexible arrays are always indirect.
101    if (RT && RT->getDecl()->hasFlexibleArrayMember())
102      return getIndirectResult(Ty, /*ByVal=*/true, State);
103
104    // Ignore empty structs/unions.
105    if (isEmptyRecord(getContext(), Ty, true))
106      return ABIArgInfo::getIgnore();
107
108    llvm::LLVMContext &LLVMContext = getVMContext();
109    unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
110    if (SizeInRegs <= State.FreeRegs) {
111      llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
112      SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32);
113      llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
114      State.FreeRegs -= SizeInRegs;
115      return ABIArgInfo::getDirectInReg(Result);
116    } else {
117      State.FreeRegs = 0;
118    }
119    return getIndirectResult(Ty, true, State);
120  }
121
122  // Treat an enum type as its underlying type.
123  if (const auto *EnumTy = Ty->getAs<EnumType>())
124    Ty = EnumTy->getDecl()->getIntegerType();
125
126  bool InReg = shouldUseInReg(Ty, State);
127
128  // Don't pass >64 bit integers in registers.
129  if (const auto *EIT = Ty->getAs<BitIntType>())
130    if (EIT->getNumBits() > 64)
131      return getIndirectResult(Ty, /*ByVal=*/true, State);
132
133  if (isPromotableIntegerTypeForABI(Ty)) {
134    if (InReg)
135      return ABIArgInfo::getDirectInReg();
136    return ABIArgInfo::getExtend(Ty);
137  }
138  if (InReg)
139    return ABIArgInfo::getDirectInReg();
140  return ABIArgInfo::getDirect();
141}
142
143namespace {
144class LanaiTargetCodeGenInfo : public TargetCodeGenInfo {
145public:
146  LanaiTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
147      : TargetCodeGenInfo(std::make_unique<LanaiABIInfo>(CGT)) {}
148};
149}
150
151std::unique_ptr<TargetCodeGenInfo>
152CodeGen::createLanaiTargetCodeGenInfo(CodeGenModule &CGM) {
153  return std::make_unique<LanaiTargetCodeGenInfo>(CGM.getTypes());
154}
155