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 36 LLVMTypeRef 37 lp_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 61 LLVMTypeRef 62 lp_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 */ 78 boolean 79 lp_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 120 boolean 121 lp_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 144 boolean 145 lp_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 159 LLVMTypeRef 160 lp_build_int_elem_type(struct gallivm_state *gallivm, struct lp_type type) 161 { 162 return LLVMIntTypeInContext(gallivm->context, type.width); 163 } 164 165 166 LLVMTypeRef 167 lp_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 */ 180 struct lp_type 181 lp_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 */ 196 struct lp_type 197 lp_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 */ 213 struct lp_type 214 lp_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 */ 231 struct lp_type 232 lp_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 */ 250 unsigned 251 lp_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 */ 286 const char * 287 lp_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 */ 335 void 336 lp_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 373 void 374 lp_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 */ 405 unsigned 406 lp_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