1 //===- Sparc.cpp ----------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ABIInfoImpl.h"
10 #include "TargetInfo.h"
12 using namespace clang
;
13 using namespace clang::CodeGen
;
15 //===----------------------------------------------------------------------===//
16 // SPARC v8 ABI Implementation.
17 // Based on the SPARC Compliance Definition version 2.4.1.
19 // Ensures that complex values are passed in registers.
22 class SparcV8ABIInfo
: public DefaultABIInfo
{
24 SparcV8ABIInfo(CodeGenTypes
&CGT
) : DefaultABIInfo(CGT
) {}
27 ABIArgInfo
classifyReturnType(QualType RetTy
) const;
28 void computeInfo(CGFunctionInfo
&FI
) const override
;
30 } // end anonymous namespace
34 SparcV8ABIInfo::classifyReturnType(QualType Ty
) const {
35 if (Ty
->isAnyComplexType()) {
36 return ABIArgInfo::getDirect();
39 return DefaultABIInfo::classifyReturnType(Ty
);
43 void SparcV8ABIInfo::computeInfo(CGFunctionInfo
&FI
) const {
45 FI
.getReturnInfo() = classifyReturnType(FI
.getReturnType());
46 for (auto &Arg
: FI
.arguments())
47 Arg
.info
= classifyArgumentType(Arg
.type
);
51 class SparcV8TargetCodeGenInfo
: public TargetCodeGenInfo
{
53 SparcV8TargetCodeGenInfo(CodeGenTypes
&CGT
)
54 : TargetCodeGenInfo(std::make_unique
<SparcV8ABIInfo
>(CGT
)) {}
56 llvm::Value
*decodeReturnAddress(CodeGen::CodeGenFunction
&CGF
,
57 llvm::Value
*Address
) const override
{
59 if (isAggregateTypeForABI(CGF
.CurFnInfo
->getReturnType()))
63 return CGF
.Builder
.CreateGEP(CGF
.Int8Ty
, Address
,
64 llvm::ConstantInt::get(CGF
.Int32Ty
, Offset
));
67 llvm::Value
*encodeReturnAddress(CodeGen::CodeGenFunction
&CGF
,
68 llvm::Value
*Address
) const override
{
70 if (isAggregateTypeForABI(CGF
.CurFnInfo
->getReturnType()))
74 return CGF
.Builder
.CreateGEP(CGF
.Int8Ty
, Address
,
75 llvm::ConstantInt::get(CGF
.Int32Ty
, Offset
));
78 } // end anonymous namespace
80 //===----------------------------------------------------------------------===//
81 // SPARC v9 ABI Implementation.
82 // Based on the SPARC Compliance Definition version 2.4.1.
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.
88 // One case requires special care:
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:
100 // declare void f(i32 inreg %i, float inreg %f)
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
107 class SparcV9ABIInfo
: public ABIInfo
{
109 SparcV9ABIInfo(CodeGenTypes
&CGT
) : ABIInfo(CGT
) {}
112 ABIArgInfo
classifyType(QualType RetTy
, unsigned SizeLimit
) const;
113 void computeInfo(CGFunctionInfo
&FI
) const override
;
114 RValue
EmitVAArg(CodeGenFunction
&CGF
, Address VAListAddr
, QualType Ty
,
115 AggValueSlot Slot
) const override
;
117 // Coercion type builder for structs passed in registers. The coercion type
118 // serves two purposes:
120 // 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned'
122 // 2. Expose aligned floating point elements as first-level elements, so the
123 // code generator knows to pass them in floating point registers.
125 // We also compute the InReg flag which indicates that the struct contains
126 // aligned 32-bit floats.
128 struct CoerceBuilder
{
129 llvm::LLVMContext
&Context
;
130 const llvm::DataLayout
&DL
;
131 SmallVector
<llvm::Type
*, 8> Elems
;
135 CoerceBuilder(llvm::LLVMContext
&c
, const llvm::DataLayout
&dl
)
136 : Context(c
), DL(dl
), Size(0), InReg(false) {}
138 // Pad Elems with integers until Size is ToSize.
139 void pad(uint64_t ToSize
) {
140 assert(ToSize
>= Size
&& "Cannot remove elements");
144 // Finish the current 64-bit word.
145 uint64_t Aligned
= llvm::alignTo(Size
, 64);
146 if (Aligned
> Size
&& Aligned
<= ToSize
) {
147 Elems
.push_back(llvm::IntegerType::get(Context
, Aligned
- Size
));
151 // Add whole 64-bit words.
152 while (Size
+ 64 <= ToSize
) {
153 Elems
.push_back(llvm::Type::getInt64Ty(Context
));
157 // Final in-word padding.
159 Elems
.push_back(llvm::IntegerType::get(Context
, ToSize
- Size
));
164 // Add a floating point element at Offset.
165 void addFloat(uint64_t Offset
, llvm::Type
*Ty
, unsigned Bits
) {
166 // Unaligned floats are treated as integers.
169 // The InReg flag is only required if there are any floats < 64 bits.
174 Size
= Offset
+ Bits
;
177 // Add a struct type to the coercion type, starting at Offset (in bits).
178 void addStruct(uint64_t Offset
, llvm::StructType
*StrTy
) {
179 const llvm::StructLayout
*Layout
= DL
.getStructLayout(StrTy
);
180 for (unsigned i
= 0, e
= StrTy
->getNumElements(); i
!= e
; ++i
) {
181 llvm::Type
*ElemTy
= StrTy
->getElementType(i
);
182 uint64_t ElemOffset
= Offset
+ Layout
->getElementOffsetInBits(i
);
183 switch (ElemTy
->getTypeID()) {
184 case llvm::Type::StructTyID
:
185 addStruct(ElemOffset
, cast
<llvm::StructType
>(ElemTy
));
187 case llvm::Type::FloatTyID
:
188 addFloat(ElemOffset
, ElemTy
, 32);
190 case llvm::Type::DoubleTyID
:
191 addFloat(ElemOffset
, ElemTy
, 64);
193 case llvm::Type::FP128TyID
:
194 addFloat(ElemOffset
, ElemTy
, 128);
196 case llvm::Type::PointerTyID
:
197 if (ElemOffset
% 64 == 0) {
199 Elems
.push_back(ElemTy
);
209 // Check if Ty is a usable substitute for the coercion type.
210 bool isUsableType(llvm::StructType
*Ty
) const {
211 return llvm::ArrayRef(Elems
) == Ty
->elements();
214 // Get the coercion type as a literal struct type.
215 llvm::Type
*getType() const {
216 if (Elems
.size() == 1)
217 return Elems
.front();
219 return llvm::StructType::get(Context
, Elems
);
223 } // end anonymous namespace
226 SparcV9ABIInfo::classifyType(QualType Ty
, unsigned SizeLimit
) const {
227 if (Ty
->isVoidType())
228 return ABIArgInfo::getIgnore();
230 uint64_t Size
= getContext().getTypeSize(Ty
);
232 // Anything too big to fit in registers is passed with an explicit indirect
233 // pointer / sret pointer.
234 if (Size
> SizeLimit
)
235 return getNaturalAlignIndirect(Ty
, /*ByVal=*/false);
237 // Treat an enum type as its underlying type.
238 if (const EnumType
*EnumTy
= Ty
->getAs
<EnumType
>())
239 Ty
= EnumTy
->getDecl()->getIntegerType();
241 // Integer types smaller than a register are extended.
242 if (Size
< 64 && Ty
->isIntegerType())
243 return ABIArgInfo::getExtend(Ty
);
245 if (const auto *EIT
= Ty
->getAs
<BitIntType
>())
246 if (EIT
->getNumBits() < 64)
247 return ABIArgInfo::getExtend(Ty
);
249 // Other non-aggregates go in registers.
250 if (!isAggregateTypeForABI(Ty
))
251 return ABIArgInfo::getDirect();
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 if (CGCXXABI::RecordArgABI RAA
= getRecordArgABI(Ty
, getCXXABI()))
256 return getNaturalAlignIndirect(Ty
, RAA
== CGCXXABI::RAA_DirectInMemory
);
258 // This is a small aggregate type that should be passed in registers.
259 // Build a coercion type from the LLVM struct type.
260 llvm::StructType
*StrTy
= dyn_cast
<llvm::StructType
>(CGT
.ConvertType(Ty
));
262 return ABIArgInfo::getDirect();
264 CoerceBuilder
CB(getVMContext(), getDataLayout());
265 CB
.addStruct(0, StrTy
);
266 // All structs, even empty ones, should take up a register argument slot,
267 // so pin the minimum struct size to one bit.
268 CB
.pad(llvm::alignTo(
269 std::max(CB
.DL
.getTypeSizeInBits(StrTy
).getKnownMinValue(), uint64_t(1)),
272 // Try to use the original type for coercion.
273 llvm::Type
*CoerceTy
= CB
.isUsableType(StrTy
) ? StrTy
: CB
.getType();
276 return ABIArgInfo::getDirectInReg(CoerceTy
);
278 return ABIArgInfo::getDirect(CoerceTy
);
281 RValue
SparcV9ABIInfo::EmitVAArg(CodeGenFunction
&CGF
, Address VAListAddr
,
282 QualType Ty
, AggValueSlot Slot
) const {
283 ABIArgInfo AI
= classifyType(Ty
, 16 * 8);
284 llvm::Type
*ArgTy
= CGT
.ConvertType(Ty
);
285 if (AI
.canHaveCoerceToType() && !AI
.getCoerceToType())
286 AI
.setCoerceToType(ArgTy
);
288 CharUnits SlotSize
= CharUnits::fromQuantity(8);
290 CGBuilderTy
&Builder
= CGF
.Builder
;
291 Address Addr
= Address(Builder
.CreateLoad(VAListAddr
, "ap.cur"),
292 getVAListElementType(CGF
), SlotSize
);
293 llvm::Type
*ArgPtrTy
= CGF
.UnqualPtrTy
;
295 auto TypeInfo
= getContext().getTypeInfoInChars(Ty
);
297 Address ArgAddr
= Address::invalid();
299 switch (AI
.getKind()) {
300 case ABIArgInfo::Expand
:
301 case ABIArgInfo::CoerceAndExpand
:
302 case ABIArgInfo::InAlloca
:
303 llvm_unreachable("Unsupported ABI kind for va_arg");
305 case ABIArgInfo::Extend
: {
307 CharUnits Offset
= SlotSize
- TypeInfo
.Width
;
308 ArgAddr
= Builder
.CreateConstInBoundsByteGEP(Addr
, Offset
, "extend");
312 case ABIArgInfo::Direct
: {
313 auto AllocSize
= getDataLayout().getTypeAllocSize(AI
.getCoerceToType());
314 Stride
= CharUnits::fromQuantity(AllocSize
).alignTo(SlotSize
);
319 case ABIArgInfo::Indirect
:
320 case ABIArgInfo::IndirectAliased
:
322 ArgAddr
= Addr
.withElementType(ArgPtrTy
);
323 ArgAddr
= Address(Builder
.CreateLoad(ArgAddr
, "indirect.arg"), ArgTy
,
327 case ABIArgInfo::Ignore
:
328 return Slot
.asRValue();
332 Address NextPtr
= Builder
.CreateConstInBoundsByteGEP(Addr
, Stride
, "ap.next");
333 Builder
.CreateStore(NextPtr
.emitRawPointer(CGF
), VAListAddr
);
335 return CGF
.EmitLoadOfAnyValue(
336 CGF
.MakeAddrLValue(ArgAddr
.withElementType(ArgTy
), Ty
), Slot
);
339 void SparcV9ABIInfo::computeInfo(CGFunctionInfo
&FI
) const {
340 FI
.getReturnInfo() = classifyType(FI
.getReturnType(), 32 * 8);
341 for (auto &I
: FI
.arguments())
342 I
.info
= classifyType(I
.type
, 16 * 8);
346 class SparcV9TargetCodeGenInfo
: public TargetCodeGenInfo
{
348 SparcV9TargetCodeGenInfo(CodeGenTypes
&CGT
)
349 : TargetCodeGenInfo(std::make_unique
<SparcV9ABIInfo
>(CGT
)) {}
351 int getDwarfEHStackPointer(CodeGen::CodeGenModule
&M
) const override
{
355 bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction
&CGF
,
356 llvm::Value
*Address
) const override
;
358 llvm::Value
*decodeReturnAddress(CodeGen::CodeGenFunction
&CGF
,
359 llvm::Value
*Address
) const override
{
360 return CGF
.Builder
.CreateGEP(CGF
.Int8Ty
, Address
,
361 llvm::ConstantInt::get(CGF
.Int32Ty
, 8));
364 llvm::Value
*encodeReturnAddress(CodeGen::CodeGenFunction
&CGF
,
365 llvm::Value
*Address
) const override
{
366 return CGF
.Builder
.CreateGEP(CGF
.Int8Ty
, Address
,
367 llvm::ConstantInt::get(CGF
.Int32Ty
, -8));
370 } // end anonymous namespace
373 SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction
&CGF
,
374 llvm::Value
*Address
) const {
375 // This is calculated from the LLVM and GCC tables and verified
376 // against gcc output. AFAIK all ABIs use the same encoding.
378 CodeGen::CGBuilderTy
&Builder
= CGF
.Builder
;
380 llvm::IntegerType
*i8
= CGF
.Int8Ty
;
381 llvm::Value
*Four8
= llvm::ConstantInt::get(i8
, 4);
382 llvm::Value
*Eight8
= llvm::ConstantInt::get(i8
, 8);
384 // 0-31: the 8-byte general-purpose registers
385 AssignToArrayRange(Builder
, Address
, Eight8
, 0, 31);
387 // 32-63: f0-31, the 4-byte floating-point registers
388 AssignToArrayRange(Builder
, Address
, Four8
, 32, 63);
398 AssignToArrayRange(Builder
, Address
, Eight8
, 64, 71);
400 // 72-87: d0-15, the 8-byte floating-point registers
401 AssignToArrayRange(Builder
, Address
, Eight8
, 72, 87);
406 std::unique_ptr
<TargetCodeGenInfo
>
407 CodeGen::createSparcV8TargetCodeGenInfo(CodeGenModule
&CGM
) {
408 return std::make_unique
<SparcV8TargetCodeGenInfo
>(CGM
.getTypes());
411 std::unique_ptr
<TargetCodeGenInfo
>
412 CodeGen::createSparcV9TargetCodeGenInfo(CodeGenModule
&CGM
) {
413 return std::make_unique
<SparcV9TargetCodeGenInfo
>(CGM
.getTypes());