[pkg-d-commits] [ldc] 12/149: Implement the @allocSize magic UDA. (#1610)

Matthias Klumpp mak at moszumanska.debian.org
Sun Apr 23 22:36:53 UTC 2017


This is an automated email from the git hooks/post-receive script.

mak pushed a commit to annotated tag v1.2.0
in repository ldc.

commit a1de24d837c618cbc6ccfc1042ce7ab1578d7bfb
Author: Johan Engelen <jbc.engelen at gmail.com>
Date:   Mon Dec 19 11:38:16 2016 +0100

    Implement the @allocSize magic UDA. (#1610)
---
 gen/uda.cpp                         | 72 ++++++++++++++++++++++++++++++++++++-
 runtime/druntime                    |  2 +-
 tests/codegen/attr_allocsize.d      | 45 +++++++++++++++++++++++
 tests/codegen/attr_allocsize_diag.d | 32 +++++++++++++++++
 4 files changed, 149 insertions(+), 2 deletions(-)

diff --git a/gen/uda.cpp b/gen/uda.cpp
index 0aa9632..c78c0f0 100644
--- a/gen/uda.cpp
+++ b/gen/uda.cpp
@@ -15,6 +15,7 @@ namespace {
 
 /// Names of the attribute structs we recognize.
 namespace attr {
+const std::string allocSize = "allocSize";
 const std::string llvmAttr = "llvmAttr";
 const std::string llvmFastMathFlag = "llvmFastMathFlag";
 const std::string optStrategy = "optStrategy";
@@ -108,6 +109,11 @@ StructLiteralExp *getMagicAttribute(Dsymbol *sym, std::string name) {
   return nullptr;
 }
 
+sinteger_t getIntElem(StructLiteralExp *sle, size_t idx) {
+  auto arg = (*sle->elements)[idx];
+  return arg->toInteger();
+}
+
 /// Returns a null-terminated string
 const char *getStringElem(StructLiteralExp *sle, size_t idx) {
   auto arg = (*sle->elements)[idx];
@@ -125,6 +131,68 @@ const char *getFirstElemString(StructLiteralExp *sle) {
   return getStringElem(sle, 0);
 }
 
+// @allocSize(1)
+// @allocSize(0,2)
+void applyAttrAllocSize(StructLiteralExp *sle, IrFunction *irFunc) {
+  llvm::Function *func = irFunc->func;
+
+  checkStructElems(sle, {Type::tint32, Type::tint32});
+  auto sizeArgIdx = getIntElem(sle, 0);
+  auto numArgIdx = getIntElem(sle, 1);
+
+  // Get the number of parameters that the user specified (excluding the
+  // implicit `this` parameter)
+  auto numUserParams = irFunc->irFty.args.size();
+
+  // Get the number of parameters of the function in LLVM IR. This includes
+  // the `this` and sret parameters.
+  auto llvmNumParams = irFunc->irFty.funcType->getNumParams();
+
+  // Verify that the index values are valid
+  bool error = false;
+  if (sizeArgIdx + 1 > sinteger_t(numUserParams)) {
+    sle->error("@ldc.attributes.allocSize.sizeArgIdx=%d too large for function "
+               "`%s` with %d arguments.",
+               (int)sizeArgIdx, irFunc->decl->toChars(), (int)numUserParams);
+    error = true;
+  }
+  if (numArgIdx + 1 > sinteger_t(numUserParams)) {
+    sle->error("@ldc.attributes.allocSize.numArgIdx=%d too large for function "
+               "`%s` with %d arguments.",
+               (int)numArgIdx, irFunc->decl->toChars(), (int)numUserParams);
+    error = true;
+  }
+  if (error)
+    return;
+
+// The allocSize attribute is only effective for LLVM >= 3.9.
+#if LDC_LLVM_VER >= 309
+  // Offset to correct indices for sret and this parameters.
+  // These parameters can never be used for allocsize, and the user-specified
+  // index does not account for these.
+  unsigned offset = llvmNumParams - numUserParams;
+
+  // Calculate the param indices for the function as defined in LLVM IR
+  auto llvmSizeIdx =
+      irFunc->irFty.reverseParams ? numUserParams - sizeArgIdx - 1 : sizeArgIdx;
+  auto llvmNumIdx =
+      irFunc->irFty.reverseParams ? numUserParams - numArgIdx - 1 : numArgIdx;
+  llvmSizeIdx += offset;
+  llvmNumIdx += offset;
+
+  llvm::AttrBuilder builder;
+  if (numArgIdx >= 0) {
+    builder.addAllocSizeAttr(llvmSizeIdx, llvmNumIdx);
+  } else {
+    builder.addAllocSizeAttr(llvmSizeIdx, llvm::Optional<unsigned>());
+  }
+  func->addAttributes(llvm::AttributeSet::FunctionIndex,
+                      llvm::AttributeSet::get(func->getContext(),
+                                              llvm::AttributeSet::FunctionIndex,
+                                              builder));
+#endif
+}
+
 // @llvmAttr("key", "value")
 // @llvmAttr("key")
 void applyAttrLLVMAttr(StructLiteralExp *sle, llvm::Function *func) {
@@ -302,7 +370,9 @@ void applyFuncDeclUDAs(FuncDeclaration *decl, IrFunction *irFunc) {
       continue;
 
     auto name = sle->sd->ident->string;
-    if (name == attr::llvmAttr) {
+    if (name == attr::allocSize) {
+      applyAttrAllocSize(sle, irFunc);
+    } else if (name == attr::llvmAttr) {
       applyAttrLLVMAttr(sle, func);
     } else if (name == attr::llvmFastMathFlag) {
       applyAttrLLVMFastMathFlag(sle, irFunc);
diff --git a/runtime/druntime b/runtime/druntime
index 02cc057..df6e85b 160000
--- a/runtime/druntime
+++ b/runtime/druntime
@@ -1 +1 @@
-Subproject commit 02cc0572f4fddf65ff863a52fd82fdface6f1dba
+Subproject commit df6e85ba928487070da890f130ae4f8924fa0195
diff --git a/tests/codegen/attr_allocsize.d b/tests/codegen/attr_allocsize.d
new file mode 100644
index 0000000..c8ab9ac
--- /dev/null
+++ b/tests/codegen/attr_allocsize.d
@@ -0,0 +1,45 @@
+// Test ldc.attributes.allocSize
+
+// REQUIRES: atleast_llvm309
+
+// RUN: %ldc -O3 -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
+
+import ldc.attributes;
+
+// CHECK-LABEL: define{{.*}}@{{.*}}my_calloc
+// CHECK-SAME: #[[ATTR0:[0-9]+]]
+extern (C) void* my_calloc(size_t num, size_t size) @allocSize(1, 0)
+{
+    return null;
+}
+
+// CHECK-LABEL: define{{.*}}@{{.*}}my_malloc
+// CHECK-SAME: #[[ATTR1:[0-9]+]]
+extern (C) void* my_malloc(int a, int b, size_t size, int c) @allocSize(2)
+{
+    return null;
+}
+
+// Test the reversed parameter order of D calling convention
+// CHECK-LABEL: define{{.*}}@{{.*}}Dlinkage_calloc
+// CHECK-SAME: #[[ATTR2:[0-9]+]]
+extern (D) void* Dlinkage_calloc(int size, int b, size_t num, int c) @allocSize(0, 2)
+{
+    return null;
+}
+
+// Test function type with hidden `this` argument
+class A
+{
+    // CHECK-LABEL: define{{.*}}@{{.*}}this_calloc
+    // CHECK-SAME: #[[ATTR3:[0-9]+]]
+    void* this_calloc(int size, int b, size_t num, int c) @allocSize(0, 2)
+    {
+        return null;
+    }
+}
+
+// CHECK-DAG: attributes #[[ATTR0]] ={{.*}} allocsize(1,0)
+// CHECK-DAG: attributes #[[ATTR1]] ={{.*}} allocsize(2)
+// CHECK-DAG: attributes #[[ATTR2]] ={{.*}} allocsize(3,1)
+// CHECK-DAG: attributes #[[ATTR3]] ={{.*}} allocsize(4,2)
diff --git a/tests/codegen/attr_allocsize_diag.d b/tests/codegen/attr_allocsize_diag.d
new file mode 100644
index 0000000..1a1f3d2
--- /dev/null
+++ b/tests/codegen/attr_allocsize_diag.d
@@ -0,0 +1,32 @@
+// Test ldc.attributes.allocSize diagnostics
+
+// Although @allocSize is only effective for LLVM>=3.9, diagnostics should work for all LLVM versions
+
+// RUN: not %ldc -d-version=NORMAL %s 2>&1 | FileCheck %s --check-prefix=NORMAL
+// RUN: not %ldc -d-version=THIS   %s 2>&1 | FileCheck %s --check-prefix=THIS
+
+import ldc.attributes;
+
+version(NORMAL)
+{
+// NORMAL: attr_allocsize_diag.d([[@LINE+2]]): Error: @ldc.attributes.allocSize.sizeArgIdx=2 too large for function `my_calloc` with 2 arguments.
+// NORMAL: attr_allocsize_diag.d([[@LINE+1]]): Error: @ldc.attributes.allocSize.numArgIdx=2 too large for function `my_calloc` with 2 arguments.
+extern (C) void* my_calloc(size_t num, size_t size) @allocSize(2, 2)
+{
+    return null;
+}
+}
+
+version(THIS)
+{
+// Test function type with hidden `this` argument
+class A
+{
+    // THIS: attr_allocsize_diag.d([[@LINE+2]]): Error: @ldc.attributes.allocSize.sizeArgIdx=4 too large for function `this_calloc` with 4 arguments.
+    // THIS: attr_allocsize_diag.d([[@LINE+1]]): Error: @ldc.attributes.allocSize.numArgIdx=4 too large for function `this_calloc` with 4 arguments.
+    void* this_calloc(int size, int b, size_t num, int c) @allocSize(4, 4)
+    {
+        return null;
+    }
+}
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-d/ldc.git



More information about the pkg-d-commits mailing list