forked from OSchip/llvm-project
Add a SparcV9ABIInfo class for handling the standard SPARC v9 ABI.
- All integer arguments smaller than 64 bits are extended. - Large structs are passed indirectly, not using 'byval'. - Structs up to 32 bytes in size are returned in registers. Some things are not implemented yet: - EmitVAArg can be implemented in terms of the va_arg instruction. - When structs are passed in registers, float members require special handling because they are passed in the floating point registers. - Structs are left-aligned when passed in registers. This may require padding. llvm-svn: 182745
This commit is contained in:
parent
9d9e1fc479
commit
d28ab7e802
|
@ -5125,6 +5125,97 @@ llvm::Value *HexagonABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
|||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SPARC v9 ABI Implementation.
|
||||
// Based on the SPARC Compliance Definition version 2.4.1.
|
||||
//
|
||||
// Function arguments a mapped to a nominal "parameter array" and promoted to
|
||||
// registers depending on their type. Each argument occupies 8 or 16 bytes in
|
||||
// the array, structs larger than 16 bytes are passed indirectly.
|
||||
//
|
||||
// One case requires special care:
|
||||
//
|
||||
// struct mixed {
|
||||
// int i;
|
||||
// float f;
|
||||
// };
|
||||
//
|
||||
// When a struct mixed is passed by value, it only occupies 8 bytes in the
|
||||
// parameter array, but the int is passed in an integer register, and the float
|
||||
// is passed in a floating point register. This is represented as two arguments
|
||||
// with the LLVM IR inreg attribute:
|
||||
//
|
||||
// declare void f(i32 inreg %i, float inreg %f)
|
||||
//
|
||||
// The code generator will only allocate 4 bytes from the parameter array for
|
||||
// the inreg arguments. All other arguments are allocated a multiple of 8
|
||||
// bytes.
|
||||
//
|
||||
namespace {
|
||||
class SparcV9ABIInfo : public ABIInfo {
|
||||
public:
|
||||
SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
|
||||
|
||||
private:
|
||||
ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const;
|
||||
virtual void computeInfo(CGFunctionInfo &FI) const;
|
||||
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
||||
CodeGenFunction &CGF) const;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ABIArgInfo
|
||||
SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
|
||||
if (Ty->isVoidType())
|
||||
return ABIArgInfo::getIgnore();
|
||||
|
||||
uint64_t Size = getContext().getTypeSize(Ty);
|
||||
|
||||
// Anything too big to fit in registers is passed with an explicit indirect
|
||||
// pointer / sret pointer.
|
||||
if (Size > SizeLimit)
|
||||
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
|
||||
|
||||
// Treat an enum type as its underlying type.
|
||||
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
|
||||
Ty = EnumTy->getDecl()->getIntegerType();
|
||||
|
||||
// Integer types smaller than a register are extended.
|
||||
if (Size < 64 && Ty->isIntegerType())
|
||||
return ABIArgInfo::getExtend();
|
||||
|
||||
// Other non-aggregates go in registers.
|
||||
if (!isAggregateTypeForABI(Ty))
|
||||
return ABIArgInfo::getDirect();
|
||||
|
||||
// This is a small aggregate type that should be passed in registers.
|
||||
// FIXME: Compute the correct coersion type.
|
||||
// FIXME: Ensure any float members are passed in float registers.
|
||||
return ABIArgInfo::getDirect();
|
||||
}
|
||||
|
||||
llvm::Value *SparcV9ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
||||
CodeGenFunction &CGF) const {
|
||||
// FIXME: Implement with va_arg.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
||||
FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8);
|
||||
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
|
||||
it != ie; ++it)
|
||||
it->info = classifyType(it->type, 16 * 8);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo {
|
||||
public:
|
||||
SparcV9TargetCodeGenInfo(CodeGenTypes &CGT)
|
||||
: TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
|
||||
if (TheTargetCodeGenInfo)
|
||||
return *TheTargetCodeGenInfo;
|
||||
|
@ -5240,5 +5331,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
|
|||
}
|
||||
case llvm::Triple::hexagon:
|
||||
return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types));
|
||||
case llvm::Triple::sparcv9:
|
||||
return *(TheTargetCodeGenInfo = new SparcV9TargetCodeGenInfo(Types));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// RUN: %clang_cc1 -triple sparcv9-unknown-linux -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
// CHECK: define void @f_void()
|
||||
void f_void(void) {}
|
||||
|
||||
// Arguments and return values smaller than the word size are extended.
|
||||
|
||||
// CHECK: define signext i32 @f_int_1(i32 signext %x)
|
||||
int f_int_1(int x) { return x; }
|
||||
|
||||
// CHECK: define zeroext i32 @f_int_2(i32 zeroext %x)
|
||||
unsigned f_int_2(unsigned x) { return x; }
|
||||
|
||||
// CHECK: define i64 @f_int_3(i64 %x)
|
||||
long long f_int_3(long long x) { return x; }
|
||||
|
||||
// CHECK: define signext i8 @f_int_4(i8 signext %x)
|
||||
char f_int_4(char x) { return x; }
|
||||
|
||||
// Small structs are passed in registers.
|
||||
struct small {
|
||||
int *a, *b;
|
||||
};
|
||||
|
||||
// CHECK: define %struct.small @f_small(i32* %x.coerce0, i32* %x.coerce1)
|
||||
struct small f_small(struct small x) {
|
||||
x.a += *x.b;
|
||||
x.b = 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
// Medium-sized structs are passed indirectly, but can be returned in registers.
|
||||
struct medium {
|
||||
int *a, *b;
|
||||
int *c, *d;
|
||||
};
|
||||
|
||||
// CHECK: define %struct.medium @f_medium(%struct.medium* %x)
|
||||
struct medium f_medium(struct medium x) {
|
||||
x.a += *x.b;
|
||||
x.b = 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
// Large structs are also returned indirectly.
|
||||
struct large {
|
||||
int *a, *b;
|
||||
int *c, *d;
|
||||
int x;
|
||||
};
|
||||
|
||||
// CHECK: define void @f_large(%struct.large* noalias sret %agg.result, %struct.large* %x)
|
||||
struct large f_large(struct large x) {
|
||||
x.a += *x.b;
|
||||
x.b = 0;
|
||||
return x;
|
||||
}
|
||||
|
Loading…
Reference in New Issue