[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