diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 71 | ||||
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp | 7 | ||||
-rw-r--r-- | llvm/lib/CodeGen/LowLevelType.cpp | 18 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64CallLowering.cpp | 188 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64CallLowering.h | 14 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64CallingConvention.td | 1 |
6 files changed, 200 insertions, 99 deletions
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index de63280fd71..578556cc8bb 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -16,18 +16,28 @@ #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Module.h" +#include "llvm/Target/TargetLowering.h" using namespace llvm; bool CallLowering::lowerCall( MachineIRBuilder &MIRBuilder, const CallInst &CI, unsigned ResReg, ArrayRef<unsigned> ArgRegs, std::function<unsigned()> GetCalleeReg) const { + auto &DL = CI.getParent()->getParent()->getParent()->getDataLayout(); + // First step is to marshall all the function's parameters into the correct // physregs and memory locations. Gather the sequence of argument types that // we'll pass to the assigner function. - SmallVector<Type *, 8> ArgTys; - for (auto &Arg : CI.arg_operands()) - ArgTys.push_back(Arg->getType()); + SmallVector<ArgInfo, 8> OrigArgs; + unsigned i = 0; + for (auto &Arg : CI.arg_operands()) { + ArgInfo OrigArg{ArgRegs[i], Arg->getType(), ISD::ArgFlagsTy{}}; + setArgFlags(OrigArg, i + 1, DL, CI); + OrigArgs.push_back(OrigArg); + ++i; + } MachineOperand Callee = MachineOperand::CreateImm(0); if (Function *F = CI.getCalledFunction()) @@ -35,5 +45,58 @@ bool CallLowering::lowerCall( else Callee = MachineOperand::CreateReg(GetCalleeReg(), false); - return lowerCall(MIRBuilder, Callee, CI.getType(), ResReg, ArgTys, ArgRegs); + ArgInfo OrigRet{ResReg, CI.getType(), ISD::ArgFlagsTy{}}; + if (!OrigRet.Ty->isVoidTy()) + setArgFlags(OrigRet, AttributeSet::ReturnIndex, DL, CI); + + return lowerCall(MIRBuilder, Callee, OrigRet, OrigArgs); } + +template <typename FuncInfoTy> +void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx, + const DataLayout &DL, + const FuncInfoTy &FuncInfo) const { + const AttributeSet &Attrs = FuncInfo.getAttributes(); + if (Attrs.hasAttribute(OpIdx, Attribute::ZExt)) + Arg.Flags.setZExt(); + if (Attrs.hasAttribute(OpIdx, Attribute::SExt)) + Arg.Flags.setSExt(); + if (Attrs.hasAttribute(OpIdx, Attribute::InReg)) + Arg.Flags.setInReg(); + if (Attrs.hasAttribute(OpIdx, Attribute::StructRet)) + Arg.Flags.setSRet(); + if (Attrs.hasAttribute(OpIdx, Attribute::SwiftSelf)) + Arg.Flags.setSwiftSelf(); + if (Attrs.hasAttribute(OpIdx, Attribute::SwiftError)) + Arg.Flags.setSwiftError(); + if (Attrs.hasAttribute(OpIdx, Attribute::ByVal)) + Arg.Flags.setByVal(); + if (Attrs.hasAttribute(OpIdx, Attribute::InAlloca)) + Arg.Flags.setInAlloca(); + + if (Arg.Flags.isByVal() || Arg.Flags.isInAlloca()) { + Type *ElementTy = cast<PointerType>(Arg.Ty)->getElementType(); + Arg.Flags.setByValSize(DL.getTypeAllocSize(ElementTy)); + // For ByVal, alignment should be passed from FE. BE will guess if + // this info is not there but there are cases it cannot get right. + unsigned FrameAlign; + if (FuncInfo.getParamAlignment(OpIdx)) + FrameAlign = FuncInfo.getParamAlignment(OpIdx); + else + FrameAlign = getTLI()->getByValTypeAlignment(ElementTy, DL); + Arg.Flags.setByValAlign(FrameAlign); + } + if (Attrs.hasAttribute(OpIdx, Attribute::Nest)) + Arg.Flags.setNest(); + Arg.Flags.setOrigAlign(DL.getABITypeAlignment(Arg.Ty)); +} + +template void +CallLowering::setArgFlags<Function>(CallLowering::ArgInfo &Arg, unsigned OpIdx, + const DataLayout &DL, + const Function &FuncInfo) const; + +template void +CallLowering::setArgFlags<CallInst>(CallLowering::ArgInfo &Arg, unsigned OpIdx, + const DataLayout &DL, + const CallInst &FuncInfo) const; diff --git a/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp b/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp index ede2bc23393..d6368b3d969 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp @@ -109,9 +109,10 @@ MachineLegalizeHelper::libcall(MachineInstr &MI) { const char *Name = TLI.getLibcallName(Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32); - CLI.lowerCall(MIRBuilder, MachineOperand::CreateES(Name), Ty, - MI.getOperand(0).getReg(), {Ty, Ty}, - {MI.getOperand(1).getReg(), MI.getOperand(2).getReg()}); + CLI.lowerCall( + MIRBuilder, MachineOperand::CreateES(Name), + {MI.getOperand(0).getReg(), Ty}, + {{MI.getOperand(1).getReg(), Ty}, {MI.getOperand(2).getReg(), Ty}}); MI.eraseFromParent(); return Legalized; } diff --git a/llvm/lib/CodeGen/LowLevelType.cpp b/llvm/lib/CodeGen/LowLevelType.cpp index fd235f2cfd1..d74b7306e0f 100644 --- a/llvm/lib/CodeGen/LowLevelType.cpp +++ b/llvm/lib/CodeGen/LowLevelType.cpp @@ -40,6 +40,24 @@ LLT::LLT(Type &Ty, const DataLayout &DL) { } } +LLT::LLT(MVT VT) { + if (VT.isVector()) { + SizeInBits = VT.getVectorElementType().getSizeInBits(); + ElementsOrAddrSpace = VT.getVectorNumElements(); + Kind = ElementsOrAddrSpace == 1 ? Scalar : Vector; + } else if (VT.isValid()) { + // Aggregates are no different from real scalars as far as GlobalISel is + // concerned. + Kind = Scalar; + SizeInBits = VT.getSizeInBits(); + ElementsOrAddrSpace = 1; + assert(SizeInBits != 0 && "invalid zero-sized type"); + } else { + Kind = Invalid; + SizeInBits = ElementsOrAddrSpace = 0; + } +} + void LLT::print(raw_ostream &OS) const { if (isVector()) OS << "<" << ElementsOrAddrSpace << " x s" << SizeInBits << ">"; diff --git a/llvm/lib/Target/AArch64/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/AArch64CallLowering.cpp index 0a3b911dfb8..3cf4eea6bb6 100644 --- a/llvm/lib/Target/AArch64/AArch64CallLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64CallLowering.cpp @@ -35,8 +35,7 @@ AArch64CallLowering::AArch64CallLowering(const AArch64TargetLowering &TLI) bool AArch64CallLowering::handleAssignments(MachineIRBuilder &MIRBuilder, CCAssignFn *AssignFn, - ArrayRef<Type *> ArgTypes, - ArrayRef<unsigned> ArgRegs, + ArrayRef<ArgInfo> Args, AssignFnTy AssignValToReg) const { MachineFunction &MF = MIRBuilder.getMF(); const Function &F = *MF.getFunction(); @@ -44,81 +43,90 @@ bool AArch64CallLowering::handleAssignments(MachineIRBuilder &MIRBuilder, SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, F.getContext()); - unsigned NumArgs = ArgTypes.size(); - auto CurTy = ArgTypes.begin(); - for (unsigned i = 0; i != NumArgs; ++i, ++CurTy) { - MVT CurVT = MVT::getVT(*CurTy); - if (AssignFn(i, CurVT, CurVT, CCValAssign::Full, ISD::ArgFlagsTy(), CCInfo)) + unsigned NumArgs = Args.size(); + for (unsigned i = 0; i != NumArgs; ++i) { + MVT CurVT = MVT::getVT(Args[i].Ty); + if (AssignFn(i, CurVT, CurVT, CCValAssign::Full, Args[i].Flags, CCInfo)) return false; } - assert(ArgLocs.size() == ArgTypes.size() && - "We have a different number of location and args?!"); - for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + for (unsigned i = 0, e = Args.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; // FIXME: Support non-register argument. if (!VA.isRegLoc()) return false; - switch (VA.getLocInfo()) { - default: - // Unknown loc info! - return false; - case CCValAssign::Full: - break; - case CCValAssign::BCvt: - // We don't care about bitcast. - break; - case CCValAssign::AExt: - // Existing high bits are fine for anyext (whatever they are). - break; - case CCValAssign::SExt: - case CCValAssign::ZExt: - // Zero/Sign extend the register. - // FIXME: Not yet implemented - return false; - } - // Everything checks out, tell the caller where we've decided this // parameter/return value should go. - AssignValToReg(MIRBuilder, ArgTypes[i], ArgRegs[i], VA.getLocReg()); + AssignValToReg(MIRBuilder, Args[i].Ty, Args[i].Reg, VA); } return true; } -void AArch64CallLowering::splitToValueTypes( - unsigned Reg, Type *Ty, SmallVectorImpl<unsigned> &SplitRegs, - SmallVectorImpl<Type *> &SplitTys, const DataLayout &DL, - MachineRegisterInfo &MRI, SplitArgTy SplitArg) const { +void AArch64CallLowering::splitToValueTypes(const ArgInfo &OrigArg, + SmallVectorImpl<ArgInfo> &SplitArgs, + const DataLayout &DL, + MachineRegisterInfo &MRI, + SplitArgTy PerformArgSplit) const { const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>(); - LLVMContext &Ctx = Ty->getContext(); + LLVMContext &Ctx = OrigArg.Ty->getContext(); SmallVector<EVT, 4> SplitVTs; SmallVector<uint64_t, 4> Offsets; - ComputeValueVTs(TLI, DL, Ty, SplitVTs, &Offsets, 0); + ComputeValueVTs(TLI, DL, OrigArg.Ty, SplitVTs, &Offsets, 0); if (SplitVTs.size() == 1) { // No splitting to do, just forward the input directly. - SplitTys.push_back(Ty); - SplitRegs.push_back(Reg); + SplitArgs.push_back(OrigArg); return; } - unsigned FirstRegIdx = SplitRegs.size(); + unsigned FirstRegIdx = SplitArgs.size(); for (auto SplitVT : SplitVTs) { + // FIXME: set split flags if they're actually used (e.g. i128 on AAPCS). Type *SplitTy = SplitVT.getTypeForEVT(Ctx); - SplitRegs.push_back(MRI.createGenericVirtualRegister(LLT{*SplitTy, DL})); - SplitTys.push_back(SplitTy); + SplitArgs.push_back( + ArgInfo{MRI.createGenericVirtualRegister(LLT{*SplitTy, DL}), SplitTy, + OrigArg.Flags}); } SmallVector<uint64_t, 4> BitOffsets; for (auto Offset : Offsets) BitOffsets.push_back(Offset * 8); - SplitArg(ArrayRef<unsigned>(&SplitRegs[FirstRegIdx], SplitRegs.end()), - BitOffsets); + SmallVector<unsigned, 8> SplitRegs; + for (auto I = &SplitArgs[FirstRegIdx]; I != SplitArgs.end(); ++I) + SplitRegs.push_back(I->Reg); + + PerformArgSplit(SplitRegs, BitOffsets); +} + +static void copyToPhysReg(MachineIRBuilder &MIRBuilder, unsigned ValReg, + CCValAssign &VA, MachineRegisterInfo &MRI) { + LLT LocTy{VA.getLocVT()}; + switch (VA.getLocInfo()) { + default: break; + case CCValAssign::AExt: + assert(!VA.getLocVT().isVector() && "unexpected vector extend"); + // Otherwise, it's a nop. + break; + case CCValAssign::SExt: { + unsigned NewReg = MRI.createGenericVirtualRegister(LocTy); + MIRBuilder.buildSExt(NewReg, ValReg); + ValReg = NewReg; + break; + } + case CCValAssign::ZExt: { + unsigned NewReg = MRI.createGenericVirtualRegister(LocTy); + MIRBuilder.buildZExt(NewReg, ValReg); + ValReg = NewReg; + break; + } + } + MIRBuilder.buildCopy(VA.getLocReg(), ValReg); } + bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, unsigned VReg) const { MachineFunction &MF = MIRBuilder.getMF(); @@ -135,18 +143,20 @@ bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI = MF.getRegInfo(); auto &DL = F.getParent()->getDataLayout(); - SmallVector<Type *, 8> SplitTys; - SmallVector<unsigned, 8> SplitRegs; - splitToValueTypes(VReg, Val->getType(), SplitRegs, SplitTys, DL, MRI, + ArgInfo OrigArg{VReg, Val->getType()}; + setArgFlags(OrigArg, AttributeSet::ReturnIndex, DL, F); + + SmallVector<ArgInfo, 8> SplitArgs; + splitToValueTypes(OrigArg, SplitArgs, DL, MRI, [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) { MIRBuilder.buildExtract(Regs, Offsets, VReg); }); - return handleAssignments(MIRBuilder, AssignFn, SplitTys, SplitRegs, + return handleAssignments(MIRBuilder, AssignFn, SplitArgs, [&](MachineIRBuilder &MIRBuilder, Type *Ty, - unsigned ValReg, unsigned PhysReg) { - MIRBuilder.buildCopy(PhysReg, ValReg); - MIB.addUse(PhysReg, RegState::Implicit); + unsigned ValReg, CCValAssign &VA) { + copyToPhysReg(MIRBuilder, ValReg, VA, MRI); + MIB.addUse(VA.getLocReg(), RegState::Implicit); }); } return true; @@ -161,12 +171,12 @@ bool AArch64CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI = MF.getRegInfo(); auto &DL = F.getParent()->getDataLayout(); - SmallVector<MachineInstr *, 8> Seqs; - SmallVector<Type *, 8> SplitTys; - SmallVector<unsigned, 8> SplitRegs; + SmallVector<ArgInfo, 8> SplitArgs; unsigned i = 0; for (auto &Arg : Args) { - splitToValueTypes(VRegs[i], Arg.getType(), SplitRegs, SplitTys, DL, MRI, + ArgInfo OrigArg{VRegs[i], Arg.getType()}; + setArgFlags(OrigArg, i + 1, DL, F); + splitToValueTypes(OrigArg, SplitArgs, DL, MRI, [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) { MIRBuilder.buildSequence(VRegs[i], Regs, Offsets); }); @@ -180,34 +190,36 @@ bool AArch64CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, CCAssignFn *AssignFn = TLI.CCAssignFnForCall(F.getCallingConv(), /*IsVarArg=*/false); - bool Res = handleAssignments(MIRBuilder, AssignFn, SplitTys, SplitRegs, - [](MachineIRBuilder &MIRBuilder, Type *Ty, - unsigned ValReg, unsigned PhysReg) { - MIRBuilder.getMBB().addLiveIn(PhysReg); - MIRBuilder.buildCopy(ValReg, PhysReg); - }); + if (!handleAssignments(MIRBuilder, AssignFn, SplitArgs, + [](MachineIRBuilder &MIRBuilder, Type *Ty, + unsigned ValReg, CCValAssign &VA) { + // FIXME: a sign/zeroext loc actually gives + // us an optimization hint. We should use it. + MIRBuilder.getMBB().addLiveIn(VA.getLocReg()); + MIRBuilder.buildCopy(ValReg, VA.getLocReg()); + })) + return false; // Move back to the end of the basic block. MIRBuilder.setMBB(MBB); - return Res; + return true; } bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, - const MachineOperand &Callee, Type *ResTy, - unsigned ResReg, ArrayRef<Type *> ArgTys, - ArrayRef<unsigned> ArgRegs) const { + const MachineOperand &Callee, + const ArgInfo &OrigRet, + ArrayRef<ArgInfo> OrigArgs) const { MachineFunction &MF = MIRBuilder.getMF(); const Function &F = *MF.getFunction(); MachineRegisterInfo &MRI = MF.getRegInfo(); auto &DL = F.getParent()->getDataLayout(); - SmallVector<Type *, 8> SplitTys; - SmallVector<unsigned, 8> SplitRegs; - for (unsigned i = 0; i < ArgTys.size(); ++i) { - splitToValueTypes(ArgRegs[i], ArgTys[i], SplitRegs, SplitTys, DL, MRI, + SmallVector<ArgInfo, 8> SplitArgs; + for (auto &OrigArg : OrigArgs) { + splitToValueTypes(OrigArg, SplitArgs, DL, MRI, [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) { - MIRBuilder.buildExtract(Regs, Offsets, ArgRegs[i]); + MIRBuilder.buildExtract(Regs, Offsets, OrigArg.Reg); }); } @@ -219,12 +231,13 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, // And finally we can do the actual assignments. For a call we need to keep // track of the registers used because they'll be implicit uses of the BL. SmallVector<unsigned, 8> PhysRegs; - handleAssignments(MIRBuilder, CallAssignFn, SplitTys, SplitRegs, - [&](MachineIRBuilder &MIRBuilder, Type *Ty, unsigned ValReg, - unsigned PhysReg) { - MIRBuilder.buildCopy(PhysReg, ValReg); - PhysRegs.push_back(PhysReg); - }); + if (!handleAssignments(MIRBuilder, CallAssignFn, SplitArgs, + [&](MachineIRBuilder &MIRBuilder, Type *Ty, + unsigned ValReg, CCValAssign &VA) { + copyToPhysReg(MIRBuilder, ValReg, VA, MRI); + PhysRegs.push_back(VA.getLocReg()); + })) + return false; // Now we can build the actual call instruction. auto MIB = MIRBuilder.buildInstr(Callee.isReg() ? AArch64::BLR : AArch64::BL); @@ -241,26 +254,31 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, // symmetry with the arugments, the physical register must be an // implicit-define of the call instruction. CCAssignFn *RetAssignFn = TLI.CCAssignFnForReturn(F.getCallingConv()); - if (ResReg) { - SplitTys.clear(); - SplitRegs.clear(); + if (OrigRet.Reg) { + SplitArgs.clear(); SmallVector<uint64_t, 8> RegOffsets; - splitToValueTypes(ResReg, ResTy, SplitRegs, SplitTys, DL, MRI, + SmallVector<unsigned, 8> SplitRegs; + splitToValueTypes(OrigRet, SplitArgs, DL, MRI, [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) { std::copy(Offsets.begin(), Offsets.end(), std::back_inserter(RegOffsets)); + std::copy(Regs.begin(), Regs.end(), + std::back_inserter(SplitRegs)); }); - handleAssignments(MIRBuilder, RetAssignFn, SplitTys, SplitRegs, + if (!handleAssignments(MIRBuilder, RetAssignFn, SplitArgs, [&](MachineIRBuilder &MIRBuilder, Type *Ty, - unsigned ValReg, unsigned PhysReg) { - MIRBuilder.buildCopy(ValReg, PhysReg); - MIB.addDef(PhysReg, RegState::Implicit); - }); + unsigned ValReg, CCValAssign &VA) { + // FIXME: a sign/zeroext loc actually gives + // us an optimization hint. We should use it. + MIRBuilder.buildCopy(ValReg, VA.getLocReg()); + MIB.addDef(VA.getLocReg(), RegState::Implicit); + })) + return false; if (!RegOffsets.empty()) - MIRBuilder.buildSequence(ResReg, SplitRegs, RegOffsets); + MIRBuilder.buildSequence(OrigRet.Reg, SplitRegs, RegOffsets); } return true; diff --git a/llvm/lib/Target/AArch64/AArch64CallLowering.h b/llvm/lib/Target/AArch64/AArch64CallLowering.h index 452551d98ae..baf063aa3ea 100644 --- a/llvm/lib/Target/AArch64/AArch64CallLowering.h +++ b/llvm/lib/Target/AArch64/AArch64CallLowering.h @@ -34,24 +34,24 @@ class AArch64CallLowering: public CallLowering { ArrayRef<unsigned> VRegs) const override; bool lowerCall(MachineIRBuilder &MIRBuilder, const MachineOperand &Callee, - Type *ResTy, unsigned ResReg, ArrayRef<Type *> ArgTys, - ArrayRef<unsigned> ArgRegs) const override; + const ArgInfo &OrigRet, + ArrayRef<ArgInfo> OrigArgs) const override; private: - typedef std::function<void(MachineIRBuilder &, Type *, unsigned, unsigned)> + typedef std::function<void(MachineIRBuilder &, Type *, unsigned, + CCValAssign &)> AssignFnTy; typedef std::function<void(ArrayRef<unsigned>, ArrayRef<uint64_t>)> SplitArgTy; - void splitToValueTypes(unsigned Reg, Type *Ty, - SmallVectorImpl<unsigned> &SplitRegs, - SmallVectorImpl<Type *> &SplitTys, + void splitToValueTypes(const ArgInfo &OrigArgInfo, + SmallVectorImpl<ArgInfo> &SplitArgs, const DataLayout &DL, MachineRegisterInfo &MRI, SplitArgTy SplitArg) const; bool handleAssignments(MachineIRBuilder &MIRBuilder, CCAssignFn *AssignFn, - ArrayRef<Type *> ArgsTypes, ArrayRef<unsigned> ArgRegs, + ArrayRef<ArgInfo> Args, AssignFnTy AssignValToReg) const; }; } // End of namespace llvm; diff --git a/llvm/lib/Target/AArch64/AArch64CallingConvention.td b/llvm/lib/Target/AArch64/AArch64CallingConvention.td index 41ad0a8a8c5..9058617768d 100644 --- a/llvm/lib/Target/AArch64/AArch64CallingConvention.td +++ b/llvm/lib/Target/AArch64/AArch64CallingConvention.td @@ -100,6 +100,7 @@ def RetCC_AArch64_AAPCS : CallingConv<[ CCIfBigEndian<CCIfType<[v2i64, v2f64, v4i32, v4f32, v8i16, v8f16, v16i8], CCBitConvertToType<f128>>>, + CCIfType<[i1, i8, i16], CCPromoteToType<i32>>, CCIfType<[i32], CCAssignToRegWithShadow<[W0, W1, W2, W3, W4, W5, W6, W7], [X0, X1, X2, X3, X4, X5, X6, X7]>>, CCIfType<[i64], CCAssignToRegWithShadow<[X0, X1, X2, X3, X4, X5, X6, X7], |