1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 29#include "util/u_debug.h" 30 31#include "lp_bld_type.h" 32#include "lp_bld_const.h" 33#include "lp_bld_init.h" 34 35 36LLVMTypeRef 37lp_build_elem_type(struct gallivm_state *gallivm, struct lp_type type) 38{ 39 if (type.floating) { 40 switch(type.width) { 41 case 16: 42 return LLVMIntTypeInContext(gallivm->context, 16); 43 break; 44 case 32: 45 return LLVMFloatTypeInContext(gallivm->context); 46 break; 47 case 64: 48 return LLVMDoubleTypeInContext(gallivm->context); 49 break; 50 default: 51 assert(0); 52 return LLVMFloatTypeInContext(gallivm->context); 53 } 54 } 55 else { 56 return LLVMIntTypeInContext(gallivm->context, type.width); 57 } 58} 59 60 61LLVMTypeRef 62lp_build_vec_type(struct gallivm_state *gallivm,struct lp_type type) 63{ 64 LLVMTypeRef elem_type = lp_build_elem_type(gallivm, type); 65 if (type.length == 1) 66 return elem_type; 67 else 68 return LLVMVectorType(elem_type, type.length); 69} 70 71 72/** 73 * This function is a mirror of lp_build_elem_type() above. 74 * 75 * XXX: I'm not sure if it wouldn't be easier/efficient to just recreate the 76 * type and check for identity. 77 */ 78boolean 79lp_check_elem_type(struct lp_type type, LLVMTypeRef elem_type) 80{ 81 LLVMTypeKind elem_kind; 82 83 assert(elem_type); 84 if(!elem_type) 85 return FALSE; 86 87 elem_kind = LLVMGetTypeKind(elem_type); 88 89 if (type.floating) { 90 switch(type.width) { 91 case 16: 92 if(elem_kind != LLVMIntegerTypeKind) 93 return FALSE; 94 break; 95 case 32: 96 if(elem_kind != LLVMFloatTypeKind) 97 return FALSE; 98 break; 99 case 64: 100 if(elem_kind != LLVMDoubleTypeKind) 101 return FALSE; 102 break; 103 default: 104 assert(0); 105 return FALSE; 106 } 107 } 108 else { 109 if(elem_kind != LLVMIntegerTypeKind) 110 return FALSE; 111 112 if(LLVMGetIntTypeWidth(elem_type) != type.width) 113 return FALSE; 114 } 115 116 return TRUE; 117} 118 119 120boolean 121lp_check_vec_type(struct lp_type type, LLVMTypeRef vec_type) 122{ 123 LLVMTypeRef elem_type; 124 125 assert(vec_type); 126 if(!vec_type) 127 return FALSE; 128 129 if (type.length == 1) 130 return lp_check_elem_type(type, vec_type); 131 132 if(LLVMGetTypeKind(vec_type) != LLVMVectorTypeKind) 133 return FALSE; 134 135 if(LLVMGetVectorSize(vec_type) != type.length) 136 return FALSE; 137 138 elem_type = LLVMGetElementType(vec_type); 139 140 return lp_check_elem_type(type, elem_type); 141} 142 143 144boolean 145lp_check_value(struct lp_type type, LLVMValueRef val) 146{ 147 LLVMTypeRef vec_type; 148 149 assert(val); 150 if(!val) 151 return FALSE; 152 153 vec_type = LLVMTypeOf(val); 154 155 return lp_check_vec_type(type, vec_type); 156} 157 158 159LLVMTypeRef 160lp_build_int_elem_type(struct gallivm_state *gallivm, struct lp_type type) 161{ 162 return LLVMIntTypeInContext(gallivm->context, type.width); 163} 164 165 166LLVMTypeRef 167lp_build_int_vec_type(struct gallivm_state *gallivm, struct lp_type type) 168{ 169 LLVMTypeRef elem_type = lp_build_int_elem_type(gallivm, type); 170 if (type.length == 1) 171 return elem_type; 172 else 173 return LLVMVectorType(elem_type, type.length); 174} 175 176 177/** 178 * Create element of vector type 179 */ 180struct lp_type 181lp_elem_type(struct lp_type type) 182{ 183 struct lp_type res_type; 184 185 assert(type.length > 1); 186 res_type = type; 187 res_type.length = 1; 188 189 return res_type; 190} 191 192 193/** 194 * Create unsigned integer type variation of given type. 195 */ 196struct lp_type 197lp_uint_type(struct lp_type type) 198{ 199 struct lp_type res_type; 200 201 assert(type.length <= LP_MAX_VECTOR_LENGTH); 202 memset(&res_type, 0, sizeof res_type); 203 res_type.width = type.width; 204 res_type.length = type.length; 205 206 return res_type; 207} 208 209 210/** 211 * Create signed integer type variation of given type. 212 */ 213struct lp_type 214lp_int_type(struct lp_type type) 215{ 216 struct lp_type res_type; 217 218 assert(type.length <= LP_MAX_VECTOR_LENGTH); 219 memset(&res_type, 0, sizeof res_type); 220 res_type.width = type.width; 221 res_type.length = type.length; 222 res_type.sign = 1; 223 224 return res_type; 225} 226 227 228/** 229 * Return the type with twice the bit width (hence half the number of elements). 230 */ 231struct lp_type 232lp_wider_type(struct lp_type type) 233{ 234 struct lp_type res_type; 235 236 memcpy(&res_type, &type, sizeof res_type); 237 res_type.width *= 2; 238 res_type.length /= 2; 239 240 assert(res_type.length); 241 242 return res_type; 243} 244 245 246/** 247 * Return the size of the LLVMType in bits. 248 * XXX this function doesn't necessarily handle all LLVM types. 249 */ 250unsigned 251lp_sizeof_llvm_type(LLVMTypeRef t) 252{ 253 LLVMTypeKind k = LLVMGetTypeKind(t); 254 255 switch (k) { 256 case LLVMIntegerTypeKind: 257 return LLVMGetIntTypeWidth(t); 258 case LLVMFloatTypeKind: 259 return 8 * sizeof(float); 260 case LLVMDoubleTypeKind: 261 return 8 * sizeof(double); 262 case LLVMVectorTypeKind: 263 { 264 LLVMTypeRef elem = LLVMGetElementType(t); 265 unsigned len = LLVMGetVectorSize(t); 266 return len * lp_sizeof_llvm_type(elem); 267 } 268 break; 269 case LLVMArrayTypeKind: 270 { 271 LLVMTypeRef elem = LLVMGetElementType(t); 272 unsigned len = LLVMGetArrayLength(t); 273 return len * lp_sizeof_llvm_type(elem); 274 } 275 break; 276 default: 277 assert(0 && "Unexpected type in lp_get_llvm_type_size()"); 278 return 0; 279 } 280} 281 282 283/** 284 * Return string name for a LLVMTypeKind. Useful for debugging. 285 */ 286const char * 287lp_typekind_name(LLVMTypeKind t) 288{ 289 switch (t) { 290 case LLVMVoidTypeKind: 291 return "LLVMVoidTypeKind"; 292 case LLVMFloatTypeKind: 293 return "LLVMFloatTypeKind"; 294 case LLVMDoubleTypeKind: 295 return "LLVMDoubleTypeKind"; 296 case LLVMX86_FP80TypeKind: 297 return "LLVMX86_FP80TypeKind"; 298 case LLVMFP128TypeKind: 299 return "LLVMFP128TypeKind"; 300 case LLVMPPC_FP128TypeKind: 301 return "LLVMPPC_FP128TypeKind"; 302 case LLVMLabelTypeKind: 303 return "LLVMLabelTypeKind"; 304 case LLVMIntegerTypeKind: 305 return "LLVMIntegerTypeKind"; 306 case LLVMFunctionTypeKind: 307 return "LLVMFunctionTypeKind"; 308 case LLVMStructTypeKind: 309 return "LLVMStructTypeKind"; 310 case LLVMArrayTypeKind: 311 return "LLVMArrayTypeKind"; 312 case LLVMPointerTypeKind: 313 return "LLVMPointerTypeKind"; 314#if HAVE_LLVM < 0x0300 315 case LLVMOpaqueTypeKind: 316 return "LLVMOpaqueTypeKind"; 317#endif 318 case LLVMVectorTypeKind: 319 return "LLVMVectorTypeKind"; 320 case LLVMMetadataTypeKind: 321 return "LLVMMetadataTypeKind"; 322#if HAVE_LLVM == 0x0207 323 case LLVMUnionTypeKind: 324 return "LLVMUnionTypeKind"; 325#endif 326 default: 327 return "unknown LLVMTypeKind"; 328 } 329} 330 331 332/** 333 * Print an LLVMTypeRef. Like LLVMDumpValue(). For debugging. 334 */ 335void 336lp_dump_llvmtype(LLVMTypeRef t) 337{ 338 LLVMTypeKind k = LLVMGetTypeKind(t); 339 340 if (k == LLVMVectorTypeKind) { 341 LLVMTypeRef te = LLVMGetElementType(t); 342 LLVMTypeKind ke = LLVMGetTypeKind(te); 343 unsigned len = LLVMGetVectorSize(t); 344 if (ke == LLVMIntegerTypeKind) { 345 unsigned b = LLVMGetIntTypeWidth(te); 346 debug_printf("Vector [%u] of %u-bit Integer\n", len, b); 347 } 348 else { 349 debug_printf("Vector [%u] of %s\n", len, lp_typekind_name(ke)); 350 } 351 } 352 else if (k == LLVMArrayTypeKind) { 353 LLVMTypeRef te = LLVMGetElementType(t); 354 LLVMTypeKind ke = LLVMGetTypeKind(te); 355 unsigned len = LLVMGetArrayLength(t); 356 debug_printf("Array [%u] of %s\n", len, lp_typekind_name(ke)); 357 } 358 else if (k == LLVMIntegerTypeKind) { 359 unsigned b = LLVMGetIntTypeWidth(t); 360 debug_printf("%u-bit Integer\n", b); 361 } 362 else if (k == LLVMPointerTypeKind) { 363 LLVMTypeRef te = LLVMGetElementType(t); 364 debug_printf("Pointer to "); 365 lp_dump_llvmtype(te); 366 } 367 else { 368 debug_printf("%s\n", lp_typekind_name(k)); 369 } 370} 371 372 373void 374lp_build_context_init(struct lp_build_context *bld, 375 struct gallivm_state *gallivm, 376 struct lp_type type) 377{ 378 bld->gallivm = gallivm; 379 bld->type = type; 380 381 bld->int_elem_type = lp_build_int_elem_type(gallivm, type); 382 if (type.floating) 383 bld->elem_type = lp_build_elem_type(gallivm, type); 384 else 385 bld->elem_type = bld->int_elem_type; 386 387 if (type.length == 1) { 388 bld->int_vec_type = bld->int_elem_type; 389 bld->vec_type = bld->elem_type; 390 } 391 else { 392 bld->int_vec_type = LLVMVectorType(bld->int_elem_type, type.length); 393 bld->vec_type = LLVMVectorType(bld->elem_type, type.length); 394 } 395 396 bld->undef = LLVMGetUndef(bld->vec_type); 397 bld->zero = LLVMConstNull(bld->vec_type); 398 bld->one = lp_build_one(gallivm, type); 399} 400 401 402/** 403 * Count the number of instructions in a function. 404 */ 405unsigned 406lp_build_count_instructions(LLVMValueRef function) 407{ 408 unsigned num_instrs = 0; 409 LLVMBasicBlockRef block; 410 411 block = LLVMGetFirstBasicBlock(function); 412 while (block) { 413 LLVMValueRef instr; 414 instr = LLVMGetFirstInstruction(block); 415 while (instr) { 416 ++num_instrs; 417 418 instr = LLVMGetNextInstruction(instr); 419 } 420 block = LLVMGetNextBasicBlock(block); 421 } 422 423 return num_instrs; 424} 425