void AArch64CallLowering::splitToValueTypes(
const ArgInfo &OrigArg, SmallVectorImpl<ArgInfo> &SplitArgs,
- const DataLayout &DL, MachineRegisterInfo &MRI,
+ const DataLayout &DL, MachineRegisterInfo &MRI, CallingConv::ID CallConv,
const SplitArgTy &PerformArgSplit) const {
const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
LLVMContext &Ctx = OrigArg.Ty->getContext();
}
unsigned FirstRegIdx = SplitArgs.size();
+ bool NeedsRegBlock = TLI.functionArgumentNeedsConsecutiveRegisters(
+ OrigArg.Ty, CallConv, false);
for (auto SplitVT : SplitVTs) {
- // FIXME: set split flags if they're actually used (e.g. i128 on AAPCS).
Type *SplitTy = SplitVT.getTypeForEVT(Ctx);
SplitArgs.push_back(
ArgInfo{MRI.createGenericVirtualRegister(getLLTForType(*SplitTy, DL)),
SplitTy, OrigArg.Flags, OrigArg.IsFixed});
+ if (NeedsRegBlock)
+ SplitArgs.back().Flags.setInConsecutiveRegs();
}
+ SplitArgs.back().Flags.setInConsecutiveRegsLast();
+
for (unsigned i = 0; i < Offsets.size(); ++i)
PerformArgSplit(SplitArgs[FirstRegIdx + i].Reg, Offsets[i] * 8);
}
setArgFlags(OrigArg, AttributeList::ReturnIndex, DL, F);
SmallVector<ArgInfo, 8> SplitArgs;
- splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
+ splitToValueTypes(OrigArg, SplitArgs, DL, MRI, F.getCallingConv(),
[&](unsigned Reg, uint64_t Offset) {
MIRBuilder.buildExtract(Reg, VReg, Offset);
});
LLT Ty = MRI.getType(VRegs[i]);
unsigned Dst = VRegs[i];
- splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
+ splitToValueTypes(OrigArg, SplitArgs, DL, MRI, F.getCallingConv(),
[&](unsigned Reg, uint64_t Offset) {
if (!Split) {
Split = true;
SmallVector<ArgInfo, 8> SplitArgs;
for (auto &OrigArg : OrigArgs) {
- splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
+ splitToValueTypes(OrigArg, SplitArgs, DL, MRI, CallConv,
[&](unsigned Reg, uint64_t Offset) {
MIRBuilder.buildExtract(Reg, OrigArg.Reg, Offset);
});
SmallVector<uint64_t, 8> RegOffsets;
SmallVector<unsigned, 8> SplitRegs;
- splitToValueTypes(OrigRet, SplitArgs, DL, MRI,
+ splitToValueTypes(OrigRet, SplitArgs, DL, MRI, F.getCallingConv(),
[&](unsigned Reg, uint64_t Offset) {
RegOffsets.push_back(Offset);
SplitRegs.push_back(Reg);
void splitToValueTypes(const ArgInfo &OrigArgInfo,
SmallVectorImpl<ArgInfo> &SplitArgs,
const DataLayout &DL, MachineRegisterInfo &MRI,
+ CallingConv::ID CallConv,
const SplitArgTy &SplitArg) const;
};
MachineMemOperand::Flags getMMOFlags(const Instruction &I) const override;
+ bool functionArgumentNeedsConsecutiveRegisters(Type *Ty,
+ CallingConv::ID CallConv,
+ bool isVarArg) const override;
private:
bool isExtFreeImpl(const Instruction *Ext) const override;
void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue> &Results,
SelectionDAG &DAG) const override;
- bool functionArgumentNeedsConsecutiveRegisters(Type *Ty,
- CallingConv::ID CallConv,
- bool isVarArg) const override;
-
bool shouldNormalizeToSelectSequence(LLVMContext &, EVT) const override;
};
call signext i8 @test_stack_slots([8 x i64] undef, i8 signext 42, i8 signext 12)
ret void
}
+
+; CHECK-LABEL: name: test_128bit_struct
+; CHECK: %x0 = COPY
+; CHECK: %x1 = COPY
+; CHECK: %x2 = COPY
+; CHECK: BL @take_128bit_struct
+define void @test_128bit_struct([2 x i64]* %ptr) {
+ %struct = load [2 x i64], [2 x i64]* %ptr
+ call void @take_128bit_struct([2 x i64]* null, [2 x i64] %struct)
+ ret void
+}
+
+; CHECK-LABEL: name: take_128bit_struct
+; CHECK: {{%.*}}(p0) = COPY %x0
+; CHECK: {{%.*}}(s64) = COPY %x1
+; CHECK: {{%.*}}(s64) = COPY %x2
+define void @take_128bit_struct([2 x i64]* %ptr, [2 x i64] %in) {
+ store [2 x i64] %in, [2 x i64]* %ptr
+ ret void
+}
+
+; CHECK-LABEL: name: test_split_struct
+; CHECK: [[STRUCT:%[0-9]+]](s128) = G_LOAD {{.*}}(p0)
+; CHECK: [[LO:%[0-9]+]](s64) = G_EXTRACT [[STRUCT]](s128), 0
+; CHECK: [[HI:%[0-9]+]](s64) = G_EXTRACT [[STRUCT]](s128), 64
+
+; CHECK: [[SP:%[0-9]+]](p0) = COPY %sp
+; CHECK: [[OFF:%[0-9]+]](s64) = G_CONSTANT i64 0
+; CHECK: [[ADDR:%[0-9]+]](p0) = G_GEP [[SP]], [[OFF]]
+; CHECK: G_STORE [[LO]](s64), [[ADDR]](p0) :: (store 8 into stack, align 0)
+
+; CHECK: [[SP:%[0-9]+]](p0) = COPY %sp
+; CHECK: [[OFF:%[0-9]+]](s64) = G_CONSTANT i64 8
+; CHECK: [[ADDR:%[0-9]+]](p0) = G_GEP [[SP]], [[OFF]]
+; CHECK: G_STORE [[HI]](s64), [[ADDR]](p0) :: (store 8 into stack + 8, align 0)
+define void @test_split_struct([2 x i64]* %ptr) {
+ %struct = load [2 x i64], [2 x i64]* %ptr
+ call void @take_split_struct([2 x i64]* null, i64 1, i64 2, i64 3,
+ i64 4, i64 5, i64 6,
+ [2 x i64] %struct)
+ ret void
+}
+
+; CHECK-LABEL: name: take_split_struct
+; CHECK: fixedStack:
+; CHECK-DAG: - { id: [[LO_FRAME:[0-9]+]], type: default, offset: 0, size: 8
+; CHECK-DAG: - { id: [[HI_FRAME:[0-9]+]], type: default, offset: 8, size: 8
+
+; CHECK: [[LOPTR:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[LO_FRAME]]
+; CHECK: [[LO:%[0-9]+]](s64) = G_LOAD [[LOPTR]](p0) :: (invariant load 8 from %fixed-stack.[[LO_FRAME]], align 0)
+
+; CHECK: [[HIPTR:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[HI_FRAME]]
+; CHECK: [[HI:%[0-9]+]](s64) = G_LOAD [[HIPTR]](p0) :: (invariant load 8 from %fixed-stack.[[HI_FRAME]], align 0)
+define void @take_split_struct([2 x i64]* %ptr, i64, i64, i64,
+ i64, i64, i64,
+ [2 x i64] %in) {
+ store [2 x i64] %in, [2 x i64]* %ptr
+ ret void
+}
define void @test_mem_i1([8 x i64], i1 %in) {
ret void
}
+
+; CHECK-LABEL: name: test_128bit_struct
+; CHECK: %x0 = COPY
+; CHECK: %x1 = COPY
+; CHECK: %x2 = COPY
+; CHECK: BL @take_128bit_struct
+define void @test_128bit_struct([2 x i64]* %ptr) {
+ %struct = load [2 x i64], [2 x i64]* %ptr
+ call void @take_128bit_struct([2 x i64]* null, [2 x i64] %struct)
+ ret void
+}
+
+; CHECK-LABEL: name: take_128bit_struct
+; CHECK: {{%.*}}(p0) = COPY %x0
+; CHECK: {{%.*}}(s64) = COPY %x1
+; CHECK: {{%.*}}(s64) = COPY %x2
+define void @take_128bit_struct([2 x i64]* %ptr, [2 x i64] %in) {
+ store [2 x i64] %in, [2 x i64]* %ptr
+ ret void
+}
+
+; CHECK-LABEL: name: test_split_struct
+; CHECK: [[STRUCT:%[0-9]+]](s128) = G_LOAD {{.*}}(p0)
+; CHECK: [[LO:%[0-9]+]](s64) = G_EXTRACT [[STRUCT]](s128), 0
+; CHECK: [[HI:%[0-9]+]](s64) = G_EXTRACT [[STRUCT]](s128), 64
+
+; CHECK: [[SP:%[0-9]+]](p0) = COPY %sp
+; CHECK: [[OFF:%[0-9]+]](s64) = G_CONSTANT i64 0
+; CHECK: [[ADDR:%[0-9]+]](p0) = G_GEP [[SP]], [[OFF]]
+; CHECK: G_STORE [[LO]](s64), [[ADDR]](p0) :: (store 8 into stack, align 0)
+
+; CHECK: [[SP:%[0-9]+]](p0) = COPY %sp
+; CHECK: [[OFF:%[0-9]+]](s64) = G_CONSTANT i64 8
+; CHECK: [[ADDR:%[0-9]+]](p0) = G_GEP [[SP]], [[OFF]]
+; CHECK: G_STORE [[HI]](s64), [[ADDR]](p0) :: (store 8 into stack + 8, align 0)
+define void @test_split_struct([2 x i64]* %ptr) {
+ %struct = load [2 x i64], [2 x i64]* %ptr
+ call void @take_split_struct([2 x i64]* null, i64 1, i64 2, i64 3,
+ i64 4, i64 5, i64 6,
+ [2 x i64] %struct)
+ ret void
+}
+
+; CHECK-LABEL: name: take_split_struct
+; CHECK: fixedStack:
+; CHECK-DAG: - { id: [[LO_FRAME:[0-9]+]], type: default, offset: 0, size: 8
+; CHECK-DAG: - { id: [[HI_FRAME:[0-9]+]], type: default, offset: 8, size: 8
+
+; CHECK: [[LOPTR:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[LO_FRAME]]
+; CHECK: [[LO:%[0-9]+]](s64) = G_LOAD [[LOPTR]](p0) :: (invariant load 8 from %fixed-stack.[[LO_FRAME]], align 0)
+
+; CHECK: [[HIPTR:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[HI_FRAME]]
+; CHECK: [[HI:%[0-9]+]](s64) = G_LOAD [[HIPTR]](p0) :: (invariant load 8 from %fixed-stack.[[HI_FRAME]], align 0)
+define void @take_split_struct([2 x i64]* %ptr, i64, i64, i64,
+ i64, i64, i64,
+ [2 x i64] %in) {
+ store [2 x i64] %in, [2 x i64]* %ptr
+ ret void
+}