From f5ec1f41226c83250e39532c2ac00d3b5c77141d Mon Sep 17 00:00:00 2001 From: gulugulubing <413153391@qq.com> Date: Sat, 4 Jul 2026 08:22:16 -0600 Subject: [PATCH] Enable @restrict for tuple parameters (follow-up to #5148) --- dmd/typesem.d | 3 +- tests/codegen/restrict_slice_tuple.d | 45 ++++++++++++++++++++++++ tests/codegen/restrict_slice_tuple_opt.d | 26 ++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/codegen/restrict_slice_tuple.d create mode 100644 tests/codegen/restrict_slice_tuple_opt.d diff --git a/dmd/typesem.d b/dmd/typesem.d index 3cd45e70845..17fa1759efc 100644 --- a/dmd/typesem.d +++ b/dmd/typesem.d @@ -2673,7 +2673,8 @@ Type typeSemantic(Type type, Loc loc, Scope* sc) stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_)); } (*newparams)[j] = new Parameter( - loc, stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl); + loc, stc, narg.type, narg.ident, narg.defaultArg, + narg.userAttribDecl ? narg.userAttribDecl : fparam.userAttribDecl); } fparam.type = new TypeTuple(newparams); fparam.type = fparam.type.typeSemantic(loc, argsc); diff --git a/tests/codegen/restrict_slice_tuple.d b/tests/codegen/restrict_slice_tuple.d new file mode 100644 index 00000000000..f7398bb0d72 --- /dev/null +++ b/tests/codegen/restrict_slice_tuple.d @@ -0,0 +1,45 @@ +// RUN: %ldc -output-ll -of=%t.ll %s && FileCheck %s < %t.ll + +import ldc.attributes; + +// Two restrict slices via a tuple parameter: +// the @restrict UDA on the tuple should propagate to both +// expanded slice elements, generating pairwise separate_storage. +// CHECK-LABEL: define {{.*}}@{{.*}}tupleTwoSlices +// CHECK: separate_storage +auto tupleTwoSlices(Args...)(@restrict Args args) { + args[0][0] = 1; + args[1][0] = 2; +} + +// Mixed tuple: slices + pointer. +// Slices get separate_storage, pointer gets noalias on the LLVM param. +// CHECK-LABEL: define {{.*}}@{{.*}}tupleMixed +// CHECK-SAME: ptr noalias +// CHECK: separate_storage +auto tupleMixed(Args...)(@restrict Args args) { + args[0][0] = *args[2]; + args[1][0] = 3; +} + +// arrayOp-like: non-tuple restrict slice + tuple restrict slices. +// @restrict on both the non-tuple param and the tuple param should +// generate separate_storage among all slices. This is the pattern +// from druntime's core.internal.array.operations.arrayOp (issue #4991). +// CHECK-LABEL: define {{.*}}@{{.*}}arrayOpLike +// CHECK: separate_storage +auto arrayOpLike(Args...)(@restrict float[] res, @restrict Args args) { + res[0] = args[0][0] + args[1][0]; +} + +void test() { + int[] a; double[] b; + tupleTwoSlices(a, b); + + int[] x; float[] y; int* p; + tupleMixed(x, y, p); + + float[] res, fa, fb; + res = new float[16]; fa = new float[16]; fb = new float[16]; + arrayOpLike(res, fa, fb); +} diff --git a/tests/codegen/restrict_slice_tuple_opt.d b/tests/codegen/restrict_slice_tuple_opt.d new file mode 100644 index 00000000000..497c147cd6d --- /dev/null +++ b/tests/codegen/restrict_slice_tuple_opt.d @@ -0,0 +1,26 @@ +// RUN: %ldc -O3 -boundscheck=off -ffast-math -output-ll -of=%t.ll %s && FileCheck %s < %t.ll + +import ldc.attributes; + +// Without restrict on tuple: LLVM must assume slices overlap → scalar. +// CHECK-LABEL: define {{.*}}@{{.*}}noRestrictTuple +// CHECK-NOT: load <4 x float> +auto noRestrictTuple(Args...)(float[] res, const Args args) { + foreach (i; 0 .. 16) + res[i] = args[0][i] * args[1][i] + args[2][i]; +} + +// With restrict on tuple (arrayOp pattern from issue #4991): vectorized. +// CHECK-LABEL: define {{.*}}@{{.*}}withRestrictTuple +// CHECK: load <4 x float> +auto withRestrictTuple(Args...)(@restrict float[] res, @restrict Args args) { + foreach (i; 0 .. 16) + res[i] = args[0][i] * args[1][i] + args[2][i]; +} + +void test() { + float[] res, a, b, c; + res = new float[16]; a = new float[16]; b = new float[16]; c = new float[16]; + noRestrictTuple(res, a, b, c); + withRestrictTuple(res, a, b, c); +}