GlobalISel (AArch64): fix ABI at border between GPRs and SP.

If a struct would end up half in GPRs and half on SP the ABI says it should
actually go entirely on the stack. We were getting this wrong in GlobalISel
before, causing compatibility issues.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311388 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Tim Northover 2017-08-21 21:56:11 +00:00
parent d900cd5e44
commit 55e2d2fb65
5 changed files with 133 additions and 10 deletions

View File

@ -172,7 +172,7 @@ struct OutgoingArgHandler : public CallLowering::ValueHandler {
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();
@ -190,14 +190,19 @@ void AArch64CallLowering::splitToValueTypes(
}
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);
}
@ -220,7 +225,7 @@ bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
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);
});
@ -250,7 +255,7 @@ bool AArch64CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
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;
@ -311,7 +316,7 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
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);
});
@ -364,7 +369,7 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
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);

View File

@ -56,6 +56,7 @@ private:
void splitToValueTypes(const ArgInfo &OrigArgInfo,
SmallVectorImpl<ArgInfo> &SplitArgs,
const DataLayout &DL, MachineRegisterInfo &MRI,
CallingConv::ID CallConv,
const SplitArgTy &SplitArg) const;
};

View File

@ -471,6 +471,9 @@ public:
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;
@ -640,10 +643,6 @@ private:
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;
};

View File

@ -33,3 +33,62 @@ define void @test_call_stack() {
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
}

View File

@ -215,3 +215,62 @@ define void @test_call_stack() {
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
}