Skip to content

Commit 2b6d76f

Browse files
[Clang][AArch64] Fix Pure Scalables Types argument passing and return
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 ab90d27 commit 2b6d76f

File tree

4 files changed

+669
-69
lines changed

4 files changed

+669
-69
lines changed

clang/include/clang/CodeGen/CGFunctionInfo.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -272,11 +272,6 @@ class ABIArgInfo {
272272
unsigned unpaddedIndex = 0;
273273
for (auto eltType : coerceToType->elements()) {
274274
if (isPaddingForCoerceAndExpand(eltType)) continue;
275-
if (unpaddedStruct) {
276-
assert(unpaddedStruct->getElementType(unpaddedIndex) == eltType);
277-
} else {
278-
assert(unpaddedIndex == 0 && unpaddedCoerceToType == eltType);
279-
}
280275
unpaddedIndex++;
281276
}
282277

@@ -295,12 +290,8 @@ class ABIArgInfo {
295290
}
296291

297292
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-
}
293+
return eltType->isArrayTy() &&
294+
eltType->getArrayElementType()->isIntegerTy(8);
304295
}
305296

306297
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

@@ -5468,6 +5504,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
54685504
case ABIArgInfo::CoerceAndExpand: {
54695505
auto coercionType = ArgInfo.getCoerceAndExpandType();
54705506
auto layout = CGM.getDataLayout().getStructLayout(coercionType);
5507+
auto unpaddedCoercionType = ArgInfo.getUnpaddedCoerceAndExpandType();
5508+
auto *unpaddedStruct = dyn_cast<llvm::StructType>(unpaddedCoercionType);
54715509

54725510
llvm::Value *tempSize = nullptr;
54735511
Address addr = Address::invalid();
@@ -5498,11 +5536,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
54985536
addr = addr.withElementType(coercionType);
54995537

55005538
unsigned IRArgPos = FirstIRArg;
5539+
unsigned unpaddedIndex = 0;
55015540
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
55025541
llvm::Type *eltType = coercionType->getElementType(i);
55035542
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
55045543
Address eltAddr = Builder.CreateStructGEP(addr, i);
5505-
llvm::Value *elt = Builder.CreateLoad(eltAddr);
5544+
llvm::Value *elt = CreateCoercedLoad(
5545+
eltAddr,
5546+
unpaddedStruct ? unpaddedStruct->getElementType(unpaddedIndex++)
5547+
: unpaddedCoercionType,
5548+
*this);
55065549
if (ArgHasMaybeUndefAttr)
55075550
elt = Builder.CreateFreeze(elt);
55085551
IRCallArgs[IRArgPos++] = elt;

0 commit comments

Comments
 (0)