From f237d85af063b56f01c60b7720baa9c89b3ef413 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sat, 4 Feb 2012 19:33:55 +0400 Subject: [PATCH] Implemented bt/btc/btr/bts intrinsics --- gen/pragma.cpp | 37 ++++++++++++++++++++++++++++++++++ gen/pragma.h | 6 +++++- gen/toir.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ runtime/druntime | 2 +- 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/gen/pragma.cpp b/gen/pragma.cpp index aacd5abe..d10f3fc9 100644 --- a/gen/pragma.cpp +++ b/gen/pragma.cpp @@ -30,6 +30,18 @@ Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str) // 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)) @@ -37,6 +49,27 @@ Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &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; } @@ -292,6 +325,10 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s, 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; diff --git a/gen/pragma.h b/gen/pragma.h index 90119ef0..cd53239a 100644 --- a/gen/pragma.h +++ b/gen/pragma.h @@ -23,7 +23,11 @@ enum Pragma LLVMatomic_store, LLVMatomic_load, LLVMatomic_cmp_xchg, - LLVMatomic_rmw + LLVMatomic_rmw, + LLVMbitop_bt, + LLVMbitop_btc, + LLVMbitop_btr, + LLVMbitop_bts }; Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str); diff --git a/gen/toir.cpp b/gen/toir.cpp index cfdda25c..97caa737 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1007,6 +1007,58 @@ DValue* CallExp::toElem(IRState* p) LLValue* ret = gIR->ir->CreateAtomicRMW(llvm::AtomicRMWInst::BinOp(op), ptr, val, llvm::AtomicOrdering(atomicOrdering)); return new DImValue(exp2->type, ret); + // bitop + } else if (fndecl->llvmInternal == LLVMbitop_bt || + fndecl->llvmInternal == LLVMbitop_btr || + fndecl->llvmInternal == LLVMbitop_btc || + fndecl->llvmInternal == LLVMbitop_bts) + { + if (arguments->dim != 2) { + error("bitop intrinsic %s expects 2 arguments"); + return NULL; + } + + Expression* exp1 = (Expression*)arguments->data[0]; + Expression* exp2 = (Expression*)arguments->data[1]; + LLValue* ptr = exp1->toElem(p)->getRVal(); + LLValue* bitnum = exp2->toElem(p)->getRVal(); + + // auto q = cast(ubyte*)ptr + (bitnum >> 3); + LLValue* q = DtoBitCast(ptr, DtoType(Type::tuns8->pointerTo())); + q = DtoGEP1(q, p->ir->CreateLShr(bitnum, 3), "bitop.q"); + + // auto mask = 1 << (bitnum & 7); + LLValue* mask = p->ir->CreateAnd(bitnum, DtoConstSize_t(7), "bitop.tmp"); + mask = p->ir->CreateShl(DtoConstSize_t(1), mask, "bitop.mask"); + + // auto result = (*q & mask) ? -1 : 0; + LLValue* val = p->ir->CreateZExt(DtoLoad(q, "bitop.tmp"), DtoSize_t(), "bitop.val"); + LLValue* result = p->ir->CreateAnd(val, mask, "bitop.tmp"); + result = p->ir->CreateICmpNE(result, DtoConstSize_t(0), "bitop.tmp"); + result = p->ir->CreateSelect(result, DtoConstInt(-1), DtoConstInt(0), "bitop.result"); + + if (fndecl->llvmInternal != LLVMbitop_bt) { + llvm::Instruction::BinaryOps op; + if (fndecl->llvmInternal == LLVMbitop_btc) { + // *q ^= mask; + op = llvm::Instruction::Xor; + } else if (fndecl->llvmInternal == LLVMbitop_btr) { + // *q &= ~mask; + mask = p->ir->CreateNot(mask); + op = llvm::Instruction::And; + } else if (fndecl->llvmInternal == LLVMbitop_bts) { + // *q |= mask; + op = llvm::Instruction::Or; + } else { + assert(false); + } + + LLValue *newVal = p->ir->CreateBinOp(op, val, mask, "bitop.new_val"); + newVal = p->ir->CreateTrunc(newVal, DtoType(Type::tuns8), "bitop.tmp"); + DtoStore(newVal, q); + } + + return new DImValue(type, result); } } return DtoCallFunction(loc, type, fnval, arguments); diff --git a/runtime/druntime b/runtime/druntime index 4db79c70..33925006 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 4db79c70e9de8f8b3b014d6f606f10b5fc41e2c5 +Subproject commit 33925006113cb894a46c8ffcb13ddc4fd29f4c54