yonghong-song created this revision.
yonghong-song added a reviewer: ast.
Herald added subscribers: pengfei, kristof.beyls.
Herald added a project: All.
yonghong-song requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Currently, record arguments are always passed by reference by allocating
space for record values in the caller. This is less efficient for 
small records which may take one or two registers. For example,
for x86_64 and aarch64, for a record size up to 16 bytes, the record
values can be passed by values directly on the registers.

This patch added BPF support of record argument with direct values
for up to 16 byte record size. If record size is 0, that record
will not take any register, which is the same behavior for x86_64
and aarch64. If the record size is greater than 16 bytes, the 
record argument will be passed by reference.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132144

Files:
  clang/lib/CodeGen/TargetInfo.cpp
  clang/test/CodeGen/bpf-struct-argument.c
  clang/test/CodeGen/bpf-union-argument.c

Index: clang/test/CodeGen/bpf-union-argument.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/bpf-union-argument.c
@@ -0,0 +1,44 @@
+// REQUIRES: bpf-registered-target
+// RUN: %clang_cc1 -triple bpf -O2 -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s
+
+union t1 {};
+union t2 {
+  int a;
+  long b;
+};
+union t3 {
+  struct {
+    int a;
+    long b;
+  };
+  long c;
+};
+union t4 {
+  struct {
+    long a;
+    long b;
+    long c;
+  };
+  long d;
+};
+
+int foo1(union t1 arg1, union t2 arg2) {
+// CHECK: define dso_local i32 @foo1(i64 %arg2.coerce)
+  return arg2.a;
+}
+
+int foo2(union t3 arg1, union t4 arg2) {
+// CHECK: define dso_local i32 @foo2([2 x i64] %arg1.coerce, ptr noundef byval(%union.t4) align 8 %arg2)
+  return arg1.a + arg2.a;
+
+}
+
+int foo3(void) {
+  union t1 tmp1 = {};
+  union t2 tmp2 = {};
+  union t3 tmp3 = {};
+  union t4 tmp4 = {};
+  return foo1(tmp1, tmp2) + foo2(tmp3, tmp4);
+// CHECK: call i32 @foo1(i64 %{{[a-zA-Z0-9]+}})
+// CHECK: call i32 @foo2([2 x i64] %{{[a-zA-Z0-9]+}}, ptr noundef byval(%union.t4) align 8 %tmp4)
+}
Index: clang/test/CodeGen/bpf-struct-argument.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/bpf-struct-argument.c
@@ -0,0 +1,36 @@
+// REQUIRES: bpf-registered-target
+// RUN: %clang_cc1 -triple bpf -O2 -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s
+
+struct t1 {};
+struct t2 {
+  int a;
+};
+struct t3 {
+  int a;
+  long b;
+};
+struct t4 {
+  long a;
+  long b;
+  long c;
+};
+
+int foo1(struct t1 arg1, struct t2 arg2) {
+// CHECK: define dso_local i32 @foo1(i32 %arg2.coerce)
+  return arg2.a;
+}
+
+int foo2(struct t3 arg1, struct t4 arg2) {
+// CHECK: define dso_local i32 @foo2([2 x i64] %arg1.coerce, ptr noundef byval(%struct.t4) align 8 %arg2)
+  return arg1.a + arg2.a;
+}
+
+int foo3(void) {
+  struct t1 tmp1 = {};
+  struct t2 tmp2 = {};
+  struct t3 tmp3 = {};
+  struct t4 tmp4 = {};
+  return foo1(tmp1, tmp2) + foo2(tmp3, tmp4);
+// CHECK: call i32 @foo1(i32 %{{[a-zA-Z0-9]+}})
+// CHECK: call i32 @foo2([2 x i64] %{{[a-zA-Z0-9]+}}, ptr noundef byval(%struct.t4) align 8 %tmp4)
+}
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -11509,6 +11509,42 @@
 public:
   BPFABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
 
+  ABIArgInfo classifyArgumentType(QualType Ty) const {
+    Ty = useFirstFieldIfTransparentUnion(Ty);
+
+    if (isAggregateTypeForABI(Ty)) {
+      uint64_t Bits = getContext().getTypeSize(Ty);
+      if (Bits == 0)
+        return ABIArgInfo::getIgnore();
+
+      // If the aggregate needs 1 or 2 registers, do not use reference.
+      if (Bits <= 128) {
+        llvm::Type *CoerceTy;
+        if (Bits <= 64) {
+          CoerceTy =
+              llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8));
+        } else {
+          llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), 64);
+          CoerceTy = llvm::ArrayType::get(RegTy, 2);
+        }
+        return ABIArgInfo::getDirect(CoerceTy);
+      } else {
+        return getNaturalAlignIndirect(Ty);
+      }
+    }
+
+    if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+      Ty = EnumTy->getDecl()->getIntegerType();
+
+    ASTContext &Context = getContext();
+    if (const auto *EIT = Ty->getAs<BitIntType>())
+      if (EIT->getNumBits() > Context.getTypeSize(Context.Int128Ty))
+        return getNaturalAlignIndirect(Ty);
+
+    return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
+                                              : ABIArgInfo::getDirect());
+  }
+
   ABIArgInfo classifyReturnType(QualType RetTy) const {
     if (RetTy->isVoidType())
       return ABIArgInfo::getIgnore();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to