/************************************************************************** * * Copyright 2009 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include "util/u_debug.h" #include "lp_bld_type.h" #include "lp_bld_const.h" #include "lp_bld_init.h" LLVMTypeRef lp_build_elem_type(struct gallivm_state *gallivm, struct lp_type type) { if (type.floating) { switch(type.width) { case 16: return LLVMIntTypeInContext(gallivm->context, 16); break; case 32: return LLVMFloatTypeInContext(gallivm->context); break; case 64: return LLVMDoubleTypeInContext(gallivm->context); break; default: assert(0); return LLVMFloatTypeInContext(gallivm->context); } } else { return LLVMIntTypeInContext(gallivm->context, type.width); } } LLVMTypeRef lp_build_vec_type(struct gallivm_state *gallivm,struct lp_type type) { LLVMTypeRef elem_type = lp_build_elem_type(gallivm, type); if (type.length == 1) return elem_type; else return LLVMVectorType(elem_type, type.length); } /** * This function is a mirror of lp_build_elem_type() above. * * XXX: I'm not sure if it wouldn't be easier/efficient to just recreate the * type and check for identity. */ boolean lp_check_elem_type(struct lp_type type, LLVMTypeRef elem_type) { LLVMTypeKind elem_kind; assert(elem_type); if(!elem_type) return FALSE; elem_kind = LLVMGetTypeKind(elem_type); if (type.floating) { switch(type.width) { case 16: if(elem_kind != LLVMIntegerTypeKind) return FALSE; break; case 32: if(elem_kind != LLVMFloatTypeKind) return FALSE; break; case 64: if(elem_kind != LLVMDoubleTypeKind) return FALSE; break; default: assert(0); return FALSE; } } else { if(elem_kind != LLVMIntegerTypeKind) return FALSE; if(LLVMGetIntTypeWidth(elem_type) != type.width) return FALSE; } return TRUE; } boolean lp_check_vec_type(struct lp_type type, LLVMTypeRef vec_type) { LLVMTypeRef elem_type; assert(vec_type); if(!vec_type) return FALSE; if (type.length == 1) return lp_check_elem_type(type, vec_type); if(LLVMGetTypeKind(vec_type) != LLVMVectorTypeKind) return FALSE; if(LLVMGetVectorSize(vec_type) != type.length) return FALSE; elem_type = LLVMGetElementType(vec_type); return lp_check_elem_type(type, elem_type); } boolean lp_check_value(struct lp_type type, LLVMValueRef val) { LLVMTypeRef vec_type; assert(val); if(!val) return FALSE; vec_type = LLVMTypeOf(val); return lp_check_vec_type(type, vec_type); } LLVMTypeRef lp_build_int_elem_type(struct gallivm_state *gallivm, struct lp_type type) { return LLVMIntTypeInContext(gallivm->context, type.width); } LLVMTypeRef lp_build_int_vec_type(struct gallivm_state *gallivm, struct lp_type type) { LLVMTypeRef elem_type = lp_build_int_elem_type(gallivm, type); if (type.length == 1) return elem_type; else return LLVMVectorType(elem_type, type.length); } /** * Create element of vector type */ struct lp_type lp_elem_type(struct lp_type type) { struct lp_type res_type; assert(type.length > 1); res_type = type; res_type.length = 1; return res_type; } /** * Create unsigned integer type variation of given type. */ struct lp_type lp_uint_type(struct lp_type type) { struct lp_type res_type; assert(type.length <= LP_MAX_VECTOR_LENGTH); memset(&res_type, 0, sizeof res_type); res_type.width = type.width; res_type.length = type.length; return res_type; } /** * Create signed integer type variation of given type. */ struct lp_type lp_int_type(struct lp_type type) { struct lp_type res_type; assert(type.length <= LP_MAX_VECTOR_LENGTH); memset(&res_type, 0, sizeof res_type); res_type.width = type.width; res_type.length = type.length; res_type.sign = 1; return res_type; } /** * Return the type with twice the bit width (hence half the number of elements). */ struct lp_type lp_wider_type(struct lp_type type) { struct lp_type res_type; memcpy(&res_type, &type, sizeof res_type); res_type.width *= 2; res_type.length /= 2; assert(res_type.length); return res_type; } /** * Return the size of the LLVMType in bits. * XXX this function doesn't necessarily handle all LLVM types. */ unsigned lp_sizeof_llvm_type(LLVMTypeRef t) { LLVMTypeKind k = LLVMGetTypeKind(t); switch (k) { case LLVMIntegerTypeKind: return LLVMGetIntTypeWidth(t); case LLVMFloatTypeKind: return 8 * sizeof(float); case LLVMDoubleTypeKind: return 8 * sizeof(double); case LLVMVectorTypeKind: { LLVMTypeRef elem = LLVMGetElementType(t); unsigned len = LLVMGetVectorSize(t); return len * lp_sizeof_llvm_type(elem); } break; case LLVMArrayTypeKind: { LLVMTypeRef elem = LLVMGetElementType(t); unsigned len = LLVMGetArrayLength(t); return len * lp_sizeof_llvm_type(elem); } break; default: assert(0 && "Unexpected type in lp_get_llvm_type_size()"); return 0; } } /** * Return string name for a LLVMTypeKind. Useful for debugging. */ const char * lp_typekind_name(LLVMTypeKind t) { switch (t) { case LLVMVoidTypeKind: return "LLVMVoidTypeKind"; case LLVMFloatTypeKind: return "LLVMFloatTypeKind"; case LLVMDoubleTypeKind: return "LLVMDoubleTypeKind"; case LLVMX86_FP80TypeKind: return "LLVMX86_FP80TypeKind"; case LLVMFP128TypeKind: return "LLVMFP128TypeKind"; case LLVMPPC_FP128TypeKind: return "LLVMPPC_FP128TypeKind"; case LLVMLabelTypeKind: return "LLVMLabelTypeKind"; case LLVMIntegerTypeKind: return "LLVMIntegerTypeKind"; case LLVMFunctionTypeKind: return "LLVMFunctionTypeKind"; case LLVMStructTypeKind: return "LLVMStructTypeKind"; case LLVMArrayTypeKind: return "LLVMArrayTypeKind"; case LLVMPointerTypeKind: return "LLVMPointerTypeKind"; #if HAVE_LLVM < 0x0300 case LLVMOpaqueTypeKind: return "LLVMOpaqueTypeKind"; #endif case LLVMVectorTypeKind: return "LLVMVectorTypeKind"; case LLVMMetadataTypeKind: return "LLVMMetadataTypeKind"; #if HAVE_LLVM == 0x0207 case LLVMUnionTypeKind: return "LLVMUnionTypeKind"; #endif default: return "unknown LLVMTypeKind"; } } /** * Print an LLVMTypeRef. Like LLVMDumpValue(). For debugging. */ void lp_dump_llvmtype(LLVMTypeRef t) { LLVMTypeKind k = LLVMGetTypeKind(t); if (k == LLVMVectorTypeKind) { LLVMTypeRef te = LLVMGetElementType(t); LLVMTypeKind ke = LLVMGetTypeKind(te); unsigned len = LLVMGetVectorSize(t); if (ke == LLVMIntegerTypeKind) { unsigned b = LLVMGetIntTypeWidth(te); debug_printf("Vector [%u] of %u-bit Integer\n", len, b); } else { debug_printf("Vector [%u] of %s\n", len, lp_typekind_name(ke)); } } else if (k == LLVMArrayTypeKind) { LLVMTypeRef te = LLVMGetElementType(t); LLVMTypeKind ke = LLVMGetTypeKind(te); unsigned len = LLVMGetArrayLength(t); debug_printf("Array [%u] of %s\n", len, lp_typekind_name(ke)); } else if (k == LLVMIntegerTypeKind) { unsigned b = LLVMGetIntTypeWidth(t); debug_printf("%u-bit Integer\n", b); } else if (k == LLVMPointerTypeKind) { LLVMTypeRef te = LLVMGetElementType(t); debug_printf("Pointer to "); lp_dump_llvmtype(te); } else { debug_printf("%s\n", lp_typekind_name(k)); } } void lp_build_context_init(struct lp_build_context *bld, struct gallivm_state *gallivm, struct lp_type type) { bld->gallivm = gallivm; bld->type = type; bld->int_elem_type = lp_build_int_elem_type(gallivm, type); if (type.floating) bld->elem_type = lp_build_elem_type(gallivm, type); else bld->elem_type = bld->int_elem_type; if (type.length == 1) { bld->int_vec_type = bld->int_elem_type; bld->vec_type = bld->elem_type; } else { bld->int_vec_type = LLVMVectorType(bld->int_elem_type, type.length); bld->vec_type = LLVMVectorType(bld->elem_type, type.length); } bld->undef = LLVMGetUndef(bld->vec_type); bld->zero = LLVMConstNull(bld->vec_type); bld->one = lp_build_one(gallivm, type); } /** * Count the number of instructions in a function. */ unsigned lp_build_count_instructions(LLVMValueRef function) { unsigned num_instrs = 0; LLVMBasicBlockRef block; block = LLVMGetFirstBasicBlock(function); while (block) { LLVMValueRef instr; instr = LLVMGetFirstInstruction(block); while (instr) { ++num_instrs; instr = LLVMGetNextInstruction(instr); } block = LLVMGetNextBasicBlock(block); } return num_instrs; }