Skip to content

Pass slices as not a struct, enable @restrict for T[] #4225

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
40 changes: 33 additions & 7 deletions gen/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
sretAttrs.addAttribute(LLAttribute::NoAlias);
if (unsigned alignment = DtoAlignment(rt))
sretAttrs.addAlignmentAttr(alignment);
newIrFty.arg_sret = new IrFuncTyArg(rt, true, std::move(sretAttrs));
newIrFty.arg_sret = new IrFuncTyArg(rt, true, false, std::move(sretAttrs));
rt = Type::tvoid;
++nextLLArgIdx;
} else {
// sext/zext return
DtoAddExtendAttr(byref ? rt->pointerTo() : rt, attrs);
}
newIrFty.ret = new IrFuncTyArg(rt, byref, std::move(attrs));
newIrFty.ret = new IrFuncTyArg(rt, byref, false, std::move(attrs));
}
++nextLLArgIdx;

Expand All @@ -140,7 +140,7 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
attrs.addAttribute(LLAttribute::Returned);
}
newIrFty.arg_this = new IrFuncTyArg(
thistype, thistype->toBasetype()->ty == TY::Tstruct, std::move(attrs));
thistype, thistype->toBasetype()->ty == TY::Tstruct, false, std::move(attrs));
++nextLLArgIdx;
} else if (nesttype) {
// Add the context pointer for nested functions
Expand All @@ -150,7 +150,7 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
llvm::AttrBuilder attrs;
#endif
attrs.addAttribute(LLAttribute::NonNull);
newIrFty.arg_nest = new IrFuncTyArg(nesttype, false, std::move(attrs));
newIrFty.arg_nest = new IrFuncTyArg(nesttype, false, false, std::move(attrs));
++nextLLArgIdx;
}

Expand Down Expand Up @@ -237,9 +237,22 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
}
}

newIrFty.args.push_back(new IrFuncTyArg(loweredDType, passPointer, std::move(attrs)));
newIrFty.args.back()->parametersIdx = i;
++nextLLArgIdx;
if (loweredDType->isTypeDArray() && !passPointer && hasRestrict(arg->userAttribDecl)) {
#if LDC_LLVM_VER >= 1400
llvm::AttrBuilder length_attrs(getGlobalContext());
#else
llvm::AttrBuilder length_attrs;
#endif
newIrFty.args.push_back(new IrFuncTyArg(Type::tsize_t, false, true, std::move(length_attrs)));
newIrFty.args.back()->parametersIdx = -1;
newIrFty.args.push_back(new IrFuncTyArg(loweredDType->nextOf()->pointerTo(), false, false, std::move(attrs)));
newIrFty.args.back()->parametersIdx = i;
nextLLArgIdx += 2;
} else {
newIrFty.args.push_back(new IrFuncTyArg(loweredDType, passPointer, false, std::move(attrs)));
newIrFty.args.back()->parametersIdx = i;
++nextLLArgIdx;
}
}

// let the ABI rewrite the types as necessary
Expand Down Expand Up @@ -800,6 +813,19 @@ void DtoDeclareFunction(FuncDeclaration *fdecl, const bool willDefine) {
for (; iarg != func->arg_end(); ++iarg) {
IrFuncTyArg *arg = irFty.args[k++];

if (arg->isArrayLength) {
size_t idx = irFty.args[k]->parametersIdx;
auto *const vd = (*fdecl->parameters)[idx];
iarg->setName(vd->ident->toChars() + llvm::Twine("_arg_len"));
IrParameter *irParam = getIrParameter(vd, true);
irParam->arg = arg;
irParam->value = &(*iarg);
++iarg;
iarg->setName(vd->ident->toChars() + llvm::Twine("_arg_ptr"));
irParam->arg2 = irFty.args[k++];;
irParam->value2 = &(*iarg);
continue;
}
if (!fdecl->parameters || arg->parametersIdx >= fdecl->parameters->length) {
iarg->setName("unnamed");
continue;
Expand Down
8 changes: 6 additions & 2 deletions gen/tocall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
DtoAddExtendAttr(argType, initialAttrs);
}

optionalIrArgs.push_back(new IrFuncTyArg(argType, passByVal, std::move(initialAttrs)));
optionalIrArgs.push_back(new IrFuncTyArg(argType, passByVal, false, std::move(initialAttrs)));
optionalIrArgs.back()->parametersIdx = i;
}

Expand Down Expand Up @@ -188,7 +188,11 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
Logger::cout() << "expects: " << *paramType << '\n';
}
if (isaStruct(llVal)) {
llVal = DtoSlicePaint(llVal, paramType);
args[llArgIdx] = DtoExtractValue(llVal, 0);
attrs.addToParam(llArgIdx + 1, irArg->attrs);
args[llArgIdx + 1] = DtoExtractValue(llVal, 1);
++i;
continue;
} else {
llVal = DtoBitCast(llVal, paramType);
}
Expand Down
24 changes: 21 additions & 3 deletions gen/uda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,15 @@ void checkStructElems(StructLiteralExp *sle, ArrayParam<Type *> elemTypes) {
/// Returns the StructLiteralExp magic attribute with identifier `id` from
/// the ldc magic module with identifier `from` (attributes or dcompute)
/// if it is applied to `sym`, otherwise returns nullptr.
StructLiteralExp *getMagicAttribute(Dsymbol *sym, const Identifier *id,
///
StructLiteralExp *getMagicAttribute(UserAttributeDeclaration* uattrs,
const Identifier *id,
const Identifier *from) {
if (!sym->userAttribDecl)
if (!uattrs)
return nullptr;

// Loop over all UDAs and early return the expression if a match was found.
Expressions *attrs = sym->userAttribDecl->getAttributes();
Expressions *attrs = uattrs->getAttributes();
expandTuples(attrs);
for (auto attr : *attrs) {
if (auto sle = attr->isStructLiteralExp())
Expand All @@ -109,6 +111,13 @@ StructLiteralExp *getMagicAttribute(Dsymbol *sym, const Identifier *id,

return nullptr;
}
StructLiteralExp *getMagicAttribute(Dsymbol *sym, const Identifier *id,
const Identifier *from) {
if (!sym->userAttribDecl)
return nullptr;

return getMagicAttribute(sym->userAttribDecl, id, from);
}

/// Calls `action` for each magic attribute with identifier `id` from
/// the ldc magic module with identifier `from` (attributes or dcompute)
Expand Down Expand Up @@ -542,6 +551,15 @@ bool hasKernelAttr(Dsymbol *sym) {
return true;
}

bool hasRestrict(UserAttributeDeclaration *uattrs) {
auto sle = getMagicAttribute(uattrs, Id::udaLLVMAttr, Id::attributes);
if (!sle)
return false;

checkStructElems(sle, {Type::tstring, Type::tstring});
return getStringElem(sle, 0) == "noalias";
}

/// Creates a mask (for &) of @ldc.attributes.noSanitize UDA applied to the
/// function.
/// If a bit is set in the mask, then the sanitizer is enabled.
Expand Down
2 changes: 2 additions & 0 deletions gen/uda.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#pragma once

class Dsymbol;
class UserAttributeDeclaration;
class FuncDeclaration;
class VarDeclaration;
struct IrFunction;
Expand All @@ -27,6 +28,7 @@ void applyVarDeclUDAs(VarDeclaration *decl, llvm::GlobalVariable *gvar);

bool hasWeakUDA(Dsymbol *sym);
bool hasKernelAttr(Dsymbol *sym);
bool hasRestrict(UserAttributeDeclaration *uattrs);
/// Must match ldc.dcompute.Compilefor + 1 == DComputeCompileFor
enum class DComputeCompileFor : int
{
Expand Down
9 changes: 5 additions & 4 deletions ir/irfuncty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,21 @@
#include "gen/logger.h"
#include "gen/tollvm.h"

IrFuncTyArg::IrFuncTyArg(Type *t, bool bref)
IrFuncTyArg::IrFuncTyArg(Type *t, bool bref, bool isArrayLength)
: type(t),
ltype(t != Type::tvoid && bref ? DtoType(t->pointerTo()) : DtoType(t)),
#if LDC_LLVM_VER >= 1400
attrs(getGlobalContext()),
#endif
byref(bref) {
byref(bref),
isArrayLength(isArrayLength) {
mem.addRange(&type, sizeof(type));
}

IrFuncTyArg::IrFuncTyArg(Type *t, bool bref, llvm::AttrBuilder a)
IrFuncTyArg::IrFuncTyArg(Type *t, bool bref, bool isArrayLength, llvm::AttrBuilder a)
: type(t),
ltype(t != Type::tvoid && bref ? DtoType(t->pointerTo()) : DtoType(t)),
attrs(std::move(a)), byref(bref) {
attrs(std::move(a)), byref(bref), isArrayLength(isArrayLength) {

mem.addRange(&type, sizeof(type));
}
Expand Down
9 changes: 7 additions & 2 deletions ir/irfuncty.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ struct IrFuncTyArg {
* LLVM Type is a reference type! */
bool byref = false;

/** 'true' if this arg is the length part of an array parameter that is
broken into length + ptr
*/
bool isArrayLength;

/** Pointer to the ABIRewrite structure needed to rewrite LLVM ValueS
* to match the final LLVM Type when passing arguments and getting
* return values */
Expand All @@ -76,8 +81,8 @@ struct IrFuncTyArg {
* @param byref Initial value for the 'byref' field. If true the initial
* LLVM Type will be of DtoType(type->pointerTo()), instead
* of just DtoType(type) */
IrFuncTyArg(Type *t, bool byref);
IrFuncTyArg(Type *t, bool byref, llvm::AttrBuilder);
IrFuncTyArg(Type *t, bool byref, bool isArrayLength = false);
IrFuncTyArg(Type *t, bool byref, bool isArrayLength, llvm::AttrBuilder);
IrFuncTyArg(const IrFuncTyArg &) = delete;

~IrFuncTyArg();
Expand Down
2 changes: 2 additions & 0 deletions ir/irvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct IrLocal : IrVar {
struct IrParameter : IrLocal {
explicit IrParameter(VarDeclaration *v) : IrLocal(v) {}
IrFuncTyArg *arg = nullptr;
IrFuncTyArg *arg2 = nullptr; // companion pointer to an array length
llvm::Value *value2;
bool isVthis = false; // true, if it is the 'this' parameter
};

Expand Down
12 changes: 12 additions & 0 deletions tests/codegen/restrict_slice.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %ldc %s -c -output-ll | FileCheck
import ldc.attributes;

//CHECK: define void @_D4testQfFAiZv({{i(64|32)}} %a_arg_len, {{i32\*|ptr}} noalias %a_arg_ptr)
//CHECK-NEXT: %a = alloca {{{i(64|32)}}, {{i32\*|ptr}}} align 8
void test(@restrict int[] a) {}

void use()
{
int[4] x;
test(x[]);
}