/** * Generate abs(a) */ LLVMValueRef lp_build_abs(struct lp_build_context *bld, LLVMValueRef a) { const struct lp_type type = bld->type; LLVMTypeRef vec_type = lp_build_vec_type(type); if(!type.sign) return a; if(type.floating) { /* Mask out the sign bit */ LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); unsigned long long absMask = ~(1ULL << (type.width - 1)); LLVMValueRef mask = lp_build_int_const_scalar(type, ((unsigned long long) absMask)); a = LLVMBuildBitCast(bld->builder, a, int_vec_type, ""); a = LLVMBuildAnd(bld->builder, a, mask, ""); a = LLVMBuildBitCast(bld->builder, a, vec_type, ""); return a; } if(type.width*type.length == 128 && util_cpu_caps.has_ssse3) { switch(type.width) { case 8: return lp_build_intrinsic_unary(bld->builder, "llvm.x86.ssse3.pabs.b.128", vec_type, a); case 16: return lp_build_intrinsic_unary(bld->builder, "llvm.x86.ssse3.pabs.w.128", vec_type, a); case 32: return lp_build_intrinsic_unary(bld->builder, "llvm.x86.ssse3.pabs.d.128", vec_type, a); } } return lp_build_max(bld, a, LLVMBuildNeg(bld->builder, a, "")); }
static void emit_ineg(const struct lp_build_tgsi_action *action, struct lp_build_tgsi_context *bld_base, struct lp_build_emit_data *emit_data) { LLVMBuilderRef builder = bld_base->base.gallivm->builder; emit_data->output[emit_data->chan] = LLVMBuildNeg(builder, emit_data->args[0], ""); }
static LLVMValueRef translateNegOp(SymbolTable *TyTable, SymbolTable *ValTable, ASTNode *Node) { ASTNode *Expr = (ASTNode*) ptrVectorGet(&(Node->Child), 0); LLVMValueRef ExprPtr = translateExpr(TyTable, ValTable, Expr); LLVMValueRef ExprLoad = LLVMBuildLoad(Builder, ExprPtr, ""); LLVMBuildNeg (Builder, ExprLoad, ""); return ExprPtr; }
static void emit_iabs(const struct lp_build_tgsi_action *action, struct lp_build_tgsi_context *bld_base, struct lp_build_emit_data *emit_data) { LLVMBuilderRef builder = bld_base->base.gallivm->builder; emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_IMAX, emit_data->args[0], LLVMBuildNeg(builder, emit_data->args[0], "")); }
/** * Small vector x scale multiplication optimization. */ LLVMValueRef lp_build_mul_imm(struct lp_build_context *bld, LLVMValueRef a, int b) { LLVMValueRef factor; if(b == 0) return bld->zero; if(b == 1) return a; if(b == -1) return LLVMBuildNeg(bld->builder, a, ""); if(b == 2 && bld->type.floating) return lp_build_add(bld, a, a); if(util_is_pot(b)) { unsigned shift = ffs(b) - 1; if(bld->type.floating) { #if 0 /* * Power of two multiplication by directly manipulating the mantissa. * * XXX: This might not be always faster, it will introduce a small error * for multiplication by zero, and it will produce wrong results * for Inf and NaN. */ unsigned mantissa = lp_mantissa(bld->type); factor = lp_build_int_const_scalar(bld->type, (unsigned long long)shift << mantissa); a = LLVMBuildBitCast(bld->builder, a, lp_build_int_vec_type(bld->type), ""); a = LLVMBuildAdd(bld->builder, a, factor, ""); a = LLVMBuildBitCast(bld->builder, a, lp_build_vec_type(bld->type), ""); return a; #endif } else { factor = lp_build_const_scalar(bld->type, shift); return LLVMBuildShl(bld->builder, a, factor, ""); } } factor = lp_build_const_scalar(bld->type, (double)b); return lp_build_mul(bld, a, factor); }
LLVMValueRef gen_neg(compile_t* c, ast_t* ast) { LLVMValueRef value = gen_expr(c, ast); if(value == NULL) return NULL; if(LLVMIsAConstantFP(value)) return LLVMConstFNeg(value); if(LLVMIsAConstantInt(value)) return LLVMConstNeg(value); if(is_fp(value)) return LLVMBuildFNeg(c->builder, value, ""); return LLVMBuildNeg(c->builder, value, ""); }
/* * gen_shift * * Shifts are a little tricky, since LLVM has explicit left-shift and * right-shift instructions, which take non-negative shift values. BLISS, * on the other hand, has a single shift operator and generates right-shifts * when the RHS is negative. If the RHS is a constant, we can do the translation * here; otherwise, we have to build a conditional to check at runtime. */ static LLVMValueRef gen_shift (gencodectx_t gctx, expr_node_t *lhs, expr_node_t *rhs, LLVMTypeRef neededtype) { LLVMBuilderRef builder = gctx->curfn->builder; LLVMTypeRef inttype = gctx->fullwordtype; LLVMValueRef lval, rval, result, test; lval = (lhs == 0 ? 0 : llvmgen_expression(gctx, lhs, inttype)); if (expr_type(rhs) == EXPTYPE_PRIM_LIT) { long count = expr_litval(rhs); if (count < 0) { rval = LLVMConstInt(inttype, -count, 0); result = LLVMBuildLShr(builder, lval, rval, llvmgen_temp(gctx)); } else { rval = LLVMConstInt(inttype, count, 0); result = LLVMBuildShl(builder, lval, rval, llvmgen_temp(gctx)); } } else { LLVMBasicBlockRef exitblock = llvmgen_exitblock_create(gctx, 0); LLVMBasicBlockRef lshiftblk, rshiftblk; llvm_btrack_t *bt = llvmgen_btrack_create(gctx, exitblock); lshiftblk = LLVMInsertBasicBlockInContext(gctx->llvmctx, exitblock, llvmgen_label(gctx)); rshiftblk = LLVMInsertBasicBlockInContext(gctx->llvmctx, exitblock, llvmgen_label(gctx)); rval = llvmgen_expression(gctx, rhs, inttype); test = LLVMBuildICmp(builder, LLVMIntSLT, rval, LLVMConstNull(inttype), llvmgen_temp(gctx)); LLVMBuildCondBr(builder, test, rshiftblk, lshiftblk); LLVMPositionBuilderAtEnd(builder, lshiftblk); result = LLVMBuildShl(builder, lval, rval, llvmgen_temp(gctx)); llvmgen_btrack_update(gctx, bt, result); LLVMPositionBuilderAtEnd(builder, rshiftblk); rval = LLVMBuildNeg(builder, rval, llvmgen_temp(gctx)); result = LLVMBuildLShr(builder, lval, rval, llvmgen_temp(gctx)); llvmgen_btrack_update(gctx, bt, result); result = llvmgen_btrack_finalize(gctx, bt, inttype); } return llvmgen_adjustval(gctx, result, neededtype, 0); } /* gen_shift */
/* * gen_operator_expression * * Code generation for operator expressions. Most of them have straightforward * translations into LLVM instructions and are handled directly here. */ static LLVMValueRef gen_operator_expression (gencodectx_t gctx, expr_node_t *exp, LLVMTypeRef neededtype) { expr_node_t *lhs = expr_op_lhs(exp); expr_node_t *rhs = expr_op_rhs(exp); optype_t op = expr_op_type(exp); LLVMBuilderRef builder = gctx->curfn->builder; LLVMTypeRef inttype; LLVMValueRef lval, rval, result; if (op == OPER_FETCH) { return gen_fetch(gctx, rhs, neededtype); } if (op == OPER_ASSIGN) { LLVMValueRef val = llvmgen_assignment(gctx, lhs, rhs); return llvmgen_adjustval(gctx, val, neededtype, 0); } if (op == OPER_SHIFT) { return gen_shift(gctx, lhs, rhs, neededtype); } inttype = LLVMIntTypeInContext(gctx->llvmctx, machine_scalar_bits(gctx->mach)); lval = (lhs == 0 ? 0 : llvmgen_expression(gctx, lhs, inttype)); rval = llvmgen_expression(gctx, rhs, inttype); switch (op) { case OPER_UNARY_PLUS: result = rval; break; case OPER_UNARY_MINUS: result = LLVMBuildNeg(builder, rval, llvmgen_temp(gctx)); break; case OPER_ADD: result = LLVMBuildAdd(builder, lval, rval, llvmgen_temp(gctx)); break; case OPER_SUBTRACT: result = LLVMBuildSub(builder, lval, rval, llvmgen_temp(gctx)); break; case OPER_MULT: result = LLVMBuildMul(builder, lval, rval, llvmgen_temp(gctx)); break; case OPER_DIV: result = LLVMBuildUDiv(builder, lval, rval, llvmgen_temp(gctx)); break; case OPER_MODULO: result = LLVMBuildURem(builder, lval, rval, llvmgen_temp(gctx)); break; case OPER_AND: result = LLVMBuildAnd(builder, lval, rval, llvmgen_temp(gctx)); break; case OPER_OR: result = LLVMBuildOr(builder, lval, rval, llvmgen_temp(gctx)); break; case OPER_NOT: result = LLVMBuildNot(builder, rval, llvmgen_temp(gctx)); break; case OPER_XOR: result = LLVMBuildXor(builder, lval, rval, llvmgen_temp(gctx)); break; case OPER_EQV: result = LLVMBuildXor(builder, lval, rval, llvmgen_temp(gctx)); result = LLVMBuildNot(builder, result, llvmgen_temp(gctx)); break; default: if (op >= OPER_CMP_EQL && op <= OPER_CMP_GEQA) { result = LLVMBuildICmp(builder, llvmgen_predfromop(op, machine_addr_signed(gctx->mach)), lval, rval, llvmgen_temp(gctx)); } else { // Everything should be covered expr_signal(gctx->ectx, STC__INTCMPERR, "gen_operator_expression"); result = LLVMConstNull(inttype); } break; } return llvmgen_adjustval(gctx, result, neededtype, 0); } /* gen_operator_expression */
/* * gen_fetch * * Generates a load operation for a fetch expression. */ static LLVMValueRef gen_fetch (gencodectx_t gctx, expr_node_t *rhs, LLVMTypeRef neededtype) { LLVMBuilderRef builder = gctx->curfn->builder; llvm_accinfo_t accinfo; LLVMValueRef addr, val; LLVMTypeRef type; int shifts_required = 0; int signext; // For field references with non-zero bit position, or with // non-CTCE size, we'll have to do bit shifting to extract // the field. addr = llvmgen_addr_expression(gctx, rhs, &accinfo); if (accinfo.posval != 0 || accinfo.sizeval != 0) { type = gctx->fullwordtype; if ((accinfo.flags & LLVMGEN_M_ACC_CONSTSIZ)) { accinfo.sizeval = LLVMConstInt(gctx->fullwordtype, accinfo.size, 0); } shifts_required = 1; } else if ((accinfo.flags & LLVMGEN_M_ACC_CONSTSIZ)) { if (accinfo.size == 0) { // XXX signal invalid size type = gctx->int1type; } else { type = LLVMIntTypeInContext(gctx->llvmctx, accinfo.size); } } else { type = gctx->fullwordtype; } signext = ((accinfo.flags & LLVMGEN_M_SEG_SIGNEXT) != 0); // If we're fetching from a register, there's no load intruction // required - EXCEPT if this was a scalar BIND, where the BIND if ((accinfo.segclass == LLVM_REG && (accinfo.flags & LLVMGEN_M_SEG_DEREFED) == 0) && (accinfo.flags & LLVMGEN_M_SEG_BINDPTR) == 0) { val = llvmgen_adjustval(gctx, addr, type, signext); } else { addr = llvmgen_adjustval(gctx, addr, LLVMPointerType(type, 0), 0); val = LLVMBuildLoad(builder, addr, llvmgen_temp(gctx)); if ((accinfo.flags & LLVMGEN_M_SEG_VOLATILE) != 0) LLVMSetVolatile(val, 1); } if (shifts_required) { val = llvmgen_adjustval(gctx, val, gctx->fullwordtype, signext); if (signext) { val = LLVMBuildAShr(builder, val, accinfo.posval, llvmgen_temp(gctx)); } else { val = LLVMBuildLShr(builder, val, accinfo.posval, llvmgen_temp(gctx)); } if ((accinfo.flags & LLVMGEN_M_ACC_CONSTSIZ) != 0) { LLVMTypeRef trunctype = LLVMIntTypeInContext(gctx->llvmctx, accinfo.size); val = llvmgen_adjustval(gctx, val, trunctype, signext); } else { LLVMValueRef neg1 = LLVMConstAllOnes(gctx->fullwordtype); LLVMValueRef mask; mask = LLVMBuildShl(builder, neg1, accinfo.sizeval, llvmgen_temp(gctx)); mask = LLVMBuildNeg(builder, mask, llvmgen_temp(gctx)); val = LLVMBuildAnd(builder, val, mask, llvmgen_temp(gctx)); if (signext) { val = LLVMBuildSExt(builder, val, gctx->fullwordtype, llvmgen_temp(gctx)); } } } return llvmgen_adjustval(gctx, val, neededtype, signext); } /* gen_fetch */
LLVMValueRef gen_neg(struct node *ast) { return LLVMBuildNeg(builder, codegen(ast->one), ""); }
LLVMValueRef lp_build_negate(struct lp_build_context *bld, LLVMValueRef a) { return LLVMBuildNeg(bld->builder, a, ""); }
/* This function will take a bool and sign extend it to a specified bitwidth. It will also perform i1 to floating point conversions if necessary. All vector components that are equal to 1 will be converted to -1 in accordance with the OpenCL standard. */ struct cl2llvm_val_t *cl2llvm_bool_ext(struct cl2llvm_val_t *bool_val, struct cl2llvmTypeWrap *type) { struct cl2llvm_val_t *value; struct cl2llvmTypeWrap *switch_type; LLVMTypeRef totype; int vec_length; switch_type = cl2llvmTypeWrapCreate(cl2llvmTypeWrapGetLlvmType(type), cl2llvmTypeWrapGetSign(type)); if (LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(type)) == LLVMVectorTypeKind) cl2llvmTypeWrapSetLlvmType(switch_type, LLVMGetElementType(cl2llvmTypeWrapGetLlvmType(type))); if (LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(type)) == LLVMVectorTypeKind) { vec_length = LLVMGetVectorSize(cl2llvmTypeWrapGetLlvmType(type)); switch (LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(switch_type))) { case LLVMIntegerTypeKind: totype = cl2llvmTypeWrapGetLlvmType(type); break; case LLVMFloatTypeKind: totype = LLVMVectorType(LLVMInt32Type(), vec_length); break; case LLVMDoubleTypeKind: totype = LLVMVectorType(LLVMInt64Type(), vec_length); break; case LLVMHalfTypeKind: totype = LLVMVectorType(LLVMInt16Type(), vec_length); break; default: cl2llvm_yyerror("unreachable code reached"); break; } } else totype = LLVMInt32Type(); value = cl2llvm_val_create(); snprintf(temp_var_name, sizeof temp_var_name, "tmp_%d", temp_var_count++); /* Build sign extension */ value->val = LLVMBuildSExt(cl2llvm_builder, bool_val->val, totype, temp_var_name); cl2llvmTypeWrapSetLlvmType(value->type, totype); cl2llvmTypeWrapSetSign(value->type, 1); /* if value is a vector, change 1's to -1's */ if (LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(type)) == LLVMVectorTypeKind) { snprintf(temp_var_name, sizeof temp_var_name, "tmp_%d", temp_var_count++); value->val = LLVMBuildNeg(cl2llvm_builder, value->val, temp_var_name); } cl2llvmTypeWrapFree(switch_type); return value; }