Skip to content

Commit 53f7f8e

Browse files
[Clang][AArch64] Fix Pure Scalables Types argument passing and return (#112747)
Pure Scalable Types are defined in AAPCS64 here: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#pure-scalable-types-psts And should be passed according to Rule C.7 here: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#682parameter-passing-rules This part of the ABI is completely unimplemented in Clang, instead it treats PSTs sometimes as HFAs/HVAs, sometime as general composite types. This patch implements the rules for passing PSTs by employing the `CoerceAndExpand` method and extending it to: * allow array types in the `coerceToType`; Now only `[N x i8]` are considered padding. * allow mismatch between the elements of the `coerceToType` and the elements of the `unpaddedCoerceToType`; AArch64 uses this to map fixed-length vector types to SVE vector types. Corectly passing a PST argument needs a decision in Clang about whether to pass it in memory or registers or, equivalently, whether to use the `Indirect` or `Expand/CoerceAndExpand` method. It was considered relatively harder (or not practically possible) to make that decision in the AArch64 backend. Hence this patch implements the register counting from AAPCS64 (cf. `NSRN`, `NPRN`) to guide the Clang's decision.
1 parent 7d1e98c commit 53f7f8e

File tree

5 files changed

+897
-78
lines changed

5 files changed

+897
-78
lines changed

clang/include/clang/CodeGen/CGFunctionInfo.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,8 @@ class ABIArgInfo {
271271
// in the unpadded type.
272272
unsigned unpaddedIndex = 0;
273273
for (auto eltType : coerceToType->elements()) {
274-
if (isPaddingForCoerceAndExpand(eltType)) continue;
275-
if (unpaddedStruct) {
276-
assert(unpaddedStruct->getElementType(unpaddedIndex) == eltType);
277-
} else {
278-
assert(unpaddedIndex == 0 && unpaddedCoerceToType == eltType);
279-
}
274+
if (isPaddingForCoerceAndExpand(eltType))
275+
continue;
280276
unpaddedIndex++;
281277
}
282278

@@ -295,12 +291,8 @@ class ABIArgInfo {
295291
}
296292

297293
static bool isPaddingForCoerceAndExpand(llvm::Type *eltType) {
298-
if (eltType->isArrayTy()) {
299-
assert(eltType->getArrayElementType()->isIntegerTy(8));
300-
return true;
301-
} else {
302-
return false;
303-
}
294+
return eltType->isArrayTy() &&
295+
eltType->getArrayElementType()->isIntegerTy(8);
304296
}
305297

306298
Kind getKind() const { return TheKind; }

clang/lib/CodeGen/CGCall.cpp

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,30 @@ static Address emitAddressAtOffset(CodeGenFunction &CGF, Address addr,
14101410
return addr;
14111411
}
14121412

1413+
static std::pair<llvm::Value *, bool>
1414+
CoerceScalableToFixed(CodeGenFunction &CGF, llvm::FixedVectorType *ToTy,
1415+
llvm::ScalableVectorType *FromTy, llvm::Value *V,
1416+
StringRef Name = "") {
1417+
// If we are casting a scalable i1 predicate vector to a fixed i8
1418+
// vector, first bitcast the source.
1419+
if (FromTy->getElementType()->isIntegerTy(1) &&
1420+
FromTy->getElementCount().isKnownMultipleOf(8) &&
1421+
ToTy->getElementType() == CGF.Builder.getInt8Ty()) {
1422+
FromTy = llvm::ScalableVectorType::get(
1423+
ToTy->getElementType(),
1424+
FromTy->getElementCount().getKnownMinValue() / 8);
1425+
V = CGF.Builder.CreateBitCast(V, FromTy);
1426+
}
1427+
if (FromTy->getElementType() == ToTy->getElementType()) {
1428+
llvm::Value *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty);
1429+
1430+
V->setName(Name + ".coerce");
1431+
V = CGF.Builder.CreateExtractVector(ToTy, V, Zero, "cast.fixed");
1432+
return {V, true};
1433+
}
1434+
return {V, false};
1435+
}
1436+
14131437
namespace {
14141438

14151439
/// Encapsulates information about the way function arguments from
@@ -3196,26 +3220,14 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
31963220
// a VLAT at the function boundary and the types match up, use
31973221
// llvm.vector.extract to convert back to the original VLST.
31983222
if (auto *VecTyTo = dyn_cast<llvm::FixedVectorType>(ConvertType(Ty))) {
3199-
llvm::Value *Coerced = Fn->getArg(FirstIRArg);
3223+
llvm::Value *ArgVal = Fn->getArg(FirstIRArg);
32003224
if (auto *VecTyFrom =
3201-
dyn_cast<llvm::ScalableVectorType>(Coerced->getType())) {
3202-
// If we are casting a scalable i1 predicate vector to a fixed i8
3203-
// vector, bitcast the source and use a vector extract.
3204-
if (VecTyFrom->getElementType()->isIntegerTy(1) &&
3205-
VecTyFrom->getElementCount().isKnownMultipleOf(8) &&
3206-
VecTyTo->getElementType() == Builder.getInt8Ty()) {
3207-
VecTyFrom = llvm::ScalableVectorType::get(
3208-
VecTyTo->getElementType(),
3209-
VecTyFrom->getElementCount().getKnownMinValue() / 8);
3210-
Coerced = Builder.CreateBitCast(Coerced, VecTyFrom);
3211-
}
3212-
if (VecTyFrom->getElementType() == VecTyTo->getElementType()) {
3213-
llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty);
3214-
3225+
dyn_cast<llvm::ScalableVectorType>(ArgVal->getType())) {
3226+
auto [Coerced, Extracted] = CoerceScalableToFixed(
3227+
*this, VecTyTo, VecTyFrom, ArgVal, Arg->getName());
3228+
if (Extracted) {
32153229
assert(NumIRArgs == 1);
3216-
Coerced->setName(Arg->getName() + ".coerce");
3217-
ArgVals.push_back(ParamValue::forDirect(Builder.CreateExtractVector(
3218-
VecTyTo, Coerced, Zero, "cast.fixed")));
3230+
ArgVals.push_back(ParamValue::forDirect(Coerced));
32193231
break;
32203232
}
32213233
}
@@ -3326,16 +3338,33 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
33263338
ArgVals.push_back(ParamValue::forIndirect(alloca));
33273339

33283340
auto coercionType = ArgI.getCoerceAndExpandType();
3341+
auto unpaddedCoercionType = ArgI.getUnpaddedCoerceAndExpandType();
3342+
auto *unpaddedStruct = dyn_cast<llvm::StructType>(unpaddedCoercionType);
3343+
33293344
alloca = alloca.withElementType(coercionType);
33303345

33313346
unsigned argIndex = FirstIRArg;
3347+
unsigned unpaddedIndex = 0;
33323348
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
33333349
llvm::Type *eltType = coercionType->getElementType(i);
33343350
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType))
33353351
continue;
33363352

33373353
auto eltAddr = Builder.CreateStructGEP(alloca, i);
3338-
auto elt = Fn->getArg(argIndex++);
3354+
llvm::Value *elt = Fn->getArg(argIndex++);
3355+
3356+
auto paramType = unpaddedStruct
3357+
? unpaddedStruct->getElementType(unpaddedIndex++)
3358+
: unpaddedCoercionType;
3359+
3360+
if (auto *VecTyTo = dyn_cast<llvm::FixedVectorType>(eltType)) {
3361+
if (auto *VecTyFrom = dyn_cast<llvm::ScalableVectorType>(paramType)) {
3362+
bool Extracted;
3363+
std::tie(elt, Extracted) = CoerceScalableToFixed(
3364+
*this, VecTyTo, VecTyFrom, elt, elt->getName());
3365+
assert(Extracted && "Unexpected scalable to fixed vector coercion");
3366+
}
3367+
}
33393368
Builder.CreateStore(elt, eltAddr);
33403369
}
33413370
assert(argIndex == FirstIRArg + NumIRArgs);
@@ -3930,17 +3959,24 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
39303959

39313960
case ABIArgInfo::CoerceAndExpand: {
39323961
auto coercionType = RetAI.getCoerceAndExpandType();
3962+
auto unpaddedCoercionType = RetAI.getUnpaddedCoerceAndExpandType();
3963+
auto *unpaddedStruct = dyn_cast<llvm::StructType>(unpaddedCoercionType);
39333964

39343965
// Load all of the coerced elements out into results.
39353966
llvm::SmallVector<llvm::Value*, 4> results;
39363967
Address addr = ReturnValue.withElementType(coercionType);
3968+
unsigned unpaddedIndex = 0;
39373969
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
39383970
auto coercedEltType = coercionType->getElementType(i);
39393971
if (ABIArgInfo::isPaddingForCoerceAndExpand(coercedEltType))
39403972
continue;
39413973

39423974
auto eltAddr = Builder.CreateStructGEP(addr, i);
3943-
auto elt = Builder.CreateLoad(eltAddr);
3975+
llvm::Value *elt = CreateCoercedLoad(
3976+
eltAddr,
3977+
unpaddedStruct ? unpaddedStruct->getElementType(unpaddedIndex++)
3978+
: unpaddedCoercionType,
3979+
*this);
39443980
results.push_back(elt);
39453981
}
39463982

@@ -5472,6 +5508,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
54725508
case ABIArgInfo::CoerceAndExpand: {
54735509
auto coercionType = ArgInfo.getCoerceAndExpandType();
54745510
auto layout = CGM.getDataLayout().getStructLayout(coercionType);
5511+
auto unpaddedCoercionType = ArgInfo.getUnpaddedCoerceAndExpandType();
5512+
auto *unpaddedStruct = dyn_cast<llvm::StructType>(unpaddedCoercionType);
54755513

54765514
llvm::Value *tempSize = nullptr;
54775515
Address addr = Address::invalid();
@@ -5502,11 +5540,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
55025540
addr = addr.withElementType(coercionType);
55035541

55045542
unsigned IRArgPos = FirstIRArg;
5543+
unsigned unpaddedIndex = 0;
55055544
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
55065545
llvm::Type *eltType = coercionType->getElementType(i);
55075546
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
55085547
Address eltAddr = Builder.CreateStructGEP(addr, i);
5509-
llvm::Value *elt = Builder.CreateLoad(eltAddr);
5548+
llvm::Value *elt = CreateCoercedLoad(
5549+
eltAddr,
5550+
unpaddedStruct ? unpaddedStruct->getElementType(unpaddedIndex++)
5551+
: unpaddedCoercionType,
5552+
*this);
55105553
if (ArgHasMaybeUndefAttr)
55115554
elt = Builder.CreateFreeze(elt);
55125555
IRCallArgs[IRArgPos++] = elt;

0 commit comments

Comments
 (0)