Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/CodeGen/Targets/Sparc.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- Sparc.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
// SPARC v8 ABI Implementation.
17
// Based on the SPARC Compliance Definition version 2.4.1.
18
//
19
// Ensures that complex values are passed in registers.
20
//
21
namespace {
22
class SparcV8ABIInfo : public DefaultABIInfo {
23
public:
24
0
  SparcV8ABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
25
26
private:
27
  ABIArgInfo classifyReturnType(QualType RetTy) const;
28
  void computeInfo(CGFunctionInfo &FI) const override;
29
};
30
} // end anonymous namespace
31
32
33
ABIArgInfo
34
0
SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
35
0
  if (Ty->isAnyComplexType()) {
36
0
    return ABIArgInfo::getDirect();
37
0
  }
38
0
  else {
39
0
    return DefaultABIInfo::classifyReturnType(Ty);
40
0
  }
41
0
}
42
43
0
void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const {
44
45
0
  FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
46
0
  for (auto &Arg : FI.arguments())
47
0
    Arg.info = classifyArgumentType(Arg.type);
48
0
}
49
50
namespace {
51
class SparcV8TargetCodeGenInfo : public TargetCodeGenInfo {
52
public:
53
  SparcV8TargetCodeGenInfo(CodeGenTypes &CGT)
54
0
      : TargetCodeGenInfo(std::make_unique<SparcV8ABIInfo>(CGT)) {}
55
56
  llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF,
57
0
                                   llvm::Value *Address) const override {
58
0
    int Offset;
59
0
    if (isAggregateTypeForABI(CGF.CurFnInfo->getReturnType()))
60
0
      Offset = 12;
61
0
    else
62
0
      Offset = 8;
63
0
    return CGF.Builder.CreateGEP(CGF.Int8Ty, Address,
64
0
                                 llvm::ConstantInt::get(CGF.Int32Ty, Offset));
65
0
  }
66
67
  llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF,
68
0
                                   llvm::Value *Address) const override {
69
0
    int Offset;
70
0
    if (isAggregateTypeForABI(CGF.CurFnInfo->getReturnType()))
71
0
      Offset = -12;
72
0
    else
73
0
      Offset = -8;
74
0
    return CGF.Builder.CreateGEP(CGF.Int8Ty, Address,
75
0
                                 llvm::ConstantInt::get(CGF.Int32Ty, Offset));
76
0
  }
77
};
78
} // end anonymous namespace
79
80
//===----------------------------------------------------------------------===//
81
// SPARC v9 ABI Implementation.
82
// Based on the SPARC Compliance Definition version 2.4.1.
83
//
84
// Function arguments a mapped to a nominal "parameter array" and promoted to
85
// registers depending on their type. Each argument occupies 8 or 16 bytes in
86
// the array, structs larger than 16 bytes are passed indirectly.
87
//
88
// One case requires special care:
89
//
90
//   struct mixed {
91
//     int i;
92
//     float f;
93
//   };
94
//
95
// When a struct mixed is passed by value, it only occupies 8 bytes in the
96
// parameter array, but the int is passed in an integer register, and the float
97
// is passed in a floating point register. This is represented as two arguments
98
// with the LLVM IR inreg attribute:
99
//
100
//   declare void f(i32 inreg %i, float inreg %f)
101
//
102
// The code generator will only allocate 4 bytes from the parameter array for
103
// the inreg arguments. All other arguments are allocated a multiple of 8
104
// bytes.
105
//
106
namespace {
107
class SparcV9ABIInfo : public ABIInfo {
108
public:
109
0
  SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
110
111
private:
112
  ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const;
113
  void computeInfo(CGFunctionInfo &FI) const override;
114
  Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
115
                    QualType Ty) const override;
116
117
  // Coercion type builder for structs passed in registers. The coercion type
118
  // serves two purposes:
119
  //
120
  // 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned'
121
  //    in registers.
122
  // 2. Expose aligned floating point elements as first-level elements, so the
123
  //    code generator knows to pass them in floating point registers.
124
  //
125
  // We also compute the InReg flag which indicates that the struct contains
126
  // aligned 32-bit floats.
127
  //
128
  struct CoerceBuilder {
129
    llvm::LLVMContext &Context;
130
    const llvm::DataLayout &DL;
131
    SmallVector<llvm::Type*, 8> Elems;
132
    uint64_t Size;
133
    bool InReg;
134
135
    CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl)
136
0
      : Context(c), DL(dl), Size(0), InReg(false) {}
137
138
    // Pad Elems with integers until Size is ToSize.
139
0
    void pad(uint64_t ToSize) {
140
0
      assert(ToSize >= Size && "Cannot remove elements");
141
0
      if (ToSize == Size)
142
0
        return;
143
144
      // Finish the current 64-bit word.
145
0
      uint64_t Aligned = llvm::alignTo(Size, 64);
146
0
      if (Aligned > Size && Aligned <= ToSize) {
147
0
        Elems.push_back(llvm::IntegerType::get(Context, Aligned - Size));
148
0
        Size = Aligned;
149
0
      }
150
151
      // Add whole 64-bit words.
152
0
      while (Size + 64 <= ToSize) {
153
0
        Elems.push_back(llvm::Type::getInt64Ty(Context));
154
0
        Size += 64;
155
0
      }
156
157
      // Final in-word padding.
158
0
      if (Size < ToSize) {
159
0
        Elems.push_back(llvm::IntegerType::get(Context, ToSize - Size));
160
0
        Size = ToSize;
161
0
      }
162
0
    }
163
164
    // Add a floating point element at Offset.
165
0
    void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) {
166
      // Unaligned floats are treated as integers.
167
0
      if (Offset % Bits)
168
0
        return;
169
      // The InReg flag is only required if there are any floats < 64 bits.
170
0
      if (Bits < 64)
171
0
        InReg = true;
172
0
      pad(Offset);
173
0
      Elems.push_back(Ty);
174
0
      Size = Offset + Bits;
175
0
    }
176
177
    // Add a struct type to the coercion type, starting at Offset (in bits).
178
0
    void addStruct(uint64_t Offset, llvm::StructType *StrTy) {
179
0
      const llvm::StructLayout *Layout = DL.getStructLayout(StrTy);
180
0
      for (unsigned i = 0, e = StrTy->getNumElements(); i != e; ++i) {
181
0
        llvm::Type *ElemTy = StrTy->getElementType(i);
182
0
        uint64_t ElemOffset = Offset + Layout->getElementOffsetInBits(i);
183
0
        switch (ElemTy->getTypeID()) {
184
0
        case llvm::Type::StructTyID:
185
0
          addStruct(ElemOffset, cast<llvm::StructType>(ElemTy));
186
0
          break;
187
0
        case llvm::Type::FloatTyID:
188
0
          addFloat(ElemOffset, ElemTy, 32);
189
0
          break;
190
0
        case llvm::Type::DoubleTyID:
191
0
          addFloat(ElemOffset, ElemTy, 64);
192
0
          break;
193
0
        case llvm::Type::FP128TyID:
194
0
          addFloat(ElemOffset, ElemTy, 128);
195
0
          break;
196
0
        case llvm::Type::PointerTyID:
197
0
          if (ElemOffset % 64 == 0) {
198
0
            pad(ElemOffset);
199
0
            Elems.push_back(ElemTy);
200
0
            Size += 64;
201
0
          }
202
0
          break;
203
0
        default:
204
0
          break;
205
0
        }
206
0
      }
207
0
    }
208
209
    // Check if Ty is a usable substitute for the coercion type.
210
0
    bool isUsableType(llvm::StructType *Ty) const {
211
0
      return llvm::ArrayRef(Elems) == Ty->elements();
212
0
    }
213
214
    // Get the coercion type as a literal struct type.
215
0
    llvm::Type *getType() const {
216
0
      if (Elems.size() == 1)
217
0
        return Elems.front();
218
0
      else
219
0
        return llvm::StructType::get(Context, Elems);
220
0
    }
221
  };
222
};
223
} // end anonymous namespace
224
225
ABIArgInfo
226
0
SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
227
0
  if (Ty->isVoidType())
228
0
    return ABIArgInfo::getIgnore();
229
230
0
  uint64_t Size = getContext().getTypeSize(Ty);
231
232
  // Anything too big to fit in registers is passed with an explicit indirect
233
  // pointer / sret pointer.
234
0
  if (Size > SizeLimit)
235
0
    return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
236
237
  // Treat an enum type as its underlying type.
238
0
  if (const EnumType *EnumTy = Ty->getAs<EnumType>())
239
0
    Ty = EnumTy->getDecl()->getIntegerType();
240
241
  // Integer types smaller than a register are extended.
242
0
  if (Size < 64 && Ty->isIntegerType())
243
0
    return ABIArgInfo::getExtend(Ty);
244
245
0
  if (const auto *EIT = Ty->getAs<BitIntType>())
246
0
    if (EIT->getNumBits() < 64)
247
0
      return ABIArgInfo::getExtend(Ty);
248
249
  // Other non-aggregates go in registers.
250
0
  if (!isAggregateTypeForABI(Ty))
251
0
    return ABIArgInfo::getDirect();
252
253
  // If a C++ object has either a non-trivial copy constructor or a non-trivial
254
  // destructor, it is passed with an explicit indirect pointer / sret pointer.
255
0
  if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
256
0
    return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
257
258
  // This is a small aggregate type that should be passed in registers.
259
  // Build a coercion type from the LLVM struct type.
260
0
  llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
261
0
  if (!StrTy)
262
0
    return ABIArgInfo::getDirect();
263
264
0
  CoerceBuilder CB(getVMContext(), getDataLayout());
265
0
  CB.addStruct(0, StrTy);
266
0
  CB.pad(llvm::alignTo(CB.DL.getTypeSizeInBits(StrTy), 64));
267
268
  // Try to use the original type for coercion.
269
0
  llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
270
271
0
  if (CB.InReg)
272
0
    return ABIArgInfo::getDirectInReg(CoerceTy);
273
0
  else
274
0
    return ABIArgInfo::getDirect(CoerceTy);
275
0
}
276
277
Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
278
0
                                  QualType Ty) const {
279
0
  ABIArgInfo AI = classifyType(Ty, 16 * 8);
280
0
  llvm::Type *ArgTy = CGT.ConvertType(Ty);
281
0
  if (AI.canHaveCoerceToType() && !AI.getCoerceToType())
282
0
    AI.setCoerceToType(ArgTy);
283
284
0
  CharUnits SlotSize = CharUnits::fromQuantity(8);
285
286
0
  CGBuilderTy &Builder = CGF.Builder;
287
0
  Address Addr = Address(Builder.CreateLoad(VAListAddr, "ap.cur"),
288
0
                         getVAListElementType(CGF), SlotSize);
289
0
  llvm::Type *ArgPtrTy = CGF.UnqualPtrTy;
290
291
0
  auto TypeInfo = getContext().getTypeInfoInChars(Ty);
292
293
0
  Address ArgAddr = Address::invalid();
294
0
  CharUnits Stride;
295
0
  switch (AI.getKind()) {
296
0
  case ABIArgInfo::Expand:
297
0
  case ABIArgInfo::CoerceAndExpand:
298
0
  case ABIArgInfo::InAlloca:
299
0
    llvm_unreachable("Unsupported ABI kind for va_arg");
300
301
0
  case ABIArgInfo::Extend: {
302
0
    Stride = SlotSize;
303
0
    CharUnits Offset = SlotSize - TypeInfo.Width;
304
0
    ArgAddr = Builder.CreateConstInBoundsByteGEP(Addr, Offset, "extend");
305
0
    break;
306
0
  }
307
308
0
  case ABIArgInfo::Direct: {
309
0
    auto AllocSize = getDataLayout().getTypeAllocSize(AI.getCoerceToType());
310
0
    Stride = CharUnits::fromQuantity(AllocSize).alignTo(SlotSize);
311
0
    ArgAddr = Addr;
312
0
    break;
313
0
  }
314
315
0
  case ABIArgInfo::Indirect:
316
0
  case ABIArgInfo::IndirectAliased:
317
0
    Stride = SlotSize;
318
0
    ArgAddr = Addr.withElementType(ArgPtrTy);
319
0
    ArgAddr = Address(Builder.CreateLoad(ArgAddr, "indirect.arg"), ArgTy,
320
0
                      TypeInfo.Align);
321
0
    break;
322
323
0
  case ABIArgInfo::Ignore:
324
0
    return Address(llvm::UndefValue::get(ArgPtrTy), ArgTy, TypeInfo.Align);
325
0
  }
326
327
  // Update VAList.
328
0
  Address NextPtr = Builder.CreateConstInBoundsByteGEP(Addr, Stride, "ap.next");
329
0
  Builder.CreateStore(NextPtr.getPointer(), VAListAddr);
330
331
0
  return ArgAddr.withElementType(ArgTy);
332
0
}
333
334
0
void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
335
0
  FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8);
336
0
  for (auto &I : FI.arguments())
337
0
    I.info = classifyType(I.type, 16 * 8);
338
0
}
339
340
namespace {
341
class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo {
342
public:
343
  SparcV9TargetCodeGenInfo(CodeGenTypes &CGT)
344
0
      : TargetCodeGenInfo(std::make_unique<SparcV9ABIInfo>(CGT)) {}
345
346
0
  int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
347
0
    return 14;
348
0
  }
349
350
  bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
351
                               llvm::Value *Address) const override;
352
353
  llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF,
354
0
                                   llvm::Value *Address) const override {
355
0
    return CGF.Builder.CreateGEP(CGF.Int8Ty, Address,
356
0
                                 llvm::ConstantInt::get(CGF.Int32Ty, 8));
357
0
  }
358
359
  llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF,
360
0
                                   llvm::Value *Address) const override {
361
0
    return CGF.Builder.CreateGEP(CGF.Int8Ty, Address,
362
0
                                 llvm::ConstantInt::get(CGF.Int32Ty, -8));
363
0
  }
364
};
365
} // end anonymous namespace
366
367
bool
368
SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
369
0
                                                llvm::Value *Address) const {
370
  // This is calculated from the LLVM and GCC tables and verified
371
  // against gcc output.  AFAIK all ABIs use the same encoding.
372
373
0
  CodeGen::CGBuilderTy &Builder = CGF.Builder;
374
375
0
  llvm::IntegerType *i8 = CGF.Int8Ty;
376
0
  llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
377
0
  llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
378
379
  // 0-31: the 8-byte general-purpose registers
380
0
  AssignToArrayRange(Builder, Address, Eight8, 0, 31);
381
382
  // 32-63: f0-31, the 4-byte floating-point registers
383
0
  AssignToArrayRange(Builder, Address, Four8, 32, 63);
384
385
  //   Y   = 64
386
  //   PSR = 65
387
  //   WIM = 66
388
  //   TBR = 67
389
  //   PC  = 68
390
  //   NPC = 69
391
  //   FSR = 70
392
  //   CSR = 71
393
0
  AssignToArrayRange(Builder, Address, Eight8, 64, 71);
394
395
  // 72-87: d0-15, the 8-byte floating-point registers
396
0
  AssignToArrayRange(Builder, Address, Eight8, 72, 87);
397
398
0
  return false;
399
0
}
400
401
std::unique_ptr<TargetCodeGenInfo>
402
0
CodeGen::createSparcV8TargetCodeGenInfo(CodeGenModule &CGM) {
403
0
  return std::make_unique<SparcV8TargetCodeGenInfo>(CGM.getTypes());
404
0
}
405
406
std::unique_ptr<TargetCodeGenInfo>
407
0
CodeGen::createSparcV9TargetCodeGenInfo(CodeGenModule &CGM) {
408
0
  return std::make_unique<SparcV9TargetCodeGenInfo>(CGM.getTypes());
409
0
}