[clang] ced0d1f - [BPF] support 128bit int explicitly in layout spec

Yonghong Song via cfe-commits cfe-commits at lists.llvm.org
Sat Mar 28 11:52:52 PDT 2020


Author: Yonghong Song
Date: 2020-03-28T11:46:29-07:00
New Revision: ced0d1f42b39bd93b350b2597ce6587d107c26a7

URL: https://github.com/llvm/llvm-project/commit/ced0d1f42b39bd93b350b2597ce6587d107c26a7
DIFF: https://github.com/llvm/llvm-project/commit/ced0d1f42b39bd93b350b2597ce6587d107c26a7.diff

LOG: [BPF] support 128bit int explicitly in layout spec

Currently, bpf does not specify 128bit alignment in its
layout spec. So for a structure like
  struct ipv6_key_t {
    unsigned pid;
    unsigned __int128 saddr;
    unsigned short lport;
  };
clang will generate IR type
  %struct.ipv6_key_t = type { i32, [12 x i8], i128, i16, [14 x i8] }
Additional padding is to ensure later IR->MIR can generate correct
stack layout with target layout spec.

But it is common practice for a tracing program to be
first compiled with target flag (e.g., x86_64 or aarch64) through
clang to generate IR and then go through llc to generate bpf
byte code. Tracing program often refers to kernel internal
data structures which needs to be compiled with non-bpf target.

But such a compilation model may cause a problem on aarch64.
The bcc issue https://github.com/iovisor/bcc/issues/2827
reported such a problem.

For the above structure, since aarch64 has "i128:128" in its
layout string, the generated IR will have
  %struct.ipv6_key_t = type { i32, i128, i16 }

Since bpf does not have "i128:128" in its spec string,
the selectionDAG assumes alignment 8 for i128 and
computes the stack storage size for the above is 32 bytes,
which leads incorrect code later.

The x86_64 does not have this issue as it does not have
"i128:128" in its layout spec as it does permits i128 to
be alignmented at 8 bytes at stack. Its IR type looks like
  %struct.ipv6_key_t = type { i32, [12 x i8], i128, i16, [14 x i8] }

The fix here is add i128 support in layout spec, the same as
aarch64. The only downside is we may have less optimal stack
allocation in certain cases since we require 16byte alignment
for i128 instead of 8. But this is probably fine as i128 is
not used widely and in most cases users should already
have proper alignment.

Differential Revision: https://reviews.llvm.org/D76587

Added: 
    llvm/test/CodeGen/BPF/i128.ll

Modified: 
    clang/lib/Basic/Targets/BPF.h
    clang/test/CodeGen/target-data.c
    llvm/lib/Target/BPF/BPFTargetMachine.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h
index b2f1831e960e..43e55dfbfb2b 100644
--- a/clang/lib/Basic/Targets/BPF.h
+++ b/clang/lib/Basic/Targets/BPF.h
@@ -35,9 +35,9 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
     Int64Type = SignedLong;
     RegParmMax = 5;
     if (Triple.getArch() == llvm::Triple::bpfeb) {
-      resetDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128");
+      resetDataLayout("E-m:e-p:64:64-i64:64-i128:128-n32:64-S128");
     } else {
-      resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
+      resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S128");
     }
     MaxAtomicPromoteWidth = 64;
     MaxAtomicInlineWidth = 64;

diff  --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c
index e49f8453e360..e619843f4bdb 100644
--- a/clang/test/CodeGen/target-data.c
+++ b/clang/test/CodeGen/target-data.c
@@ -245,8 +245,8 @@
 
 // RUN: %clang_cc1 -triple bpfel -o - -emit-llvm %s | \
 // RUN: FileCheck %s -check-prefix=BPFEL
-// BPFEL: target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
+// BPFEL: target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
 
 // RUN: %clang_cc1 -triple bpfeb -o - -emit-llvm %s | \
 // RUN: FileCheck %s -check-prefix=BPFEB
-// BPFEB: target datalayout = "E-m:e-p:64:64-i64:64-n32:64-S128"
+// BPFEB: target datalayout = "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128"

diff  --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
index d2a332c78aa6..4d42e7414075 100644
--- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp
+++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
@@ -42,9 +42,9 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() {
 // DataLayout: little or big endian
 static std::string computeDataLayout(const Triple &TT) {
   if (TT.getArch() == Triple::bpfeb)
-    return "E-m:e-p:64:64-i64:64-n32:64-S128";
+    return "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
   else
-    return "e-m:e-p:64:64-i64:64-n32:64-S128";
+    return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
 }
 
 static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) {

diff  --git a/llvm/test/CodeGen/BPF/i128.ll b/llvm/test/CodeGen/BPF/i128.ll
new file mode 100644
index 000000000000..c77838fa8bb4
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/i128.ll
@@ -0,0 +1,67 @@
+; RUN: llc -march=bpfel -o - %s | FileCheck %s
+; RUN: llc -march=bpfeb -o - %s | FileCheck %s
+; Source code:
+;   struct ipv6_key_t {
+;     unsigned pid;
+;     unsigned __int128 saddr;
+;     unsigned short lport;
+;   };
+;
+;   extern void test1(void *);
+;   int test(int pid) {
+;     struct ipv6_key_t ipv6_key = {.pid = pid};
+;     test1(&ipv6_key);
+;     return 0;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -S -emit-llvm t.c
+
+%struct.ipv6_key_t = type { i32, i128, i16 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(i32 %pid) local_unnamed_addr #0 {
+entry:
+  %ipv6_key = alloca %struct.ipv6_key_t, align 16
+  %0 = bitcast %struct.ipv6_key_t* %ipv6_key to i8*
+  call void @llvm.lifetime.start.p0i8(i64 48, i8* nonnull %0) #4
+  call void @llvm.memset.p0i8.i64(i8* nonnull align 16 dereferenceable(48) %0, i8 0, i64 48, i1 false)
+  %pid1 = getelementptr inbounds %struct.ipv6_key_t, %struct.ipv6_key_t* %ipv6_key, i64 0, i32 0
+  store i32 %pid, i32* %pid1, align 16, !tbaa !2
+  call void @test1(i8* nonnull %0) #4
+  call void @llvm.lifetime.end.p0i8(i64 48, i8* nonnull %0) #4
+  ret i32 0
+}
+
+; CHECK-LABEL: test
+; CHECK:       *(u64 *)(r10 - 48) = r{{[0-9]+}}
+; CHECK:       *(u32 *)(r10 - 48) = r{{[0-9]+}}
+
+; Function Attrs: argmemonly nounwind willreturn
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: argmemonly nounwind willreturn writeonly
+declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #2
+
+declare dso_local void @test1(i8*) local_unnamed_addr #3
+
+; Function Attrs: argmemonly nounwind willreturn
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind willreturn }
+attributes #2 = { argmemonly nounwind willreturn writeonly }
+attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 55fc7a47f8f18f84b44ff16f4e7a420c0a42ddf1)"}
+!2 = !{!3, !4, i64 0}
+!3 = !{!"ipv6_key_t", !4, i64 0, !7, i64 16, !8, i64 32}
+!4 = !{!"int", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C/C++ TBAA"}
+!7 = !{!"__int128", !5, i64 0}
+!8 = !{!"short", !5, i64 0}


        


More information about the cfe-commits mailing list