mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-28 14:10:42 +03:00
384 lines
9.9 KiB
C++
384 lines
9.9 KiB
C++
#include "pragma.h"
|
|
#include "attrib.h"
|
|
#include "id.h"
|
|
#include "expression.h"
|
|
#include "scope.h"
|
|
#include "module.h"
|
|
#include "declaration.h"
|
|
#include "template.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
static bool parseStringExp(Expression* e, std::string& res)
|
|
{
|
|
StringExp *s = NULL;
|
|
|
|
e = e->optimize(WANTvalue);
|
|
if (e->op == TOKstring && (s = (StringExp *)e))
|
|
{
|
|
char* str = (char*)s->string;
|
|
res = str;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str)
|
|
{
|
|
Identifier *ident = decl->ident;
|
|
Expressions *args = decl->args;
|
|
|
|
// pragma(intrinsic, "string") { funcdecl(s) }
|
|
if (ident == Id::intrinsic)
|
|
{
|
|
struct LdcIntrinsic
|
|
{
|
|
std::string name;
|
|
Pragma pragma;
|
|
};
|
|
static LdcIntrinsic ldcIntrinsic[] = {
|
|
{ "bitop.bt", LLVMbitop_bt },
|
|
{ "bitop.btc", LLVMbitop_btc },
|
|
{ "bitop.btr", LLVMbitop_btr },
|
|
{ "bitop.bts", LLVMbitop_bts },
|
|
};
|
|
|
|
Expression* expr = (Expression *)args->data[0];
|
|
expr = expr->semantic(sc);
|
|
if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
|
|
{
|
|
error("requires exactly 1 string literal parameter");
|
|
fatal();
|
|
}
|
|
|
|
std::string prefix = "ldc.";
|
|
if (arg1str.length() > prefix.length() &&
|
|
std::equal(prefix.begin(), prefix.end(), arg1str.begin()))
|
|
{
|
|
std::string name(arg1str.begin() + prefix.length(), arg1str.end());
|
|
int i = 0, j = sizeof(ldcIntrinsic) / sizeof(ldcIntrinsic[0]), k, l;
|
|
do
|
|
{
|
|
k = (i + j) / 2;
|
|
l = name.compare(ldcIntrinsic[k].name);
|
|
if (!l)
|
|
return ldcIntrinsic[k].pragma;
|
|
else if (l < 0)
|
|
j = k;
|
|
else
|
|
i = k + 1;
|
|
}
|
|
while (i != j);
|
|
}
|
|
|
|
return LLVMintrinsic;
|
|
}
|
|
|
|
// pragma(notypeinfo) { typedecl(s) }
|
|
else if (ident == Id::no_typeinfo)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMno_typeinfo;
|
|
}
|
|
|
|
// pragma(nomoduleinfo) ;
|
|
else if (ident == Id::no_moduleinfo)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMno_moduleinfo;
|
|
}
|
|
|
|
// pragma(alloca) { funcdecl(s) }
|
|
else if (ident == Id::Alloca)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMalloca;
|
|
}
|
|
|
|
// pragma(va_start) { templdecl(s) }
|
|
else if (ident == Id::vastart)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMva_start;
|
|
}
|
|
|
|
// pragma(va_copy) { funcdecl(s) }
|
|
else if (ident == Id::vacopy)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMva_copy;
|
|
}
|
|
|
|
// pragma(va_end) { funcdecl(s) }
|
|
else if (ident == Id::vaend)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMva_end;
|
|
}
|
|
|
|
// pragma(va_arg) { templdecl(s) }
|
|
else if (ident == Id::vaarg)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMva_arg;
|
|
}
|
|
|
|
// pragma(fence) { funcdecl(s) }
|
|
else if (ident == Id::fence)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMfence;
|
|
}
|
|
|
|
// pragma(atomic_load) { templdecl(s) }
|
|
else if (ident == Id::atomic_load)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMatomic_load;
|
|
}
|
|
|
|
// pragma(atomic_store) { templdecl(s) }
|
|
else if (ident == Id::atomic_store)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMatomic_store;
|
|
}
|
|
|
|
// pragma(atomic_cmp_xchg) { templdecl(s) }
|
|
else if (ident == Id::atomic_cmp_xchg)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMatomic_cmp_xchg;
|
|
}
|
|
|
|
// pragma(atomic_rmw, "string") { templdecl(s) }
|
|
else if (ident == Id::atomic_rmw)
|
|
{
|
|
Expression* expr = (Expression *)args->data[0];
|
|
expr = expr->semantic(sc);
|
|
if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
|
|
{
|
|
error("requires exactly 1 string literal parameter");
|
|
fatal();
|
|
}
|
|
return LLVMatomic_rmw;
|
|
}
|
|
|
|
// pragma(ldc, "string") { templdecl(s) }
|
|
else if (ident == Id::ldc)
|
|
{
|
|
Expression* expr = (Expression *)args->data[0];
|
|
expr = expr->semantic(sc);
|
|
if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
|
|
{
|
|
error("requires exactly 1 string literal parameter");
|
|
fatal();
|
|
}
|
|
else if (arg1str == "verbose")
|
|
{
|
|
sc->module->llvmForceLogging = true;
|
|
}
|
|
else
|
|
{
|
|
error("command '%s' invalid", expr->toChars());
|
|
fatal();
|
|
}
|
|
}
|
|
|
|
// pragma(llvm_inline_asm) { templdecl(s) }
|
|
else if (ident == Id::llvm_inline_asm)
|
|
{
|
|
if (args && args->dim > 0)
|
|
{
|
|
error("takes no parameters");
|
|
fatal();
|
|
}
|
|
return LLVMinline_asm;
|
|
}
|
|
|
|
return LLVMnone;
|
|
}
|
|
|
|
void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s,
|
|
Pragma llvm_internal, const std::string &arg1str)
|
|
{
|
|
if (llvm_internal == LLVMnone)
|
|
return;
|
|
|
|
if (s->llvmInternal)
|
|
{
|
|
error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars());
|
|
fatal();
|
|
}
|
|
|
|
Identifier *ident = decl->ident;
|
|
|
|
switch(llvm_internal)
|
|
{
|
|
case LLVMintrinsic:
|
|
if (FuncDeclaration* fd = s->isFuncDeclaration())
|
|
{
|
|
fd->llvmInternal = llvm_internal;
|
|
fd->intrinsicName = arg1str;
|
|
fd->linkage = LINKintrinsic;
|
|
((TypeFunction*)fd->type)->linkage = LINKintrinsic;
|
|
}
|
|
else if (TemplateDeclaration* td = s->isTemplateDeclaration())
|
|
{
|
|
td->llvmInternal = llvm_internal;
|
|
td->intrinsicName = arg1str;
|
|
}
|
|
else
|
|
{
|
|
error("only allowed on function declarations");
|
|
fatal();
|
|
}
|
|
break;
|
|
|
|
case LLVMatomic_rmw:
|
|
if (TemplateDeclaration* td = s->isTemplateDeclaration())
|
|
{
|
|
td->llvmInternal = llvm_internal;
|
|
td->intrinsicName = arg1str;
|
|
}
|
|
else
|
|
{
|
|
error("the '%s' pragma is only allowed on template declarations", ident->toChars());
|
|
fatal();
|
|
}
|
|
break;
|
|
|
|
case LLVMva_start:
|
|
case LLVMva_arg:
|
|
case LLVMatomic_load:
|
|
case LLVMatomic_store:
|
|
case LLVMatomic_cmp_xchg:
|
|
if (TemplateDeclaration* td = s->isTemplateDeclaration())
|
|
{
|
|
if (td->parameters->dim != 1)
|
|
{
|
|
error("the '%s' pragma template must have exactly one template parameter", ident->toChars());
|
|
fatal();
|
|
}
|
|
else if (!td->onemember)
|
|
{
|
|
error("the '%s' pragma template must have exactly one member", ident->toChars());
|
|
fatal();
|
|
}
|
|
else if (td->overnext || td->overroot)
|
|
{
|
|
error("the '%s' pragma template must not be overloaded", ident->toChars());
|
|
fatal();
|
|
}
|
|
td->llvmInternal = llvm_internal;
|
|
}
|
|
else
|
|
{
|
|
error("the '%s' pragma is only allowed on template declarations", ident->toChars());
|
|
fatal();
|
|
}
|
|
break;
|
|
|
|
case LLVMva_copy:
|
|
case LLVMva_end:
|
|
case LLVMfence:
|
|
case LLVMbitop_bt:
|
|
case LLVMbitop_btc:
|
|
case LLVMbitop_btr:
|
|
case LLVMbitop_bts:
|
|
if (FuncDeclaration* fd = s->isFuncDeclaration())
|
|
{
|
|
fd->llvmInternal = llvm_internal;
|
|
}
|
|
else
|
|
{
|
|
error("the '%s' pragma is only allowed on function declarations", ident->toChars());
|
|
fatal();
|
|
}
|
|
break;
|
|
|
|
case LLVMno_typeinfo:
|
|
s->llvmInternal = llvm_internal;
|
|
break;
|
|
|
|
case LLVMalloca:
|
|
if (FuncDeclaration* fd = s->isFuncDeclaration())
|
|
{
|
|
fd->llvmInternal = llvm_internal;
|
|
}
|
|
else
|
|
{
|
|
error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars());
|
|
fatal();
|
|
}
|
|
break;
|
|
|
|
case LLVMinline_asm:
|
|
if (TemplateDeclaration* td = s->isTemplateDeclaration())
|
|
{
|
|
if (td->parameters->dim > 1)
|
|
{
|
|
error("the '%s' pragma template must have exactly zero or one template parameters", ident->toChars());
|
|
fatal();
|
|
}
|
|
else if (!td->onemember)
|
|
{
|
|
error("the '%s' pragma template must have exactly one member", ident->toChars());
|
|
fatal();
|
|
}
|
|
td->llvmInternal = llvm_internal;
|
|
}
|
|
else
|
|
{
|
|
error("the '%s' pragma is only allowed on template declarations", ident->toChars());
|
|
fatal();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
warning(Loc(), "the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars());
|
|
}
|
|
}
|