]> granicus.if.org Git - llvm/commitdiff
GlobalISel (AArch64): fix ABI at border between GPRs and SP.
authorTim Northover <tnorthover@apple.com>
Thu, 17 Aug 2017 23:14:01 +0000 (23:14 +0000)
committerTim Northover <tnorthover@apple.com>
Thu, 17 Aug 2017 23:14:01 +0000 (23:14 +0000)
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@311137 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/AArch64/AArch64CallLowering.cpp
test/CodeGen/AArch64/GlobalISel/call-translator.ll

index fc09763ed38795f7c770f975d7182071f8085a3a..a0ef3262483822f8f7757851e154f6ba1484052f 100644 (file)
@@ -188,12 +188,16 @@ void AArch64CallLowering::splitToValueTypes(
   }
 
   unsigned FirstRegIdx = SplitArgs.size();
+  bool AlreadySplit = 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 (!AlreadySplit) {
+      SplitArgs.back().Flags.setSplit();
+      AlreadySplit = true;
+    }
   }
 
   for (unsigned i = 0; i < Offsets.size(); ++i)
index 1cc196be3594da39a89c7cf6c4c40417ca5d75d9..b5d85055f23ad0582e48086517bf8f3105824633 100644 (file)
@@ -215,3 +215,42 @@ define void @test_call_stack() {
 define void @test_mem_i1([8 x i64], i1 %in) {
   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
+}