Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
45 changes: 45 additions & 0 deletions tests/codegen/restrict_slice_tuple.d
Original file line number Diff line number Diff line change
@@ -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);
}
26 changes: 26 additions & 0 deletions tests/codegen/restrict_slice_tuple_opt.d
Original file line number Diff line number Diff line change
@@ -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);
}
Loading