diff --git a/dmd/attrib.c b/dmd/attrib.c index 0afb3e98..b709683a 100644 --- a/dmd/attrib.c +++ b/dmd/attrib.c @@ -838,7 +838,7 @@ void PragmaDeclaration::semantic(Scope *sc) expr = expr->semantic(sc); 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(); } llvm_internal = LLVMintrinsic; @@ -849,7 +849,7 @@ void PragmaDeclaration::semantic(Scope *sc) { if (args && args->dim > 0) { - error("pragma no_typeinfo takes no parameters"); + error("takes no parameters"); fatal(); } llvm_internal = LLVMno_typeinfo; @@ -860,7 +860,7 @@ void PragmaDeclaration::semantic(Scope *sc) { if (args && args->dim > 0) { - error("pragma no_moduleinfo takes no parameters"); + error("takes no parameters"); fatal(); } llvm_internal = LLVMno_moduleinfo; @@ -871,7 +871,7 @@ void PragmaDeclaration::semantic(Scope *sc) { if (args && args->dim > 0) { - error("pragma alloca takes no parameters"); + error("takes no parameters"); fatal(); } llvm_internal = LLVMalloca; @@ -882,7 +882,7 @@ void PragmaDeclaration::semantic(Scope *sc) { if (args && args->dim > 0) { - error("pragma va_start takes no parameters"); + error("takes no parameters"); fatal(); } llvm_internal = LLVMva_start; @@ -893,7 +893,7 @@ void PragmaDeclaration::semantic(Scope *sc) { if (args && args->dim > 0) { - error("pragma va_copy takes no parameters"); + error("takes no parameters"); fatal(); } llvm_internal = LLVMva_copy; @@ -904,7 +904,7 @@ void PragmaDeclaration::semantic(Scope *sc) { if (args && args->dim > 0) { - error("pragma va_end takes no parameters"); + error("takes no parameters"); fatal(); } llvm_internal = LLVMva_end; @@ -915,7 +915,7 @@ void PragmaDeclaration::semantic(Scope *sc) { if (args && args->dim > 0) { - error("pragma va_arg takes no parameters"); + error("takes no parameters"); fatal(); } llvm_internal = LLVMva_arg; @@ -928,7 +928,7 @@ void PragmaDeclaration::semantic(Scope *sc) expr = expr->semantic(sc); 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(); } else if (arg1str == "verbose") @@ -937,7 +937,7 @@ void PragmaDeclaration::semantic(Scope *sc) } else { - error("pragma llvmdc command '%s' invalid"); + error("command '%s' invalid"); fatal(); } } @@ -1000,9 +1000,14 @@ void PragmaDeclaration::semantic(Scope *sc) fd->llvmInternal = llvm_internal; fd->intrinsicName = arg1str; } + else if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + td->llvmInternal = llvm_internal; + td->intrinsicName = arg1str; + } else { - error("the intrinsic pragma is only allowed on function declarations"); + error("only allowed on function declarations"); fatal(); } break; diff --git a/dmd/template.c b/dmd/template.c index 4892fef2..659fd4c6 100644 --- a/dmd/template.c +++ b/dmd/template.c @@ -303,6 +303,10 @@ Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) } d = Dsymbol::arraySyntaxCopy(members); td = new TemplateDeclaration(loc, ident, p, d); + + // LLVMDC + td->intrinsicName = intrinsicName; + return td; } diff --git a/dmd/template.h b/dmd/template.h index 57b72d45..8729f7b2 100644 --- a/dmd/template.h +++ b/dmd/template.h @@ -15,6 +15,8 @@ #pragma once #endif /* __DMC__ */ +#include + #include "root.h" #include "arraytypes.h" #include "dsymbol.h" @@ -83,6 +85,9 @@ struct TemplateDeclaration : ScopeDsymbol TemplateTupleParameter *isVariadic(); int isOverloadable(); + + // LLVMDC + std::string intrinsicName; }; struct TemplateParameter diff --git a/gen/functions.cpp b/gen/functions.cpp index b94bda9a..fcec5a2d 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -300,6 +300,12 @@ void DtoResolveFunction(FuncDeclaration* fdecl) Logger::println("magic va_start found"); fdecl->llvmInternal = LLVMva_start; } + else if (tempdecl->llvmInternal == LLVMintrinsic) + { + Logger::println("overloaded intrinsic found"); + fdecl->llvmInternal = LLVMintrinsic; + DtoOverloadedIntrinsicName(tinst, tempdecl, fdecl->intrinsicName); + } } DtoFunctionType(fdecl); diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 69d94ec7..980ef59b 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1553,3 +1553,32 @@ LLValue* DtoBoolean(Loc& loc, DValue* dval) assert(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()); +} diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 5a98e9fa..b193ec52 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -110,6 +110,9 @@ LLValue* DtoBoolean(Loc& loc, DValue* dval); /// get the default initializer of the type LLConstant* DtoDefaultInit(Type* t); +// fixup an overloaded intrinsic name string +void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, std::string& name); + //////////////////////////////////////////// // gen/tocall.cpp stuff below //////////////////////////////////////////// diff --git a/llvmdc-tango b/llvmdc-tango index 574bbade..8bd68f26 100644 --- a/llvmdc-tango +++ b/llvmdc-tango @@ -42,7 +42,7 @@ version=-version=$i [link] -#oneatatime=yes +oneatatime=yes cmd=llvmdc $i -of$o libdir=-L-L=$i @@ -52,7 +52,7 @@ flag=-L$i [liblink] safe=yes -#oneatatime=yes +oneatatime=yes cmd=llvm-ar rsc $o $i libdir=-L=$i diff --git a/runtime/import/llvmdc/intrinsics.di b/runtime/import/llvmdc/intrinsics.di index 01f18251..c1d6bdb9 100644 --- a/runtime/import/llvmdc/intrinsics.di +++ b/runtime/import/llvmdc/intrinsics.di @@ -245,16 +245,65 @@ pragma(intrinsic, "llvm.part.select.i64") 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 // -// 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 diff --git a/tests/mini/atomic1.d b/tests/mini/atomic1.d new file mode 100644 index 00000000..b6cb1c17 --- /dev/null +++ b/tests/mini/atomic1.d @@ -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); +}