LDCはpragmaを利用してLLVMのコード生成時にvolatileLoad/volatileStoreのハンドリングをしてる。
ここではvolatileLoadの呼び出し/コード生成までみていく。
core.bitopモジュールは、LDCコンパイラを使うときは特に指定しなくても pragma(LDC_intrinsic, “ldc.bitop.vld”) を指定して volatileLoad の宣言をしている。
// druntime - src/core/bitop.d version (LDC) { pragma(LDC_intrinsic, "ldc.bitop.vld") ubyte volatileLoad(ubyte* ptr); pragma(LDC_intrinsic, "ldc.bitop.vld") ushort volatileLoad(ushort* ptr); pragma(LDC_intrinsic, "ldc.bitop.vld") uint volatileLoad(uint* ptr); pragma(LDC_intrinsic, "ldc.bitop.vld") ulong volatileLoad(ulong* ptr); pragma(LDC_intrinsic, "ldc.bitop.vst") void volatileStore(ubyte* ptr, ubyte value); pragma(LDC_intrinsic, "ldc.bitop.vst") void volatileStore(ushort* ptr, ushort value); pragma(LDC_intrinsic, "ldc.bitop.vst") void volatileStore(uint* ptr, uint value); pragma(LDC_intrinsic, "ldc.bitop.vst") void volatileStore(ulong* ptr, ulong value); } ...
宣言の一覧はこれ。
// ldc - gen/dpragma.d extern (C++) enum LDCPragma : int { LLVMnone = 0, // Not an LDC pragma. LLVMignore, // Pragma has already been processed in DtoGetPragma, ignore. LLVMintrinsic, LLVMglobal_crt_ctor, LLVMglobal_crt_dtor, LLVMno_typeinfo, LLVMalloca, LLVMva_start, LLVMva_copy, LLVMva_end, LLVMva_arg, LLVMinline_asm, LLVMinline_ir, LLVMfence, LLVMatomic_store, LLVMatomic_load, LLVMatomic_cmp_xchg, LLVMatomic_rmw, LLVMbitop_bt, LLVMbitop_btc, LLVMbitop_btr, LLVMbitop_bts, LLVMbitop_vld, LLVMbitop_vst, LLVMextern_weak };
Dコードから命令に落とすところはこうなっている。素朴。
bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e, DValue *&result) { ... if (fndecl->llvmInternal == LLVMbitop_vld) { if (e->arguments->dim != 1) { e->error("bitop.vld intrinsic expects 1 argument"); fatal(); } // TODO: Check types Expression *exp1 = (*e->arguments)[0]; LLValue *ptr = DtoRVal(exp1); result = new DImValue(e->type, DtoVolatileLoad(ptr)); return true; } ...
ここでLLVMの中間コード生成するところに渡している。あとはごにょごにょやってLLVM IRを生成してるだけ。(だけ、とは)
LLValue *DtoVolatileLoad(LLValue *src, const char *name) { llvm::LoadInst *ld = gIR->ir->CreateLoad(src, name); ld->setVolatile(true); return ld; }
たとえば、ARM Cortex-Mとかでベアメタル環境で volatileLoad/volatileStore がほしければ core.bitop の定義をそのままもってくるとよい。