1from ctypes import POINTER, c_char_p, c_int, c_size_t, c_uint, c_bool, c_void_p 2import enum 3 4from llvmlite.binding import ffi 5from llvmlite.binding.common import _decode_string, _encode_string 6 7 8class Linkage(enum.IntEnum): 9 # The LLVMLinkage enum from llvm-c/Core.h 10 11 external = 0 12 available_externally = 1 13 linkonce_any = 2 14 linkonce_odr = 3 15 linkonce_odr_autohide = 4 16 weak_any = 5 17 weak_odr = 6 18 appending = 7 19 internal = 8 20 private = 9 21 dllimport = 10 22 dllexport = 11 23 external_weak = 12 24 ghost = 13 25 common = 14 26 linker_private = 15 27 linker_private_weak = 16 28 29 30class Visibility(enum.IntEnum): 31 # The LLVMVisibility enum from llvm-c/Core.h 32 33 default = 0 34 hidden = 1 35 protected = 2 36 37 38class StorageClass(enum.IntEnum): 39 # The LLVMDLLStorageClass enum from llvm-c/Core.h 40 41 default = 0 42 dllimport = 1 43 dllexport = 2 44 45 46class TypeRef(ffi.ObjectRef): 47 """A weak reference to a LLVM type 48 """ 49 @property 50 def name(self): 51 """ 52 Get type name 53 """ 54 return ffi.ret_string(ffi.lib.LLVMPY_GetTypeName(self)) 55 56 @property 57 def is_pointer(self): 58 """ 59 Returns true is the type is a pointer type. 60 """ 61 return ffi.lib.LLVMPY_TypeIsPointer(self) 62 63 @property 64 def element_type(self): 65 """ 66 Returns the pointed-to type. When the type is not a pointer, 67 raises exception. 68 """ 69 if not self.is_pointer: 70 raise ValueError("Type {} is not a pointer".format(self)) 71 return TypeRef(ffi.lib.LLVMPY_GetElementType(self)) 72 73 def __str__(self): 74 return ffi.ret_string(ffi.lib.LLVMPY_PrintType(self)) 75 76 77class ValueRef(ffi.ObjectRef): 78 """A weak reference to a LLVM value. 79 """ 80 81 def __init__(self, ptr, kind, parents): 82 self._kind = kind 83 self._parents = parents 84 ffi.ObjectRef.__init__(self, ptr) 85 86 def __str__(self): 87 with ffi.OutputString() as outstr: 88 ffi.lib.LLVMPY_PrintValueToString(self, outstr) 89 return str(outstr) 90 91 @property 92 def module(self): 93 """ 94 The module this function or global variable value was obtained from. 95 """ 96 return self._parents.get('module') 97 98 @property 99 def function(self): 100 """ 101 The function this argument or basic block value was obtained from. 102 """ 103 return self._parents.get('function') 104 105 @property 106 def block(self): 107 """ 108 The block this instruction value was obtained from. 109 """ 110 return self._parents.get('block') 111 112 @property 113 def instruction(self): 114 """ 115 The instruction this operand value was obtained from. 116 """ 117 return self._parents.get('instruction') 118 119 @property 120 def is_global(self): 121 return self._kind == 'global' 122 123 @property 124 def is_function(self): 125 return self._kind == 'function' 126 127 @property 128 def is_block(self): 129 return self._kind == 'block' 130 131 @property 132 def is_argument(self): 133 return self._kind == 'argument' 134 135 @property 136 def is_instruction(self): 137 return self._kind == 'instruction' 138 139 @property 140 def is_operand(self): 141 return self._kind == 'operand' 142 143 @property 144 def name(self): 145 return _decode_string(ffi.lib.LLVMPY_GetValueName(self)) 146 147 @name.setter 148 def name(self, val): 149 ffi.lib.LLVMPY_SetValueName(self, _encode_string(val)) 150 151 @property 152 def linkage(self): 153 return Linkage(ffi.lib.LLVMPY_GetLinkage(self)) 154 155 @linkage.setter 156 def linkage(self, value): 157 if not isinstance(value, Linkage): 158 value = Linkage[value] 159 ffi.lib.LLVMPY_SetLinkage(self, value) 160 161 @property 162 def visibility(self): 163 return Visibility(ffi.lib.LLVMPY_GetVisibility(self)) 164 165 @visibility.setter 166 def visibility(self, value): 167 if not isinstance(value, Visibility): 168 value = Visibility[value] 169 ffi.lib.LLVMPY_SetVisibility(self, value) 170 171 @property 172 def storage_class(self): 173 return StorageClass(ffi.lib.LLVMPY_GetDLLStorageClass(self)) 174 175 @storage_class.setter 176 def storage_class(self, value): 177 if not isinstance(value, StorageClass): 178 value = StorageClass[value] 179 ffi.lib.LLVMPY_SetDLLStorageClass(self, value) 180 181 def add_function_attribute(self, attr): 182 """Only works on function value 183 184 Parameters 185 ----------- 186 attr : str 187 attribute name 188 """ 189 if not self.is_function: 190 raise ValueError('expected function value, got %s' % (self._kind,)) 191 attrname = str(attr) 192 attrval = ffi.lib.LLVMPY_GetEnumAttributeKindForName( 193 _encode_string(attrname), len(attrname)) 194 if attrval == 0: 195 raise ValueError('no such attribute {!r}'.format(attrname)) 196 ffi.lib.LLVMPY_AddFunctionAttr(self, attrval) 197 198 @property 199 def type(self): 200 """ 201 This value's LLVM type. 202 """ 203 # XXX what does this return? 204 return TypeRef(ffi.lib.LLVMPY_TypeOf(self)) 205 206 @property 207 def is_declaration(self): 208 """ 209 Whether this value (presumably global) is defined in the current 210 module. 211 """ 212 if not (self.is_global or self.is_function): 213 raise ValueError('expected global or function value, got %s' 214 % (self._kind,)) 215 return ffi.lib.LLVMPY_IsDeclaration(self) 216 217 @property 218 def attributes(self): 219 """ 220 Return an iterator over this value's attributes. 221 The iterator will yield a string for each attribute. 222 """ 223 itr = iter(()) 224 if self.is_function: 225 it = ffi.lib.LLVMPY_FunctionAttributesIter(self) 226 itr = _AttributeListIterator(it) 227 elif self.is_instruction: 228 if self.opcode == 'call': 229 it = ffi.lib.LLVMPY_CallInstAttributesIter(self) 230 itr = _AttributeListIterator(it) 231 elif self.opcode == 'invoke': 232 it = ffi.lib.LLVMPY_InvokeInstAttributesIter(self) 233 itr = _AttributeListIterator(it) 234 elif self.is_global: 235 it = ffi.lib.LLVMPY_GlobalAttributesIter(self) 236 itr = _AttributeSetIterator(it) 237 elif self.is_argument: 238 it = ffi.lib.LLVMPY_ArgumentAttributesIter(self) 239 itr = _AttributeSetIterator(it) 240 return itr 241 242 @property 243 def blocks(self): 244 """ 245 Return an iterator over this function's blocks. 246 The iterator will yield a ValueRef for each block. 247 """ 248 if not self.is_function: 249 raise ValueError('expected function value, got %s' % (self._kind,)) 250 it = ffi.lib.LLVMPY_FunctionBlocksIter(self) 251 parents = self._parents.copy() 252 parents.update(function=self) 253 return _BlocksIterator(it, parents) 254 255 @property 256 def arguments(self): 257 """ 258 Return an iterator over this function's arguments. 259 The iterator will yield a ValueRef for each argument. 260 """ 261 if not self.is_function: 262 raise ValueError('expected function value, got %s' % (self._kind,)) 263 it = ffi.lib.LLVMPY_FunctionArgumentsIter(self) 264 parents = self._parents.copy() 265 parents.update(function=self) 266 return _ArgumentsIterator(it, parents) 267 268 @property 269 def instructions(self): 270 """ 271 Return an iterator over this block's instructions. 272 The iterator will yield a ValueRef for each instruction. 273 """ 274 if not self.is_block: 275 raise ValueError('expected block value, got %s' % (self._kind,)) 276 it = ffi.lib.LLVMPY_BlockInstructionsIter(self) 277 parents = self._parents.copy() 278 parents.update(block=self) 279 return _InstructionsIterator(it, parents) 280 281 @property 282 def operands(self): 283 """ 284 Return an iterator over this instruction's operands. 285 The iterator will yield a ValueRef for each operand. 286 """ 287 if not self.is_instruction: 288 raise ValueError('expected instruction value, got %s' 289 % (self._kind,)) 290 it = ffi.lib.LLVMPY_InstructionOperandsIter(self) 291 parents = self._parents.copy() 292 parents.update(instruction=self) 293 return _OperandsIterator(it, parents) 294 295 @property 296 def opcode(self): 297 if not self.is_instruction: 298 raise ValueError('expected instruction value, got %s' 299 % (self._kind,)) 300 return ffi.ret_string(ffi.lib.LLVMPY_GetOpcodeName(self)) 301 302 303class _ValueIterator(ffi.ObjectRef): 304 305 kind = None # derived classes must specify the Value kind value 306 # as class attribute 307 308 def __init__(self, ptr, parents): 309 ffi.ObjectRef.__init__(self, ptr) 310 # Keep parent objects (module, function, etc) alive 311 self._parents = parents 312 if self.kind is None: 313 raise NotImplementedError('%s must specify kind attribute' 314 % (type(self).__name__,)) 315 316 def __next__(self): 317 vp = self._next() 318 if vp: 319 return ValueRef(vp, self.kind, self._parents) 320 else: 321 raise StopIteration 322 323 next = __next__ 324 325 def __iter__(self): 326 return self 327 328 329class _AttributeIterator(ffi.ObjectRef): 330 331 def __next__(self): 332 vp = self._next() 333 if vp: 334 return vp 335 else: 336 raise StopIteration 337 338 next = __next__ 339 340 def __iter__(self): 341 return self 342 343 344class _AttributeListIterator(_AttributeIterator): 345 346 def _dispose(self): 347 self._capi.LLVMPY_DisposeAttributeListIter(self) 348 349 def _next(self): 350 return ffi.ret_bytes(ffi.lib.LLVMPY_AttributeListIterNext(self)) 351 352 353class _AttributeSetIterator(_AttributeIterator): 354 355 def _dispose(self): 356 self._capi.LLVMPY_DisposeAttributeSetIter(self) 357 358 def _next(self): 359 return ffi.ret_bytes(ffi.lib.LLVMPY_AttributeSetIterNext(self)) 360 361 362class _BlocksIterator(_ValueIterator): 363 364 kind = 'block' 365 366 def _dispose(self): 367 self._capi.LLVMPY_DisposeBlocksIter(self) 368 369 def _next(self): 370 return ffi.lib.LLVMPY_BlocksIterNext(self) 371 372 373class _ArgumentsIterator(_ValueIterator): 374 375 kind = 'argument' 376 377 def _dispose(self): 378 self._capi.LLVMPY_DisposeArgumentsIter(self) 379 380 def _next(self): 381 return ffi.lib.LLVMPY_ArgumentsIterNext(self) 382 383 384class _InstructionsIterator(_ValueIterator): 385 386 kind = 'instruction' 387 388 def _dispose(self): 389 self._capi.LLVMPY_DisposeInstructionsIter(self) 390 391 def _next(self): 392 return ffi.lib.LLVMPY_InstructionsIterNext(self) 393 394 395class _OperandsIterator(_ValueIterator): 396 397 kind = 'operand' 398 399 def _dispose(self): 400 self._capi.LLVMPY_DisposeOperandsIter(self) 401 402 def _next(self): 403 return ffi.lib.LLVMPY_OperandsIterNext(self) 404 405 406# FFI 407 408ffi.lib.LLVMPY_PrintValueToString.argtypes = [ 409 ffi.LLVMValueRef, 410 POINTER(c_char_p) 411] 412 413ffi.lib.LLVMPY_GetGlobalParent.argtypes = [ffi.LLVMValueRef] 414ffi.lib.LLVMPY_GetGlobalParent.restype = ffi.LLVMModuleRef 415 416ffi.lib.LLVMPY_GetValueName.argtypes = [ffi.LLVMValueRef] 417ffi.lib.LLVMPY_GetValueName.restype = c_char_p 418 419ffi.lib.LLVMPY_SetValueName.argtypes = [ffi.LLVMValueRef, c_char_p] 420 421ffi.lib.LLVMPY_TypeOf.argtypes = [ffi.LLVMValueRef] 422ffi.lib.LLVMPY_TypeOf.restype = ffi.LLVMTypeRef 423 424 425ffi.lib.LLVMPY_PrintType.argtypes = [ffi.LLVMTypeRef] 426ffi.lib.LLVMPY_PrintType.restype = c_void_p 427 428ffi.lib.LLVMPY_TypeIsPointer.argtypes = [ffi.LLVMTypeRef] 429ffi.lib.LLVMPY_TypeIsPointer.restype = c_bool 430 431ffi.lib.LLVMPY_GetElementType.argtypes = [ffi.LLVMTypeRef] 432ffi.lib.LLVMPY_GetElementType.restype = ffi.LLVMTypeRef 433 434 435ffi.lib.LLVMPY_GetTypeName.argtypes = [ffi.LLVMTypeRef] 436ffi.lib.LLVMPY_GetTypeName.restype = c_void_p 437 438ffi.lib.LLVMPY_GetLinkage.argtypes = [ffi.LLVMValueRef] 439ffi.lib.LLVMPY_GetLinkage.restype = c_int 440 441ffi.lib.LLVMPY_SetLinkage.argtypes = [ffi.LLVMValueRef, c_int] 442 443ffi.lib.LLVMPY_GetVisibility.argtypes = [ffi.LLVMValueRef] 444ffi.lib.LLVMPY_GetVisibility.restype = c_int 445 446ffi.lib.LLVMPY_SetVisibility.argtypes = [ffi.LLVMValueRef, c_int] 447 448ffi.lib.LLVMPY_GetDLLStorageClass.argtypes = [ffi.LLVMValueRef] 449ffi.lib.LLVMPY_GetDLLStorageClass.restype = c_int 450 451ffi.lib.LLVMPY_SetDLLStorageClass.argtypes = [ffi.LLVMValueRef, c_int] 452 453ffi.lib.LLVMPY_GetEnumAttributeKindForName.argtypes = [c_char_p, c_size_t] 454ffi.lib.LLVMPY_GetEnumAttributeKindForName.restype = c_uint 455 456ffi.lib.LLVMPY_AddFunctionAttr.argtypes = [ffi.LLVMValueRef, c_uint] 457 458ffi.lib.LLVMPY_IsDeclaration.argtypes = [ffi.LLVMValueRef] 459ffi.lib.LLVMPY_IsDeclaration.restype = c_int 460 461ffi.lib.LLVMPY_FunctionAttributesIter.argtypes = [ffi.LLVMValueRef] 462ffi.lib.LLVMPY_FunctionAttributesIter.restype = ffi.LLVMAttributeListIterator 463 464ffi.lib.LLVMPY_CallInstAttributesIter.argtypes = [ffi.LLVMValueRef] 465ffi.lib.LLVMPY_CallInstAttributesIter.restype = ffi.LLVMAttributeListIterator 466 467ffi.lib.LLVMPY_InvokeInstAttributesIter.argtypes = [ffi.LLVMValueRef] 468ffi.lib.LLVMPY_InvokeInstAttributesIter.restype = ffi.LLVMAttributeListIterator 469 470ffi.lib.LLVMPY_GlobalAttributesIter.argtypes = [ffi.LLVMValueRef] 471ffi.lib.LLVMPY_GlobalAttributesIter.restype = ffi.LLVMAttributeSetIterator 472 473ffi.lib.LLVMPY_ArgumentAttributesIter.argtypes = [ffi.LLVMValueRef] 474ffi.lib.LLVMPY_ArgumentAttributesIter.restype = ffi.LLVMAttributeSetIterator 475 476ffi.lib.LLVMPY_FunctionBlocksIter.argtypes = [ffi.LLVMValueRef] 477ffi.lib.LLVMPY_FunctionBlocksIter.restype = ffi.LLVMBlocksIterator 478 479ffi.lib.LLVMPY_FunctionArgumentsIter.argtypes = [ffi.LLVMValueRef] 480ffi.lib.LLVMPY_FunctionArgumentsIter.restype = ffi.LLVMArgumentsIterator 481 482ffi.lib.LLVMPY_BlockInstructionsIter.argtypes = [ffi.LLVMValueRef] 483ffi.lib.LLVMPY_BlockInstructionsIter.restype = ffi.LLVMInstructionsIterator 484 485ffi.lib.LLVMPY_InstructionOperandsIter.argtypes = [ffi.LLVMValueRef] 486ffi.lib.LLVMPY_InstructionOperandsIter.restype = ffi.LLVMOperandsIterator 487 488ffi.lib.LLVMPY_DisposeAttributeListIter.argtypes = [ 489 ffi.LLVMAttributeListIterator] 490 491ffi.lib.LLVMPY_DisposeAttributeSetIter.argtypes = [ffi.LLVMAttributeSetIterator] 492 493ffi.lib.LLVMPY_DisposeBlocksIter.argtypes = [ffi.LLVMBlocksIterator] 494 495ffi.lib.LLVMPY_DisposeInstructionsIter.argtypes = [ffi.LLVMInstructionsIterator] 496 497ffi.lib.LLVMPY_DisposeOperandsIter.argtypes = [ffi.LLVMOperandsIterator] 498 499ffi.lib.LLVMPY_AttributeListIterNext.argtypes = [ffi.LLVMAttributeListIterator] 500ffi.lib.LLVMPY_AttributeListIterNext.restype = c_void_p 501 502ffi.lib.LLVMPY_AttributeSetIterNext.argtypes = [ffi.LLVMAttributeSetIterator] 503ffi.lib.LLVMPY_AttributeSetIterNext.restype = c_void_p 504 505ffi.lib.LLVMPY_BlocksIterNext.argtypes = [ffi.LLVMBlocksIterator] 506ffi.lib.LLVMPY_BlocksIterNext.restype = ffi.LLVMValueRef 507 508ffi.lib.LLVMPY_ArgumentsIterNext.argtypes = [ffi.LLVMArgumentsIterator] 509ffi.lib.LLVMPY_ArgumentsIterNext.restype = ffi.LLVMValueRef 510 511ffi.lib.LLVMPY_InstructionsIterNext.argtypes = [ffi.LLVMInstructionsIterator] 512ffi.lib.LLVMPY_InstructionsIterNext.restype = ffi.LLVMValueRef 513 514ffi.lib.LLVMPY_OperandsIterNext.argtypes = [ffi.LLVMOperandsIterator] 515ffi.lib.LLVMPY_OperandsIterNext.restype = ffi.LLVMValueRef 516 517ffi.lib.LLVMPY_GetOpcodeName.argtypes = [ffi.LLVMValueRef] 518ffi.lib.LLVMPY_GetOpcodeName.restype = c_void_p 519