mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-11 21:37:17 +03:00
Added support for overloaded intrinsics.
Added atomic intrinsics in the intrinsics.di header.
This commit is contained in:
parent
3346a78e71
commit
5bf3e8911a
9 changed files with 127 additions and 14 deletions
27
dmd/attrib.c
27
dmd/attrib.c
|
@ -838,7 +838,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
expr = expr->semantic(sc);
|
expr = expr->semantic(sc);
|
||||||
if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
|
if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
|
||||||
{
|
{
|
||||||
error("pragma intrinsic requires exactly 1 string literal parameter");
|
error("requires exactly 1 string literal parameter");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm_internal = LLVMintrinsic;
|
llvm_internal = LLVMintrinsic;
|
||||||
|
@ -849,7 +849,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
if (args && args->dim > 0)
|
if (args && args->dim > 0)
|
||||||
{
|
{
|
||||||
error("pragma no_typeinfo takes no parameters");
|
error("takes no parameters");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm_internal = LLVMno_typeinfo;
|
llvm_internal = LLVMno_typeinfo;
|
||||||
|
@ -860,7 +860,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
if (args && args->dim > 0)
|
if (args && args->dim > 0)
|
||||||
{
|
{
|
||||||
error("pragma no_moduleinfo takes no parameters");
|
error("takes no parameters");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm_internal = LLVMno_moduleinfo;
|
llvm_internal = LLVMno_moduleinfo;
|
||||||
|
@ -871,7 +871,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
if (args && args->dim > 0)
|
if (args && args->dim > 0)
|
||||||
{
|
{
|
||||||
error("pragma alloca takes no parameters");
|
error("takes no parameters");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm_internal = LLVMalloca;
|
llvm_internal = LLVMalloca;
|
||||||
|
@ -882,7 +882,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
if (args && args->dim > 0)
|
if (args && args->dim > 0)
|
||||||
{
|
{
|
||||||
error("pragma va_start takes no parameters");
|
error("takes no parameters");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm_internal = LLVMva_start;
|
llvm_internal = LLVMva_start;
|
||||||
|
@ -893,7 +893,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
if (args && args->dim > 0)
|
if (args && args->dim > 0)
|
||||||
{
|
{
|
||||||
error("pragma va_copy takes no parameters");
|
error("takes no parameters");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm_internal = LLVMva_copy;
|
llvm_internal = LLVMva_copy;
|
||||||
|
@ -904,7 +904,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
if (args && args->dim > 0)
|
if (args && args->dim > 0)
|
||||||
{
|
{
|
||||||
error("pragma va_end takes no parameters");
|
error("takes no parameters");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm_internal = LLVMva_end;
|
llvm_internal = LLVMva_end;
|
||||||
|
@ -915,7 +915,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
{
|
{
|
||||||
if (args && args->dim > 0)
|
if (args && args->dim > 0)
|
||||||
{
|
{
|
||||||
error("pragma va_arg takes no parameters");
|
error("takes no parameters");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm_internal = LLVMva_arg;
|
llvm_internal = LLVMva_arg;
|
||||||
|
@ -928,7 +928,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
expr = expr->semantic(sc);
|
expr = expr->semantic(sc);
|
||||||
if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
|
if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
|
||||||
{
|
{
|
||||||
error("pragma llvmdc requires exactly 1 string literal parameter");
|
error("requires exactly 1 string literal parameter");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
else if (arg1str == "verbose")
|
else if (arg1str == "verbose")
|
||||||
|
@ -937,7 +937,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error("pragma llvmdc command '%s' invalid");
|
error("command '%s' invalid");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,9 +1000,14 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||||
fd->llvmInternal = llvm_internal;
|
fd->llvmInternal = llvm_internal;
|
||||||
fd->intrinsicName = arg1str;
|
fd->intrinsicName = arg1str;
|
||||||
}
|
}
|
||||||
|
else if (TemplateDeclaration* td = s->isTemplateDeclaration())
|
||||||
|
{
|
||||||
|
td->llvmInternal = llvm_internal;
|
||||||
|
td->intrinsicName = arg1str;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error("the intrinsic pragma is only allowed on function declarations");
|
error("only allowed on function declarations");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -303,6 +303,10 @@ Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
|
||||||
}
|
}
|
||||||
d = Dsymbol::arraySyntaxCopy(members);
|
d = Dsymbol::arraySyntaxCopy(members);
|
||||||
td = new TemplateDeclaration(loc, ident, p, d);
|
td = new TemplateDeclaration(loc, ident, p, d);
|
||||||
|
|
||||||
|
// LLVMDC
|
||||||
|
td->intrinsicName = intrinsicName;
|
||||||
|
|
||||||
return td;
|
return td;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#endif /* __DMC__ */
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "root.h"
|
#include "root.h"
|
||||||
#include "arraytypes.h"
|
#include "arraytypes.h"
|
||||||
#include "dsymbol.h"
|
#include "dsymbol.h"
|
||||||
|
@ -83,6 +85,9 @@ struct TemplateDeclaration : ScopeDsymbol
|
||||||
|
|
||||||
TemplateTupleParameter *isVariadic();
|
TemplateTupleParameter *isVariadic();
|
||||||
int isOverloadable();
|
int isOverloadable();
|
||||||
|
|
||||||
|
// LLVMDC
|
||||||
|
std::string intrinsicName;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TemplateParameter
|
struct TemplateParameter
|
||||||
|
|
|
@ -300,6 +300,12 @@ void DtoResolveFunction(FuncDeclaration* fdecl)
|
||||||
Logger::println("magic va_start found");
|
Logger::println("magic va_start found");
|
||||||
fdecl->llvmInternal = LLVMva_start;
|
fdecl->llvmInternal = LLVMva_start;
|
||||||
}
|
}
|
||||||
|
else if (tempdecl->llvmInternal == LLVMintrinsic)
|
||||||
|
{
|
||||||
|
Logger::println("overloaded intrinsic found");
|
||||||
|
fdecl->llvmInternal = LLVMintrinsic;
|
||||||
|
DtoOverloadedIntrinsicName(tinst, tempdecl, fdecl->intrinsicName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DtoFunctionType(fdecl);
|
DtoFunctionType(fdecl);
|
||||||
|
|
|
@ -1553,3 +1553,32 @@ LLValue* DtoBoolean(Loc& loc, DValue* dval)
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, std::string& name)
|
||||||
|
{
|
||||||
|
Logger::println("DtoOverloadedIntrinsicName");
|
||||||
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
Logger::println("template instance: %s", ti->toChars());
|
||||||
|
Logger::println("template declaration: %s", td->toChars());
|
||||||
|
Logger::println("intrinsic name: %s", td->intrinsicName.c_str());
|
||||||
|
|
||||||
|
// for now use the size in bits of the first template param in the instance
|
||||||
|
assert(ti->tdtypes.dim == 1);
|
||||||
|
Type* T = (Type*)ti->tdtypes.data[0];
|
||||||
|
|
||||||
|
char tmp[10];
|
||||||
|
sprintf(tmp, "%d", T->size()*8);
|
||||||
|
|
||||||
|
// replace # in name with bitsize
|
||||||
|
name = td->intrinsicName;
|
||||||
|
|
||||||
|
std::string needle("#");
|
||||||
|
size_t pos;
|
||||||
|
while(std::string::npos != (pos = name.find(needle)))
|
||||||
|
name.replace(pos, 1, tmp);
|
||||||
|
|
||||||
|
Logger::println("final intrinsic name: %s", name.c_str());
|
||||||
|
}
|
||||||
|
|
|
@ -110,6 +110,9 @@ LLValue* DtoBoolean(Loc& loc, DValue* dval);
|
||||||
/// get the default initializer of the type
|
/// get the default initializer of the type
|
||||||
LLConstant* DtoDefaultInit(Type* t);
|
LLConstant* DtoDefaultInit(Type* t);
|
||||||
|
|
||||||
|
// fixup an overloaded intrinsic name string
|
||||||
|
void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, std::string& name);
|
||||||
|
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
// gen/tocall.cpp stuff below
|
// gen/tocall.cpp stuff below
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
|
|
|
@ -42,7 +42,7 @@ version=-version=$i
|
||||||
|
|
||||||
|
|
||||||
[link]
|
[link]
|
||||||
#oneatatime=yes
|
oneatatime=yes
|
||||||
cmd=llvmdc $i -of$o
|
cmd=llvmdc $i -of$o
|
||||||
|
|
||||||
libdir=-L-L=$i
|
libdir=-L-L=$i
|
||||||
|
@ -52,7 +52,7 @@ flag=-L$i
|
||||||
|
|
||||||
[liblink]
|
[liblink]
|
||||||
safe=yes
|
safe=yes
|
||||||
#oneatatime=yes
|
oneatatime=yes
|
||||||
cmd=llvm-ar rsc $o $i
|
cmd=llvm-ar rsc $o $i
|
||||||
|
|
||||||
libdir=-L=$i
|
libdir=-L=$i
|
||||||
|
|
|
@ -245,16 +245,65 @@ pragma(intrinsic, "llvm.part.select.i64")
|
||||||
ulong llvm_part_select_i(ulong val, uint loBit, uint hiBit);
|
ulong llvm_part_select_i(ulong val, uint loBit, uint hiBit);
|
||||||
|
|
||||||
|
|
||||||
|
// The 'llvm.part.set' family of intrinsic functions replaces a range of bits in an integer value with another integer value. It returns the integer with the replaced bits.
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// declare i17 @llvm.part.set.i17.i9 (i17 %val, i9 %repl, i32 %lo, i32 %hi)
|
||||||
|
// declare i29 @llvm.part.set.i29.i9 (i29 %val, i9 %repl, i32 %lo, i32 %hi)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// ATOMIC OPERATIONS AND SYNCHRONIZATION INTRINSICS
|
// ATOMIC OPERATIONS AND SYNCHRONIZATION INTRINSICS
|
||||||
//
|
//
|
||||||
|
|
||||||
// TODO
|
// The llvm.memory.barrier intrinsic guarantees ordering between specific pairs of memory access types.
|
||||||
|
|
||||||
|
pragma(intrinsic, "llvm.memory.barrier")
|
||||||
|
void llvm_memory_barrier(bool ll, bool ls, bool sl, bool ss, bool device);
|
||||||
|
|
||||||
|
// This loads a value in memory and compares it to a given value. If they are equal, it stores a new value into the memory.
|
||||||
|
|
||||||
|
pragma(intrinsic, "llvm.atomic.cmp.swap.i#.p0i#")
|
||||||
|
T llvm_atomic_cmp_swap(T)(T* ptr, T cmp, T val);
|
||||||
|
|
||||||
|
// This intrinsic loads the value stored in memory at ptr and yields the value from memory. It then stores the value in val in the memory at ptr.
|
||||||
|
|
||||||
|
pragma(intrinsic, "llvm.atomic.swap.i#.p0i#")
|
||||||
|
T llvm_atomic_swap(T)(T* ptr, T val);
|
||||||
|
|
||||||
|
// This intrinsic adds delta to the value stored in memory at ptr. It yields the original value at ptr.
|
||||||
|
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.add.i#.p0i#")
|
||||||
|
T llvm_atomic_load_add(T)(T* ptr, T val);
|
||||||
|
|
||||||
|
// This intrinsic subtracts delta to the value stored in memory at ptr. It yields the original value at ptr.
|
||||||
|
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.sub.i#.p0i#")
|
||||||
|
T llvm_atomic_load_sub(T)(T* ptr, T val);
|
||||||
|
|
||||||
|
// These intrinsics bitwise the operation (and, nand, or, xor) delta to the value stored in memory at ptr. It yields the original value at ptr.
|
||||||
|
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.and.i#.p0i#")
|
||||||
|
T llvm_atomic_load_and(T)(T* ptr, T val);
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.nand.i#.p0i#")
|
||||||
|
T llvm_atomic_load_nand(T)(T* ptr, T val);
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.or.i#.p0i#")
|
||||||
|
T llvm_atomic_load_or(T)(T* ptr, T val);
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.xor.i#.p0i#")
|
||||||
|
T llvm_atomic_load_xor(T)(T* ptr, T val);
|
||||||
|
|
||||||
|
// These intrinsics takes the signed or unsigned minimum or maximum of delta and the value stored in memory at ptr. It yields the original value at ptr.
|
||||||
|
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.max.i#.p0i#")
|
||||||
|
T llvm_atomic_load_max(T)(T* ptr, T val);
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.min.i#.p0i#")
|
||||||
|
T llvm_atomic_load_min(T)(T* ptr, T val);
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.umax.i#.p0i#")
|
||||||
|
T llvm_atomic_load_umax(T)(T* ptr, T val);
|
||||||
|
pragma(intrinsic, "llvm.atomic.load.umin.i#.p0i#")
|
||||||
|
T llvm_atomic_load_umin(T)(T* ptr, T val);
|
||||||
|
|
||||||
//
|
//
|
||||||
// GENERAL INTRINSICS
|
// GENERAL INTRINSICS
|
||||||
|
|
12
tests/mini/atomic1.d
Normal file
12
tests/mini/atomic1.d
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module mini.atomic1;
|
||||||
|
|
||||||
|
pragma(intrinsic, "llvm.atomic.swap.i#.p0i#")
|
||||||
|
T atomic_swap(T)(T* ptr, T val);
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
int i = 42;
|
||||||
|
int j = atomic_swap(&i, 43);
|
||||||
|
assert(j == 42);
|
||||||
|
assert(i == 43);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue