1 module d.llvm.intrinsic; 2 3 import d.llvm.local; 4 5 import source.name; 6 7 import d.ir.expression; 8 9 import llvm.c.core; 10 11 struct IntrinsicGenData { 12 private: 13 LLVMValueRef[Name] cache; 14 } 15 16 struct IntrinsicGen { 17 private LocalPass pass; 18 alias pass this; 19 20 this(LocalPass pass) { 21 this.pass = pass; 22 } 23 24 private @property 25 ref LLVMValueRef[Name] cache() { 26 return intrinsicGenData.cache; 27 } 28 29 LLVMValueRef build(Intrinsic i, Expression[] args) { 30 import d.llvm.expression, std.algorithm, std.range; 31 return build(i, args.map!(a => ExpressionGen(pass).visit(a)).array()); 32 } 33 34 LLVMValueRef build(Intrinsic i, LLVMValueRef[] args) { 35 bool weak; 36 final switch(i) with(Intrinsic) { 37 case None: 38 assert(0, "invalid intrinsic"); 39 40 case Expect: 41 return expect(args); 42 43 case CompareAndSwap: 44 return cas(weak, args); 45 46 case CompareAndSwapWeak: 47 weak = true; 48 goto case CompareAndSwap; 49 50 case PopCount: 51 return ctpop(args); 52 53 case CountLeadingZeros: 54 return ctlz(args); 55 56 case CountTrailingZeros: 57 return cttz(args); 58 59 case ByteSwap: 60 return bswap(args); 61 } 62 } 63 64 LLVMValueRef expect(LLVMValueRef[] args) in { 65 assert(args.length == 2, "Invalid argument count"); 66 } do { 67 return expect(args[0], args[1]); 68 } 69 70 LLVMValueRef expect(LLVMValueRef v, LLVMValueRef e) { 71 LLVMValueRef[2] args = [v, e]; 72 return LLVMBuildCall(builder, getExpect(), args.ptr, args.length, ""); 73 } 74 75 auto getExpect() { 76 auto name = context.getName("llvm.expect.i1"); 77 if (auto fPtr = name in cache) { 78 return *fPtr; 79 } 80 81 auto i1 = LLVMInt1TypeInContext(llvmCtx); 82 LLVMTypeRef[2] params = [i1, i1]; 83 84 auto type = LLVMFunctionType(i1, params.ptr, params.length, false); 85 return cache[name] = LLVMAddFunction( 86 dmodule, 87 name.toStringz(context), 88 type, 89 ); 90 } 91 92 LLVMValueRef cas(bool weak, LLVMValueRef[] args) in { 93 assert(args.length == 3, "Invalid argument count"); 94 } do { 95 return cas( 96 weak, 97 args[0], 98 args[1], 99 args[2], 100 LLVMAtomicOrdering.SequentiallyConsistent, 101 ); 102 } 103 104 LLVMValueRef cas( 105 bool weak, 106 LLVMValueRef ptr, 107 LLVMValueRef old, 108 LLVMValueRef val, 109 LLVMAtomicOrdering ordering, 110 ) { 111 return LLVMBuildAtomicCmpXchg( 112 builder, 113 ptr, 114 old, 115 val, 116 ordering, 117 ordering, 118 false, 119 ); 120 } 121 122 LLVMValueRef ctpop(LLVMValueRef[] args) in { 123 assert(args.length == 1, "Invalid argument count"); 124 } do { 125 return ctpop(args[0]); 126 } 127 128 LLVMValueRef ctpop(LLVMValueRef n) { 129 auto bits = LLVMGetIntTypeWidth(LLVMTypeOf(n)); 130 return LLVMBuildCall(builder, getCtpop(bits), &n, 1, ""); 131 } 132 133 auto getCtpop(uint bits) { 134 import std.conv; 135 auto name = context.getName("llvm.ctpop.i" ~ to!string(bits)); 136 if (auto fPtr = name in cache) { 137 return *fPtr; 138 } 139 140 auto t = LLVMIntTypeInContext(llvmCtx, bits); 141 return cache[name] = LLVMAddFunction( 142 dmodule, 143 name.toStringz(context), 144 LLVMFunctionType(t, &t, 1, false), 145 ); 146 } 147 148 LLVMValueRef ctlz(LLVMValueRef[] args) in { 149 assert(args.length == 1, "Invalid argument count"); 150 } do { 151 return ctlz(args[0]); 152 } 153 154 LLVMValueRef ctlz(LLVMValueRef n) { 155 LLVMValueRef[2] args = [ 156 n, 157 LLVMConstInt(LLVMInt1TypeInContext(llvmCtx), false, false), 158 ]; 159 160 auto bits = LLVMGetIntTypeWidth(LLVMTypeOf(n)); 161 return LLVMBuildCall(builder, getCtlz(bits), args.ptr, args.length, ""); 162 } 163 164 auto getCtlz(uint bits) { 165 import std.conv; 166 auto name = context.getName("llvm.ctlz.i" ~ to!string(bits)); 167 if (auto fPtr = name in cache) { 168 return *fPtr; 169 } 170 171 auto t = LLVMIntTypeInContext(llvmCtx, bits); 172 LLVMTypeRef[2] params = [t, LLVMInt1TypeInContext(llvmCtx)]; 173 174 auto type = LLVMFunctionType(t, params.ptr, params.length, false); 175 return cache[name] = LLVMAddFunction( 176 dmodule, 177 name.toStringz(context), 178 type, 179 ); 180 } 181 182 LLVMValueRef cttz(LLVMValueRef[] args) in { 183 assert(args.length == 1, "Invalid argument count"); 184 } do { 185 return cttz(args[0]); 186 } 187 188 LLVMValueRef cttz(LLVMValueRef n) { 189 LLVMValueRef[2] args = [ 190 n, 191 LLVMConstInt(LLVMInt1TypeInContext(llvmCtx), false, false), 192 ]; 193 194 auto bits = LLVMGetIntTypeWidth(LLVMTypeOf(n)); 195 return LLVMBuildCall(builder, getCttz(bits), args.ptr, args.length, ""); 196 } 197 198 auto getCttz(uint bits) { 199 import std.conv; 200 auto name = context.getName("llvm.cttz.i" ~ to!string(bits)); 201 if (auto fPtr = name in cache) { 202 return *fPtr; 203 } 204 205 auto t = LLVMIntTypeInContext(llvmCtx, bits); 206 LLVMTypeRef[2] params = [t, LLVMInt1TypeInContext(llvmCtx)]; 207 208 auto type = LLVMFunctionType(t, params.ptr, params.length, false); 209 return cache[name] = LLVMAddFunction( 210 dmodule, 211 name.toStringz(context), 212 type, 213 ); 214 } 215 216 LLVMValueRef bswap(LLVMValueRef[] args) in { 217 assert(args.length == 1, "Invalid argument count"); 218 } do { 219 return bswap(args[0]); 220 } 221 222 LLVMValueRef bswap(LLVMValueRef n) { 223 auto bits = LLVMGetIntTypeWidth(LLVMTypeOf(n)); 224 return LLVMBuildCall(builder, getBswap(bits), &n, 1, ""); 225 } 226 227 auto getBswap(uint bits) { 228 import std.conv; 229 auto name = context.getName("llvm.bswap.i" ~ to!string(bits)); 230 if (auto fPtr = name in cache) { 231 return *fPtr; 232 } 233 234 auto t = LLVMIntTypeInContext(llvmCtx, bits); 235 return cache[name] = LLVMAddFunction( 236 dmodule, 237 name.toStringz(context), 238 LLVMFunctionType(t, &t, 1, false), 239 ); 240 } 241 }