ldc/gen/pragma.cpp
2012-04-05 15:30:00 +04:00

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());
}
}