LLVMValueRef lp_build_one(struct lp_type type) { LLVMTypeRef elem_type; LLVMValueRef elems[LP_MAX_VECTOR_LENGTH]; unsigned i; assert(type.length <= LP_MAX_VECTOR_LENGTH); elem_type = lp_build_elem_type(type); if(type.floating) elems[0] = LLVMConstReal(elem_type, 1.0); else if(type.fixed) elems[0] = LLVMConstInt(elem_type, 1LL << (type.width/2), 0); else if(!type.norm) elems[0] = LLVMConstInt(elem_type, 1, 0); else if(type.sign) elems[0] = LLVMConstInt(elem_type, (1LL << (type.width - 1)) - 1, 0); else { /* special case' -- 1.0 for normalized types is more easily attained if * we start with a vector consisting of all bits set */ LLVMTypeRef vec_type = LLVMVectorType(elem_type, type.length); LLVMValueRef vec = LLVMConstAllOnes(vec_type); #if 0 if(type.sign) /* TODO: Unfortunately this caused "Tried to create a shift operation * on a non-integer type!" */ vec = LLVMConstLShr(vec, lp_build_const_int_vec(type, 1)); #endif return vec; } for(i = 1; i < type.length; ++i) elems[i] = elems[0]; if (type.length == 1) return elems[0]; else return LLVMConstVector(elems, type.length); }
LLVMValueRef gen_shr(compile_t* c, ast_t* left, ast_t* right) { ast_t* type = ast_type(left); bool sign = is_signed(c->opt, type); LLVMValueRef l_value = gen_expr(c, left); LLVMValueRef r_value = gen_expr(c, right); if((l_value == NULL) || (r_value == NULL)) return NULL; if(LLVMIsConstant(l_value) && LLVMIsConstant(r_value)) { if(sign) return LLVMConstAShr(l_value, r_value); return LLVMConstLShr(l_value, r_value); } if(sign) return LLVMBuildAShr(c->builder, l_value, r_value, ""); return LLVMBuildLShr(c->builder, l_value, r_value, ""); }
/** * Generate a * b */ LLVMValueRef lp_build_mul(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b) { const struct lp_type type = bld->type; LLVMValueRef shift; LLVMValueRef res; if(a == bld->zero) return bld->zero; if(a == bld->one) return b; if(b == bld->zero) return bld->zero; if(b == bld->one) return a; if(a == bld->undef || b == bld->undef) return bld->undef; if(!type.floating && !type.fixed && type.norm) { if(type.width == 8) { struct lp_type i16_type = lp_wider_type(type); LLVMValueRef al, ah, bl, bh, abl, abh, ab; lp_build_unpack2(bld->builder, type, i16_type, a, &al, &ah); lp_build_unpack2(bld->builder, type, i16_type, b, &bl, &bh); /* PMULLW, PSRLW, PADDW */ abl = lp_build_mul_u8n(bld->builder, i16_type, al, bl); abh = lp_build_mul_u8n(bld->builder, i16_type, ah, bh); ab = lp_build_pack2(bld->builder, i16_type, type, abl, abh); return ab; } /* FIXME */ assert(0); } if(type.fixed) shift = lp_build_int_const_scalar(type, type.width/2); else shift = NULL; if(LLVMIsConstant(a) && LLVMIsConstant(b)) { res = LLVMConstMul(a, b); if(shift) { if(type.sign) res = LLVMConstAShr(res, shift); else res = LLVMConstLShr(res, shift); } } else { res = LLVMBuildMul(bld->builder, a, b, ""); if(shift) { if(type.sign) res = LLVMBuildAShr(bld->builder, res, shift, ""); else res = LLVMBuildLShr(bld->builder, res, shift, ""); } } return res; }