static void emit_ssg(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; LLVMValueRef cmp, val; if (emit_data->inst->Instruction.Opcode == TGSI_OPCODE_I64SSG) { cmp = LLVMBuildICmp(builder, LLVMIntSGT, emit_data->args[0], bld_base->int64_bld.zero, ""); val = LLVMBuildSelect(builder, cmp, bld_base->int64_bld.one, emit_data->args[0], ""); cmp = LLVMBuildICmp(builder, LLVMIntSGE, val, bld_base->int64_bld.zero, ""); val = LLVMBuildSelect(builder, cmp, val, LLVMConstInt(bld_base->int64_bld.elem_type, -1, true), ""); } else if (emit_data->inst->Instruction.Opcode == TGSI_OPCODE_ISSG) { cmp = LLVMBuildICmp(builder, LLVMIntSGT, emit_data->args[0], bld_base->int_bld.zero, ""); val = LLVMBuildSelect(builder, cmp, bld_base->int_bld.one, emit_data->args[0], ""); cmp = LLVMBuildICmp(builder, LLVMIntSGE, val, bld_base->int_bld.zero, ""); val = LLVMBuildSelect(builder, cmp, val, LLVMConstInt(bld_base->int_bld.elem_type, -1, true), ""); } else { // float SSG cmp = LLVMBuildFCmp(builder, LLVMRealOGT, emit_data->args[0], bld_base->base.zero, ""); val = LLVMBuildSelect(builder, cmp, bld_base->base.one, emit_data->args[0], ""); cmp = LLVMBuildFCmp(builder, LLVMRealOGE, val, bld_base->base.zero, ""); val = LLVMBuildSelect(builder, cmp, val, LLVMConstReal(bld_base->base.elem_type, -1), ""); } emit_data->output[emit_data->chan] = val; }
static void kill_if_fetch_args(struct lp_build_tgsi_context *bld_base, struct lp_build_emit_data *emit_data) { const struct tgsi_full_instruction *inst = emit_data->inst; struct gallivm_state *gallivm = bld_base->base.gallivm; LLVMBuilderRef builder = gallivm->builder; unsigned i; LLVMValueRef conds[TGSI_NUM_CHANNELS]; for (i = 0; i < TGSI_NUM_CHANNELS; i++) { LLVMValueRef value = lp_build_emit_fetch(bld_base, inst, 0, i); conds[i] = LLVMBuildFCmp(builder, LLVMRealOLT, value, bld_base->base.zero, ""); } /* Or the conditions together */ for (i = TGSI_NUM_CHANNELS - 1; i > 0; i--) { conds[i - 1] = LLVMBuildOr(builder, conds[i], conds[i - 1], ""); } emit_data->dst_type = LLVMVoidTypeInContext(gallivm->context); emit_data->arg_count = 1; emit_data->args[0] = LLVMBuildSelect(builder, conds[0], lp_build_const_float(gallivm, -1.0f), bld_base->base.zero, ""); }
static void emit_set_cond(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; LLVMRealPredicate pred; LLVMValueRef cond; /* Use ordered for everything but NE (which is usual for * float comparisons) */ switch (emit_data->inst->Instruction.Opcode) { case TGSI_OPCODE_SGE: pred = LLVMRealOGE; break; case TGSI_OPCODE_SEQ: pred = LLVMRealOEQ; break; case TGSI_OPCODE_SLE: pred = LLVMRealOLE; break; case TGSI_OPCODE_SLT: pred = LLVMRealOLT; break; case TGSI_OPCODE_SNE: pred = LLVMRealUNE; break; case TGSI_OPCODE_SGT: pred = LLVMRealOGT; break; default: assert(!"unknown instruction"); pred = 0; break; } cond = LLVMBuildFCmp(builder, pred, emit_data->args[0], emit_data->args[1], ""); emit_data->output[emit_data->chan] = LLVMBuildSelect(builder, cond, bld_base->base.one, bld_base->base.zero, ""); }
static void emit_dcmp(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; LLVMContextRef context = bld_base->base.gallivm->context; LLVMRealPredicate pred; /* Use ordered for everything but NE (which is usual for * float comparisons) */ switch (emit_data->inst->Instruction.Opcode) { case TGSI_OPCODE_DSEQ: pred = LLVMRealOEQ; break; case TGSI_OPCODE_DSGE: pred = LLVMRealOGE; break; case TGSI_OPCODE_DSLT: pred = LLVMRealOLT; break; case TGSI_OPCODE_DSNE: pred = LLVMRealUNE; break; default: assert(!"unknown instruction"); pred = 0; break; } LLVMValueRef v = LLVMBuildFCmp(builder, pred, emit_data->args[0], emit_data->args[1],""); v = LLVMBuildSExtOrBitCast(builder, v, LLVMInt32TypeInContext(context), ""); emit_data->output[emit_data->chan] = v; }
static LLVMValueRef llvm_face_select_helper( struct radeon_llvm_context * ctx, const char *intrinsic, unsigned face_register, unsigned frontcolor_register, unsigned backcolor_regiser) { LLVMValueRef backcolor = llvm_load_input_helper( ctx, intrinsic, backcolor_regiser); LLVMValueRef front_color = llvm_load_input_helper( ctx, intrinsic, frontcolor_register); LLVMValueRef face = llvm_load_input_helper( ctx, "llvm.R600.load.input", face_register); LLVMValueRef is_face_positive = LLVMBuildFCmp( ctx->soa.bld_base.base.gallivm->builder, LLVMRealUGT, face, lp_build_const_float(ctx->soa.bld_base.base.gallivm, 0.0f), ""); return LLVMBuildSelect( ctx->soa.bld_base.base.gallivm->builder, is_face_positive, front_color, backcolor, ""); }
static LLVMValueRef make_cmp_value(compile_t* c, bool sign, LLVMValueRef l_value, LLVMValueRef r_value, LLVMRealPredicate cmp_f, LLVMIntPredicate cmp_si, LLVMIntPredicate cmp_ui) { if((l_value == NULL) || (r_value == NULL)) return NULL; if(LLVMIsConstant(l_value) && LLVMIsConstant(r_value)) { if(is_fp(l_value)) return LLVMConstFCmp(cmp_f, l_value, r_value); if(sign) return LLVMConstICmp(cmp_si, l_value, r_value); return LLVMConstICmp(cmp_ui, l_value, r_value); } if(is_fp(l_value)) return LLVMBuildFCmp(c->builder, cmp_f, l_value, r_value, ""); if(sign) return LLVMBuildICmp(c->builder, cmp_si, l_value, r_value, ""); return LLVMBuildICmp(c->builder, cmp_ui, l_value, r_value, ""); }
/** * Build a manual selection sequence for cube face sc/tc coordinates and * major axis vector (multiplied by 2 for consistency) for the given * vec3 \p coords, for the face implied by \p selcoords. * * For the major axis, we always adjust the sign to be in the direction of * selcoords.ma; i.e., a positive out_ma means that coords is pointed towards * the selcoords major axis. */ static void build_cube_select(LLVMBuilderRef builder, const struct cube_selection_coords *selcoords, const LLVMValueRef *coords, LLVMValueRef *out_st, LLVMValueRef *out_ma) { LLVMTypeRef f32 = LLVMTypeOf(coords[0]); LLVMValueRef is_ma_positive; LLVMValueRef sgn_ma; LLVMValueRef is_ma_z, is_not_ma_z; LLVMValueRef is_ma_y; LLVMValueRef is_ma_x; LLVMValueRef sgn; LLVMValueRef tmp; is_ma_positive = LLVMBuildFCmp(builder, LLVMRealUGE, selcoords->ma, LLVMConstReal(f32, 0.0), ""); sgn_ma = LLVMBuildSelect(builder, is_ma_positive, LLVMConstReal(f32, 1.0), LLVMConstReal(f32, -1.0), ""); is_ma_z = LLVMBuildFCmp(builder, LLVMRealUGE, selcoords->id, LLVMConstReal(f32, 4.0), ""); is_not_ma_z = LLVMBuildNot(builder, is_ma_z, ""); is_ma_y = LLVMBuildAnd(builder, is_not_ma_z, LLVMBuildFCmp(builder, LLVMRealUGE, selcoords->id, LLVMConstReal(f32, 2.0), ""), ""); is_ma_x = LLVMBuildAnd(builder, is_not_ma_z, LLVMBuildNot(builder, is_ma_y, ""), ""); /* Select sc */ tmp = LLVMBuildSelect(builder, is_ma_z, coords[2], coords[0], ""); sgn = LLVMBuildSelect(builder, is_ma_y, LLVMConstReal(f32, 1.0), LLVMBuildSelect(builder, is_ma_x, sgn_ma, LLVMBuildFNeg(builder, sgn_ma, ""), ""), ""); out_st[0] = LLVMBuildFMul(builder, tmp, sgn, ""); /* Select tc */ tmp = LLVMBuildSelect(builder, is_ma_y, coords[2], coords[1], ""); sgn = LLVMBuildSelect(builder, is_ma_y, LLVMBuildFNeg(builder, sgn_ma, ""), LLVMConstReal(f32, -1.0), ""); out_st[1] = LLVMBuildFMul(builder, tmp, sgn, ""); /* Select ma */ tmp = LLVMBuildSelect(builder, is_ma_z, coords[2], LLVMBuildSelect(builder, is_ma_y, coords[1], coords[0], ""), ""); sgn = LLVMBuildSelect(builder, is_ma_positive, LLVMConstReal(f32, 2.0), LLVMConstReal(f32, -2.0), ""); *out_ma = LLVMBuildFMul(builder, tmp, sgn, ""); }
/* Perform front/back face culling and return true if the primitive is accepted. */ static LLVMValueRef ac_cull_face(struct ac_llvm_context *ctx, LLVMValueRef pos[3][4], struct ac_position_w_info *w, bool cull_front, bool cull_back, bool cull_zero_area) { LLVMBuilderRef builder = ctx->builder; if (cull_front && cull_back) return ctx->i1false; if (!cull_front && !cull_back && !cull_zero_area) return ctx->i1true; /* Front/back face culling. Also if the determinant == 0, the triangle * area is 0. */ LLVMValueRef det_t0 = LLVMBuildFSub(builder, pos[2][0], pos[0][0], ""); LLVMValueRef det_t1 = LLVMBuildFSub(builder, pos[1][1], pos[0][1], ""); LLVMValueRef det_t2 = LLVMBuildFSub(builder, pos[0][0], pos[1][0], ""); LLVMValueRef det_t3 = LLVMBuildFSub(builder, pos[0][1], pos[2][1], ""); LLVMValueRef det_p0 = LLVMBuildFMul(builder, det_t0, det_t1, ""); LLVMValueRef det_p1 = LLVMBuildFMul(builder, det_t2, det_t3, ""); LLVMValueRef det = LLVMBuildFSub(builder, det_p0, det_p1, ""); /* Negative W negates the determinant. */ det = LLVMBuildSelect(builder, w->w_reflection, LLVMBuildFNeg(builder, det, ""), det, ""); LLVMValueRef accepted = NULL; if (cull_front) { LLVMRealPredicate cond = cull_zero_area ? LLVMRealOGT : LLVMRealOGE; accepted = LLVMBuildFCmp(builder, cond, det, ctx->f32_0, ""); } else if (cull_back) { LLVMRealPredicate cond = cull_zero_area ? LLVMRealOLT : LLVMRealOLE; accepted = LLVMBuildFCmp(builder, cond, det, ctx->f32_0, ""); } else if (cull_zero_area) { accepted = LLVMBuildFCmp(builder, LLVMRealONE, det, ctx->f32_0, ""); } return accepted; }
SCM llvm_build_float_cmp(SCM scm_function, SCM scm_predicate, SCM scm_value_a, SCM scm_value_b) { SCM retval; struct llvm_function_t *function = get_llvm_function(scm_function); struct llvm_value_t *value_a = get_llvm_value(scm_value_a); struct llvm_value_t *value_b = get_llvm_value(scm_value_b); struct llvm_value_t *result = (struct llvm_value_t *)scm_gc_calloc(sizeof(struct llvm_value_t), "llvm value"); SCM_NEWSMOB(retval, llvm_value_tag, result); result->value = LLVMBuildFCmp(function->builder, scm_to_int(scm_predicate), value_a->value, value_b->value, "x"); return retval; }
static LLVMValueRef llvm_face_select_helper( struct radeon_llvm_context * ctx, LLVMValueRef face, LLVMValueRef front_color, LLVMValueRef back_color) { const struct lp_build_context * bb = &ctx->soa.bld_base.base; LLVMValueRef is_front = LLVMBuildFCmp( bb->gallivm->builder, LLVMRealUGT, face, lp_build_const_float(bb->gallivm, 0.0f), ""); return LLVMBuildSelect(bb->gallivm->builder, is_front, front_color, back_color, ""); }
/** * Do the one or two-sided stencil test comparison. * \sa lp_build_stencil_test_single * \param face an integer indicating front (+) or back (-) facing polygon. * If NULL, assume front-facing. */ static LLVMValueRef lp_build_stencil_test(struct lp_build_context *bld, const struct pipe_stencil_state stencil[2], LLVMValueRef stencilRefs[2], LLVMValueRef stencilVals, LLVMValueRef face) { LLVMValueRef res; assert(stencil[0].enabled); if (stencil[1].enabled && face) { /* do two-sided test */ struct lp_build_flow_context *flow_ctx; struct lp_build_if_state if_ctx; LLVMValueRef front_facing; LLVMValueRef zero = LLVMConstReal(LLVMFloatType(), 0.0); LLVMValueRef result = bld->undef; flow_ctx = lp_build_flow_create(bld->builder); lp_build_flow_scope_begin(flow_ctx); lp_build_flow_scope_declare(flow_ctx, &result); /* front_facing = face > 0.0 */ front_facing = LLVMBuildFCmp(bld->builder, LLVMRealUGT, face, zero, ""); lp_build_if(&if_ctx, flow_ctx, bld->builder, front_facing); { result = lp_build_stencil_test_single(bld, &stencil[0], stencilRefs[0], stencilVals); } lp_build_else(&if_ctx); { result = lp_build_stencil_test_single(bld, &stencil[1], stencilRefs[1], stencilVals); } lp_build_endif(&if_ctx); lp_build_flow_scope_end(flow_ctx); lp_build_flow_destroy(flow_ctx); res = result; } else { /* do single-side test */ res = lp_build_stencil_test_single(bld, &stencil[0], stencilRefs[0], stencilVals); } return res; }
static void emit_cmp(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; LLVMValueRef cond, *args = emit_data->args; cond = LLVMBuildFCmp(builder, LLVMRealOLT, args[0], bld_base->base.zero, ""); emit_data->output[emit_data->chan] = LLVMBuildSelect(builder, cond, args[1], args[2], ""); }
static void emit_cndlt( 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; LLVMValueRef float_zero = lp_build_const_float( bld_base->base.gallivm, 0.0f); LLVMValueRef cmp = LLVMBuildFCmp( builder, LLVMRealULT, emit_data->args[0], float_zero, ""); emit_data->output[emit_data->chan] = LLVMBuildSelect(builder, cmp, emit_data->args[1], emit_data->args[2], ""); }
/** Helper used by lp_build_cube_lookup() * Return (major_coord >= 0) ? pos_face : neg_face; */ static LLVMValueRef lp_build_cube_face(struct lp_build_sample_context *bld, LLVMValueRef major_coord, unsigned pos_face, unsigned neg_face) { struct gallivm_state *gallivm = bld->gallivm; LLVMBuilderRef builder = gallivm->builder; LLVMValueRef cmp = LLVMBuildFCmp(builder, LLVMRealUGE, major_coord, bld->float_bld.zero, ""); LLVMValueRef pos = lp_build_const_int32(gallivm, pos_face); LLVMValueRef neg = lp_build_const_int32(gallivm, neg_face); LLVMValueRef res = LLVMBuildSelect(builder, cmp, pos, neg, ""); return res; }
static LLVMValueRef translateFloatBinOp(NodeKind Op, LLVMValueRef ValueE1, LLVMValueRef ValueE2) { switch (Op) { case SumOp: return LLVMBuildFAdd(Builder, ValueE1, ValueE2, ""); case SubOp: return LLVMBuildFSub(Builder, ValueE1, ValueE2, ""); case MultOp: return LLVMBuildFMul(Builder, ValueE1, ValueE2, ""); case DivOp: return LLVMBuildFDiv(Builder, ValueE1, ValueE2, ""); case LtOp: return LLVMBuildFCmp(Builder, LLVMRealOLT, ValueE1, ValueE2, ""); case LeOp: return LLVMBuildFCmp(Builder, LLVMRealOLE, ValueE1, ValueE2, ""); case GtOp: return LLVMBuildFCmp(Builder, LLVMRealOGT, ValueE1, ValueE2, ""); case GeOp: return LLVMBuildFCmp(Builder, LLVMRealOGE, ValueE1, ValueE2, ""); case EqOp: return LLVMBuildFCmp(Builder, LLVMRealOEQ, ValueE1, ValueE2, ""); case DiffOp: return LLVMBuildFCmp(Builder, LLVMRealONE, ValueE1, ValueE2, ""); default: return NULL; } }
static void ac_analyze_position_w(struct ac_llvm_context *ctx, LLVMValueRef pos[3][4], struct ac_position_w_info *w) { LLVMBuilderRef builder = ctx->builder; LLVMValueRef all_w_negative = ctx->i1true; w->w_reflection = ctx->i1false; w->any_w_negative = ctx->i1false; for (unsigned i = 0; i < 3; i++) { LLVMValueRef neg_w; neg_w = LLVMBuildFCmp(builder, LLVMRealOLT, pos[i][3], ctx->f32_0, ""); /* If neg_w is true, negate w_reflection. */ w->w_reflection = LLVMBuildXor(builder, w->w_reflection, neg_w, ""); w->any_w_negative = LLVMBuildOr(builder, w->any_w_negative, neg_w, ""); all_w_negative = LLVMBuildAnd(builder, all_w_negative, neg_w, ""); } w->all_w_positive = LLVMBuildNot(builder, w->any_w_negative, ""); w->w_accepted = LLVMBuildNot(builder, all_w_negative, ""); }
/* This function returns an i1 1 if the value is not equal to 0 and an i1 0 if the value is equal to 0. */ struct cl2llvm_val_t *cl2llvm_to_bool_ne_0(struct cl2llvm_val_t *value) { LLVMValueRef const_zero; LLVMValueRef zero_vec[16]; LLVMTypeRef switch_type; int i; int veclength; struct cl2llvm_val_t *bool_val = cl2llvm_val_create_w_init(value->val, cl2llvmTypeWrapGetSign(value->type)); /* if value is i1 no conversion necessary */ if (LLVMTypeOf(value->val) == LLVMInt1Type()) return bool_val; /* If value is a vector create a vector of constant zeros, else create a scalar 0. */ if (LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(value->type)) == LLVMVectorTypeKind) { switch_type = LLVMGetElementType(cl2llvmTypeWrapGetLlvmType(value->type)); veclength = LLVMGetVectorSize(cl2llvmTypeWrapGetLlvmType(value->type)); switch (LLVMGetTypeKind(LLVMGetElementType(cl2llvmTypeWrapGetLlvmType(value->type)))) { case LLVMIntegerTypeKind: /* Create zero vector */ for (i = 0; i < veclength; i++) zero_vec[i] = LLVMConstInt(switch_type, 0, 0); break; case LLVMFloatTypeKind: case LLVMDoubleTypeKind: case LLVMHalfTypeKind: /* Create zero vector */ for (i = 0; i < veclength; i++) zero_vec[i] = LLVMConstReal(switch_type, 0); break; default: cl2llvm_yyerror("unreachable code reached"); } const_zero = LLVMConstVector(zero_vec, veclength); } else if (LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(value->type)) == LLVMIntegerTypeKind) { const_zero = LLVMConstInt(cl2llvmTypeWrapGetLlvmType(value->type), 0, 0); switch_type = cl2llvmTypeWrapGetLlvmType(value->type); } else if (LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(value->type)) == LLVMFloatTypeKind || LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(value->type)) == LLVMDoubleTypeKind || LLVMGetTypeKind(cl2llvmTypeWrapGetLlvmType(value->type)) == LLVMHalfTypeKind) { const_zero = LLVMConstReal(cl2llvmTypeWrapGetLlvmType(value->type), 0); switch_type = cl2llvmTypeWrapGetLlvmType(value->type); } /* Create comparison */ snprintf(temp_var_name, sizeof temp_var_name, "tmp_%d", temp_var_count++); switch (LLVMGetTypeKind(switch_type)) { case LLVMFloatTypeKind: case LLVMDoubleTypeKind: case LLVMHalfTypeKind: bool_val->val = LLVMBuildFCmp(cl2llvm_builder, LLVMRealONE, value->val, const_zero, temp_var_name); break; case LLVMIntegerTypeKind: bool_val->val = LLVMBuildICmp(cl2llvm_builder, LLVMIntNE, value->val, const_zero, temp_var_name); break; default: cl2llvm_yyerror("unreachable code reached"); break; } cl2llvmTypeWrapSetLlvmType(bool_val->type, LLVMInt1Type()); cl2llvmTypeWrapSetSign(bool_val->type, 0); return bool_val; }
static void declare_input_fs( struct si_shader_context * si_shader_ctx, unsigned input_index, const struct tgsi_full_declaration *decl) { struct si_shader *shader = &si_shader_ctx->shader->shader; struct lp_build_context * base = &si_shader_ctx->radeon_bld.soa.bld_base.base; struct gallivm_state * gallivm = base->gallivm; LLVMTypeRef input_type = LLVMFloatTypeInContext(gallivm->context); LLVMValueRef main_fn = si_shader_ctx->radeon_bld.main_fn; LLVMValueRef interp_param; const char * intr_name; /* This value is: * [15:0] NewPrimMask (Bit mask for each quad. It is set it the * quad begins a new primitive. Bit 0 always needs * to be unset) * [32:16] ParamOffset * */ LLVMValueRef params = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, SI_PARAM_PRIM_MASK); LLVMValueRef attr_number; unsigned chan; if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) { for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); si_shader_ctx->radeon_bld.inputs[soa_index] = LLVMGetParam(main_fn, SI_PARAM_POS_X_FLOAT + chan); if (chan == 3) /* RCP for fragcoord.w */ si_shader_ctx->radeon_bld.inputs[soa_index] = LLVMBuildFDiv(gallivm->builder, lp_build_const_float(gallivm, 1.0f), si_shader_ctx->radeon_bld.inputs[soa_index], ""); } return; } if (decl->Semantic.Name == TGSI_SEMANTIC_FACE) { LLVMValueRef face, is_face_positive; face = LLVMGetParam(main_fn, SI_PARAM_FRONT_FACE); is_face_positive = LLVMBuildFCmp(gallivm->builder, LLVMRealUGT, face, lp_build_const_float(gallivm, 0.0f), ""); si_shader_ctx->radeon_bld.inputs[radeon_llvm_reg_index_soa(input_index, 0)] = LLVMBuildSelect(gallivm->builder, is_face_positive, lp_build_const_float(gallivm, 1.0f), lp_build_const_float(gallivm, 0.0f), ""); si_shader_ctx->radeon_bld.inputs[radeon_llvm_reg_index_soa(input_index, 1)] = si_shader_ctx->radeon_bld.inputs[radeon_llvm_reg_index_soa(input_index, 2)] = lp_build_const_float(gallivm, 0.0f); si_shader_ctx->radeon_bld.inputs[radeon_llvm_reg_index_soa(input_index, 3)] = lp_build_const_float(gallivm, 1.0f); return; } shader->input[input_index].param_offset = shader->ninterp++; attr_number = lp_build_const_int32(gallivm, shader->input[input_index].param_offset); /* XXX: Handle all possible interpolation modes */ switch (decl->Interp.Interpolate) { case TGSI_INTERPOLATE_COLOR: if (si_shader_ctx->shader->key.ps.flatshade) { interp_param = 0; } else { if (decl->Interp.Centroid) interp_param = LLVMGetParam(main_fn, SI_PARAM_PERSP_CENTROID); else interp_param = LLVMGetParam(main_fn, SI_PARAM_PERSP_CENTER); } break; case TGSI_INTERPOLATE_CONSTANT: interp_param = 0; break; case TGSI_INTERPOLATE_LINEAR: if (decl->Interp.Centroid) interp_param = LLVMGetParam(main_fn, SI_PARAM_LINEAR_CENTROID); else interp_param = LLVMGetParam(main_fn, SI_PARAM_LINEAR_CENTER); break; case TGSI_INTERPOLATE_PERSPECTIVE: if (decl->Interp.Centroid) interp_param = LLVMGetParam(main_fn, SI_PARAM_PERSP_CENTROID); else interp_param = LLVMGetParam(main_fn, SI_PARAM_PERSP_CENTER); break; default: fprintf(stderr, "Warning: Unhandled interpolation mode.\n"); return; } intr_name = interp_param ? "llvm.SI.fs.interp" : "llvm.SI.fs.constant"; /* XXX: Could there be more than TGSI_NUM_CHANNELS (4) ? */ if (decl->Semantic.Name == TGSI_SEMANTIC_COLOR && si_shader_ctx->shader->key.ps.color_two_side) { LLVMValueRef args[4]; LLVMValueRef face, is_face_positive; LLVMValueRef back_attr_number = lp_build_const_int32(gallivm, shader->input[input_index].param_offset + 1); face = LLVMGetParam(main_fn, SI_PARAM_FRONT_FACE); is_face_positive = LLVMBuildFCmp(gallivm->builder, LLVMRealUGT, face, lp_build_const_float(gallivm, 0.0f), ""); args[2] = params; args[3] = interp_param; for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { LLVMValueRef llvm_chan = lp_build_const_int32(gallivm, chan); unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); LLVMValueRef front, back; args[0] = llvm_chan; args[1] = attr_number; front = build_intrinsic(base->gallivm->builder, intr_name, input_type, args, args[3] ? 4 : 3, LLVMReadNoneAttribute | LLVMNoUnwindAttribute); args[1] = back_attr_number; back = build_intrinsic(base->gallivm->builder, intr_name, input_type, args, args[3] ? 4 : 3, LLVMReadNoneAttribute | LLVMNoUnwindAttribute); si_shader_ctx->radeon_bld.inputs[soa_index] = LLVMBuildSelect(gallivm->builder, is_face_positive, front, back, ""); } shader->ninterp++; } else { for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { LLVMValueRef args[4]; LLVMValueRef llvm_chan = lp_build_const_int32(gallivm, chan); unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); args[0] = llvm_chan; args[1] = attr_number; args[2] = params; args[3] = interp_param; si_shader_ctx->radeon_bld.inputs[soa_index] = build_intrinsic(base->gallivm->builder, intr_name, input_type, args, args[3] ? 4 : 3, LLVMReadNoneAttribute | LLVMNoUnwindAttribute); } } }
/** * Generate code to do cube face selection and compute per-face texcoords. */ void lp_build_cube_lookup(struct lp_build_sample_context *bld, LLVMValueRef s, LLVMValueRef t, LLVMValueRef r, LLVMValueRef *face, LLVMValueRef *face_s, LLVMValueRef *face_t) { struct lp_build_context *float_bld = &bld->float_bld; struct lp_build_context *coord_bld = &bld->coord_bld; LLVMBuilderRef builder = bld->gallivm->builder; LLVMValueRef rx, ry, rz; LLVMValueRef arx, ary, arz; LLVMValueRef c25 = lp_build_const_float(bld->gallivm, 0.25); LLVMValueRef arx_ge_ary, arx_ge_arz; LLVMValueRef ary_ge_arx, ary_ge_arz; LLVMValueRef arx_ge_ary_arz, ary_ge_arx_arz; assert(bld->coord_bld.type.length == 4); /* * Use the average of the four pixel's texcoords to choose the face. */ rx = lp_build_mul(float_bld, c25, lp_build_sum_vector(&bld->coord_bld, s)); ry = lp_build_mul(float_bld, c25, lp_build_sum_vector(&bld->coord_bld, t)); rz = lp_build_mul(float_bld, c25, lp_build_sum_vector(&bld->coord_bld, r)); arx = lp_build_abs(float_bld, rx); ary = lp_build_abs(float_bld, ry); arz = lp_build_abs(float_bld, rz); /* * Compare sign/magnitude of rx,ry,rz to determine face */ arx_ge_ary = LLVMBuildFCmp(builder, LLVMRealUGE, arx, ary, ""); arx_ge_arz = LLVMBuildFCmp(builder, LLVMRealUGE, arx, arz, ""); ary_ge_arx = LLVMBuildFCmp(builder, LLVMRealUGE, ary, arx, ""); ary_ge_arz = LLVMBuildFCmp(builder, LLVMRealUGE, ary, arz, ""); arx_ge_ary_arz = LLVMBuildAnd(builder, arx_ge_ary, arx_ge_arz, ""); ary_ge_arx_arz = LLVMBuildAnd(builder, ary_ge_arx, ary_ge_arz, ""); { struct lp_build_if_state if_ctx; LLVMValueRef face_s_var; LLVMValueRef face_t_var; LLVMValueRef face_var; face_s_var = lp_build_alloca(bld->gallivm, bld->coord_bld.vec_type, "face_s_var"); face_t_var = lp_build_alloca(bld->gallivm, bld->coord_bld.vec_type, "face_t_var"); face_var = lp_build_alloca(bld->gallivm, bld->int_bld.vec_type, "face_var"); lp_build_if(&if_ctx, bld->gallivm, arx_ge_ary_arz); { /* +/- X face */ LLVMValueRef sign = lp_build_sgn(float_bld, rx); LLVMValueRef ima = lp_build_cube_ima(coord_bld, s); *face_s = lp_build_cube_coord(coord_bld, sign, +1, r, ima); *face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima); *face = lp_build_cube_face(bld, rx, PIPE_TEX_FACE_POS_X, PIPE_TEX_FACE_NEG_X); LLVMBuildStore(builder, *face_s, face_s_var); LLVMBuildStore(builder, *face_t, face_t_var); LLVMBuildStore(builder, *face, face_var); } lp_build_else(&if_ctx); { struct lp_build_if_state if_ctx2; lp_build_if(&if_ctx2, bld->gallivm, ary_ge_arx_arz); { /* +/- Y face */ LLVMValueRef sign = lp_build_sgn(float_bld, ry); LLVMValueRef ima = lp_build_cube_ima(coord_bld, t); *face_s = lp_build_cube_coord(coord_bld, NULL, -1, s, ima); *face_t = lp_build_cube_coord(coord_bld, sign, -1, r, ima); *face = lp_build_cube_face(bld, ry, PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y); LLVMBuildStore(builder, *face_s, face_s_var); LLVMBuildStore(builder, *face_t, face_t_var); LLVMBuildStore(builder, *face, face_var); } lp_build_else(&if_ctx2); { /* +/- Z face */ LLVMValueRef sign = lp_build_sgn(float_bld, rz); LLVMValueRef ima = lp_build_cube_ima(coord_bld, r); *face_s = lp_build_cube_coord(coord_bld, sign, -1, s, ima); *face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima); *face = lp_build_cube_face(bld, rz, PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z); LLVMBuildStore(builder, *face_s, face_s_var); LLVMBuildStore(builder, *face_t, face_t_var); LLVMBuildStore(builder, *face, face_var); } lp_build_endif(&if_ctx2); } lp_build_endif(&if_ctx); *face_s = LLVMBuildLoad(builder, face_s_var, "face_s"); *face_t = LLVMBuildLoad(builder, face_t_var, "face_t"); *face = LLVMBuildLoad(builder, face_var, "face"); } }
LLVMValueRef bllvm_compile_comparison(const struct rir_expression *expr, struct llvm_traversal_ctx *ctx) { LLVMValueRef left = bllvm_value_from_rir_value_or_die(expr->binaryop.a, ctx); LLVMValueRef right = bllvm_value_from_rir_value_or_die(expr->binaryop.b, ctx); struct rir_type *typea = expr->binaryop.a->type; struct rir_type *typeb = expr->binaryop.b->type; RF_ASSERT(rir_type_is_elementary(typea), "Backend comparisons should only happen with elementary types"); RF_ASSERT(rir_type_is_elementary(typeb), "Backend comparisons should only happen with elementary types"); RF_ASSERT(typea->etype == typeb->etype, "Comparison should only happen with same type"); // TODO: Maybe take into account signedness? if (elementary_type_is_float(typea->etype)) { LLVMRealPredicate llvm_real_compare_type; switch(expr->type) { case RIR_EXPRESSION_CMP_EQ: llvm_real_compare_type = LLVMRealOEQ; break; case RIR_EXPRESSION_CMP_NE: llvm_real_compare_type = LLVMRealONE; break; case RIR_EXPRESSION_CMP_GE: llvm_real_compare_type = LLVMRealOGE; break; case RIR_EXPRESSION_CMP_GT: llvm_real_compare_type = LLVMRealOGT; break; case RIR_EXPRESSION_CMP_LE: llvm_real_compare_type = LLVMRealOLE; break; case RIR_EXPRESSION_CMP_LT: llvm_real_compare_type = LLVMRealOLT; break; default: RF_CRITICAL_FAIL("Illegal operand types at comparison code generation"); return NULL; break; } return LLVMBuildFCmp(ctx->builder, llvm_real_compare_type, left, right, ""); } LLVMIntPredicate llvm_int_compare_type; switch(expr->type) { case RIR_EXPRESSION_CMP_EQ: llvm_int_compare_type = LLVMIntEQ; break; case RIR_EXPRESSION_CMP_NE: llvm_int_compare_type = LLVMIntNE; break; case RIR_EXPRESSION_CMP_GE: llvm_int_compare_type = LLVMIntUGE; break; case RIR_EXPRESSION_CMP_GT: llvm_int_compare_type = LLVMIntUGT; break; case RIR_EXPRESSION_CMP_LE: llvm_int_compare_type = LLVMIntULE; break; case RIR_EXPRESSION_CMP_LT: llvm_int_compare_type = LLVMIntULT; break; default: RF_CRITICAL_FAIL("Illegal operand types at comparison code generation"); return NULL; break; } return LLVMBuildICmp(ctx->builder, llvm_int_compare_type, left, right, ""); }
static LLVMValueRef gen_is_value(compile_t* c, ast_t* left_type, ast_t* right_type, LLVMValueRef l_value, LLVMValueRef r_value) { LLVMTypeRef l_type = LLVMTypeOf(l_value); LLVMTypeRef r_type = LLVMTypeOf(r_value); switch(LLVMGetTypeKind(l_type)) { case LLVMIntegerTypeKind: { // If it's the same type, compare. if(l_type == r_type) return LLVMBuildICmp(c->builder, LLVMIntEQ, l_value, r_value, ""); // If left_type is a subtype of right_type, check if r_value is a boxed // numeric primitive. if(is_subtype(left_type, right_type, NULL, c->opt)) return raw_is_box(c, left_type, l_value, r_value); // It can't have the same identity. return LLVMConstInt(c->i1, 0, false); } case LLVMFloatTypeKind: case LLVMDoubleTypeKind: { // If it's the same type, just compare. if(l_type == r_type) return LLVMBuildFCmp(c->builder, LLVMRealOEQ, l_value, r_value, ""); // If left_type is a subtype of right_type, check if r_value is a boxed // numeric primitive. if(is_subtype(left_type, right_type, NULL, c->opt)) return raw_is_box(c, left_type,l_value, r_value); // It can't have the same identity. return LLVMConstInt(c->i1, 0, false); } case LLVMStructTypeKind: { // Pairwise comparison. if(LLVMGetTypeKind(r_type) == LLVMStructTypeKind) return tuple_is(c, left_type, right_type, l_value, r_value); // If left_type is a subtype of right_type, check if r_value is a boxed // tuple. if(is_subtype(left_type, right_type, NULL, c->opt)) return raw_is_box(c, left_type, l_value, r_value); // It can't have the same identity. return LLVMConstInt(c->i1, 0, false); } case LLVMPointerTypeKind: { if(LLVMGetTypeKind(r_type) != LLVMPointerTypeKind) return gen_is_value(c, right_type, left_type, r_value, l_value); l_value = LLVMBuildBitCast(c->builder, l_value, c->object_ptr, ""); r_value = LLVMBuildBitCast(c->builder, r_value, c->object_ptr, ""); if(!is_known(left_type) && !is_known(right_type)) { int possible_boxes = boxed_subtypes_overlap(c->reach, left_type, right_type); if((possible_boxes & BOXED_SUBTYPES_BOXED) != 0) return box_is_box(c, left_type, l_value, r_value, possible_boxes); } // If the types can be the same, check the address. if(is_subtype(left_type, right_type, NULL, c->opt) || is_subtype(right_type, left_type, NULL, c->opt)) return LLVMBuildICmp(c->builder, LLVMIntEQ, l_value, r_value, ""); // It can't have the same identity. return LLVMConstInt(c->i1, 0, false); } default: {} } pony_assert(0); return NULL; }
/* Perform view culling and small primitive elimination and return true * if the primitive is accepted and initially_accepted == true. */ static LLVMValueRef cull_bbox(struct ac_llvm_context *ctx, LLVMValueRef pos[3][4], LLVMValueRef initially_accepted, struct ac_position_w_info *w, LLVMValueRef vp_scale[2], LLVMValueRef vp_translate[2], LLVMValueRef small_prim_precision, bool cull_view_xy, bool cull_view_near_z, bool cull_view_far_z, bool cull_small_prims, bool use_halfz_clip_space) { LLVMBuilderRef builder = ctx->builder; if (!cull_view_xy && !cull_view_near_z && !cull_view_far_z && !cull_small_prims) return ctx->i1true; /* Skip the culling if the primitive has already been rejected or * if any W is negative. The bounding box culling doesn't work when * W is negative. */ LLVMValueRef cond = LLVMBuildAnd(builder, initially_accepted, w->all_w_positive, ""); LLVMValueRef accepted_var = ac_build_alloca_undef(ctx, ctx->i1, ""); LLVMBuildStore(builder, initially_accepted, accepted_var); ac_build_ifcc(ctx, cond, 10000000 /* does this matter? */); { LLVMValueRef bbox_min[3], bbox_max[3]; LLVMValueRef accepted = initially_accepted; /* Compute the primitive bounding box for easy culling. */ for (unsigned chan = 0; chan < 3; chan++) { bbox_min[chan] = ac_build_fmin(ctx, pos[0][chan], pos[1][chan]); bbox_min[chan] = ac_build_fmin(ctx, bbox_min[chan], pos[2][chan]); bbox_max[chan] = ac_build_fmax(ctx, pos[0][chan], pos[1][chan]); bbox_max[chan] = ac_build_fmax(ctx, bbox_max[chan], pos[2][chan]); } /* View culling. */ if (cull_view_xy || cull_view_near_z || cull_view_far_z) { for (unsigned chan = 0; chan < 3; chan++) { LLVMValueRef visible; if ((cull_view_xy && chan <= 1) || (cull_view_near_z && chan == 2)) { float t = chan == 2 && use_halfz_clip_space ? 0 : -1; visible = LLVMBuildFCmp(builder, LLVMRealOGE, bbox_max[chan], LLVMConstReal(ctx->f32, t), ""); accepted = LLVMBuildAnd(builder, accepted, visible, ""); } if ((cull_view_xy && chan <= 1) || (cull_view_far_z && chan == 2)) { visible = LLVMBuildFCmp(builder, LLVMRealOLE, bbox_min[chan], ctx->f32_1, ""); accepted = LLVMBuildAnd(builder, accepted, visible, ""); } } } /* Small primitive elimination. */ if (cull_small_prims) { /* Assuming a sample position at (0.5, 0.5), if we round * the bounding box min/max extents and the results of * the rounding are equal in either the X or Y direction, * the bounding box does not intersect the sample. * * See these GDC slides for pictures: * https://frostbite-wp-prd.s3.amazonaws.com/wp-content/uploads/2016/03/29204330/GDC_2016_Compute.pdf */ LLVMValueRef min, max, not_equal[2], visible; for (unsigned chan = 0; chan < 2; chan++) { /* Convert the position to screen-space coordinates. */ min = ac_build_fmad(ctx, bbox_min[chan], vp_scale[chan], vp_translate[chan]); max = ac_build_fmad(ctx, bbox_max[chan], vp_scale[chan], vp_translate[chan]); /* Scale the bounding box according to the precision of * the rasterizer and the number of MSAA samples. */ min = LLVMBuildFSub(builder, min, small_prim_precision, ""); max = LLVMBuildFAdd(builder, max, small_prim_precision, ""); /* Determine if the bbox intersects the sample point. * It also works for MSAA, but vp_scale, vp_translate, * and small_prim_precision are computed differently. */ min = ac_build_round(ctx, min); max = ac_build_round(ctx, max); not_equal[chan] = LLVMBuildFCmp(builder, LLVMRealONE, min, max, ""); } visible = LLVMBuildAnd(builder, not_equal[0], not_equal[1], ""); accepted = LLVMBuildAnd(builder, accepted, visible, ""); } LLVMBuildStore(builder, accepted, accepted_var); } ac_build_endif(ctx, 10000000); return LLVMBuildLoad(builder, accepted_var, ""); }
/** * Build code to compare two values 'a' and 'b' of 'type' using the given func. * \param func one of PIPE_FUNC_x * The result values will be 0 for false or ~0 for true. */ LLVMValueRef lp_build_compare(struct gallivm_state *gallivm, const struct lp_type type, unsigned func, LLVMValueRef a, LLVMValueRef b) { LLVMBuilderRef builder = gallivm->builder; LLVMTypeRef int_vec_type = lp_build_int_vec_type(gallivm, type); LLVMValueRef zeros = LLVMConstNull(int_vec_type); LLVMValueRef ones = LLVMConstAllOnes(int_vec_type); LLVMValueRef cond; LLVMValueRef res; assert(func >= PIPE_FUNC_NEVER); assert(func <= PIPE_FUNC_ALWAYS); assert(lp_check_value(type, a)); assert(lp_check_value(type, b)); if(func == PIPE_FUNC_NEVER) return zeros; if(func == PIPE_FUNC_ALWAYS) return ones; #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) /* * There are no unsigned integer comparison instructions in SSE. */ if (!type.floating && !type.sign && type.width * type.length == 128 && util_cpu_caps.has_sse2 && (func == PIPE_FUNC_LESS || func == PIPE_FUNC_LEQUAL || func == PIPE_FUNC_GREATER || func == PIPE_FUNC_GEQUAL) && (gallivm_debug & GALLIVM_DEBUG_PERF)) { debug_printf("%s: inefficient <%u x i%u> unsigned comparison\n", __FUNCTION__, type.length, type.width); } #endif #if HAVE_LLVM < 0x0207 #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) if(type.width * type.length == 128) { if(type.floating && util_cpu_caps.has_sse) { /* float[4] comparison */ LLVMTypeRef vec_type = lp_build_vec_type(gallivm, type); LLVMValueRef args[3]; unsigned cc; boolean swap; swap = FALSE; switch(func) { case PIPE_FUNC_EQUAL: cc = 0; break; case PIPE_FUNC_NOTEQUAL: cc = 4; break; case PIPE_FUNC_LESS: cc = 1; break; case PIPE_FUNC_LEQUAL: cc = 2; break; case PIPE_FUNC_GREATER: cc = 1; swap = TRUE; break; case PIPE_FUNC_GEQUAL: cc = 2; swap = TRUE; break; default: assert(0); return lp_build_undef(gallivm, type); } if(swap) { args[0] = b; args[1] = a; } else { args[0] = a; args[1] = b; } args[2] = LLVMConstInt(LLVMInt8TypeInContext(gallivm->context), cc, 0); res = lp_build_intrinsic(builder, "llvm.x86.sse.cmp.ps", vec_type, args, 3); res = LLVMBuildBitCast(builder, res, int_vec_type, ""); return res; } else if(util_cpu_caps.has_sse2) { /* int[4] comparison */ static const struct { unsigned swap:1; unsigned eq:1; unsigned gt:1; unsigned not:1; } table[] = { {0, 0, 0, 1}, /* PIPE_FUNC_NEVER */ {1, 0, 1, 0}, /* PIPE_FUNC_LESS */ {0, 1, 0, 0}, /* PIPE_FUNC_EQUAL */ {0, 0, 1, 1}, /* PIPE_FUNC_LEQUAL */ {0, 0, 1, 0}, /* PIPE_FUNC_GREATER */ {0, 1, 0, 1}, /* PIPE_FUNC_NOTEQUAL */ {1, 0, 1, 1}, /* PIPE_FUNC_GEQUAL */ {0, 0, 0, 0} /* PIPE_FUNC_ALWAYS */ }; const char *pcmpeq; const char *pcmpgt; LLVMValueRef args[2]; LLVMValueRef res; LLVMTypeRef vec_type = lp_build_vec_type(gallivm, type); switch (type.width) { case 8: pcmpeq = "llvm.x86.sse2.pcmpeq.b"; pcmpgt = "llvm.x86.sse2.pcmpgt.b"; break; case 16: pcmpeq = "llvm.x86.sse2.pcmpeq.w"; pcmpgt = "llvm.x86.sse2.pcmpgt.w"; break; case 32: pcmpeq = "llvm.x86.sse2.pcmpeq.d"; pcmpgt = "llvm.x86.sse2.pcmpgt.d"; break; default: assert(0); return lp_build_undef(gallivm, type); } /* There are no unsigned comparison instructions. So flip the sign bit * so that the results match. */ if (table[func].gt && !type.sign) { LLVMValueRef msb = lp_build_const_int_vec(gallivm, type, (unsigned long long)1 << (type.width - 1)); a = LLVMBuildXor(builder, a, msb, ""); b = LLVMBuildXor(builder, b, msb, ""); } if(table[func].swap) { args[0] = b; args[1] = a; } else { args[0] = a; args[1] = b; } if(table[func].eq) res = lp_build_intrinsic(builder, pcmpeq, vec_type, args, 2); else if (table[func].gt) res = lp_build_intrinsic(builder, pcmpgt, vec_type, args, 2); else res = LLVMConstNull(vec_type); if(table[func].not) res = LLVMBuildNot(builder, res, ""); return res; } } /* if (type.width * type.length == 128) */ #endif #endif /* HAVE_LLVM < 0x0207 */ /* XXX: It is not clear if we should use the ordered or unordered operators */ if(type.floating) { LLVMRealPredicate op; switch(func) { case PIPE_FUNC_NEVER: op = LLVMRealPredicateFalse; break; case PIPE_FUNC_ALWAYS: op = LLVMRealPredicateTrue; break; case PIPE_FUNC_EQUAL: op = LLVMRealUEQ; break; case PIPE_FUNC_NOTEQUAL: op = LLVMRealUNE; break; case PIPE_FUNC_LESS: op = LLVMRealULT; break; case PIPE_FUNC_LEQUAL: op = LLVMRealULE; break; case PIPE_FUNC_GREATER: op = LLVMRealUGT; break; case PIPE_FUNC_GEQUAL: op = LLVMRealUGE; break; default: assert(0); return lp_build_undef(gallivm, type); } #if HAVE_LLVM >= 0x0207 cond = LLVMBuildFCmp(builder, op, a, b, ""); res = LLVMBuildSExt(builder, cond, int_vec_type, ""); #else if (type.length == 1) { cond = LLVMBuildFCmp(builder, op, a, b, ""); res = LLVMBuildSExt(builder, cond, int_vec_type, ""); } else { unsigned i; res = LLVMGetUndef(int_vec_type); debug_printf("%s: warning: using slow element-wise float" " vector comparison\n", __FUNCTION__); for (i = 0; i < type.length; ++i) { LLVMValueRef index = lp_build_const_int32(gallivm, i); cond = LLVMBuildFCmp(builder, op, LLVMBuildExtractElement(builder, a, index, ""), LLVMBuildExtractElement(builder, b, index, ""), ""); cond = LLVMBuildSelect(builder, cond, LLVMConstExtractElement(ones, index), LLVMConstExtractElement(zeros, index), ""); res = LLVMBuildInsertElement(builder, res, cond, index, ""); } } #endif } else { LLVMIntPredicate op; switch(func) { case PIPE_FUNC_EQUAL: op = LLVMIntEQ; break; case PIPE_FUNC_NOTEQUAL: op = LLVMIntNE; break; case PIPE_FUNC_LESS: op = type.sign ? LLVMIntSLT : LLVMIntULT; break; case PIPE_FUNC_LEQUAL: op = type.sign ? LLVMIntSLE : LLVMIntULE; break; case PIPE_FUNC_GREATER: op = type.sign ? LLVMIntSGT : LLVMIntUGT; break; case PIPE_FUNC_GEQUAL: op = type.sign ? LLVMIntSGE : LLVMIntUGE; break; default: assert(0); return lp_build_undef(gallivm, type); } #if HAVE_LLVM >= 0x0207 cond = LLVMBuildICmp(builder, op, a, b, ""); res = LLVMBuildSExt(builder, cond, int_vec_type, ""); #else if (type.length == 1) { cond = LLVMBuildICmp(builder, op, a, b, ""); res = LLVMBuildSExt(builder, cond, int_vec_type, ""); } else { unsigned i; res = LLVMGetUndef(int_vec_type); if (gallivm_debug & GALLIVM_DEBUG_PERF) { debug_printf("%s: using slow element-wise int" " vector comparison\n", __FUNCTION__); } for(i = 0; i < type.length; ++i) { LLVMValueRef index = lp_build_const_int32(gallivm, i); cond = LLVMBuildICmp(builder, op, LLVMBuildExtractElement(builder, a, index, ""), LLVMBuildExtractElement(builder, b, index, ""), ""); cond = LLVMBuildSelect(builder, cond, LLVMConstExtractElement(ones, index), LLVMConstExtractElement(zeros, index), ""); res = LLVMBuildInsertElement(builder, res, cond, index, ""); } } #endif } return res; }
struct vm_value * vm_value_build_cmp_op(struct vm_state *vm, int operation, struct vm_value *lhs, struct vm_value *rhs) { struct vm_value *res; LLVMOpcode opcode; LLVMIntPredicate int_predicate; LLVMRealPredicate float_predicate; res = vm_value_new(lhs->type_specifier, ""); opcode = (res->type_specifier == TYPE_INT) ? LLVMICmp : LLVMFCmp; switch (operation) { case AST_GT: if (res->type_specifier == TYPE_INT) int_predicate = LLVMIntSGT; else float_predicate = LLVMRealOGT; break; case AST_LT: if (res->type_specifier == TYPE_INT) int_predicate = LLVMIntSLT; else float_predicate = LLVMRealOLT; break; case AST_EQ: if (res->type_specifier == TYPE_INT) int_predicate = LLVMIntEQ; else float_predicate = LLVMRealOEQ; break; case AST_NE: if (res->type_specifier == TYPE_INT) int_predicate = LLVMIntNE; else float_predicate = LLVMRealONE; break; case AST_LE: if (res->type_specifier == TYPE_INT) int_predicate = LLVMIntSLE; else float_predicate = LLVMRealOLE; break; case AST_GE: if (res->type_specifier == TYPE_INT) int_predicate = LLVMIntSGE; else float_predicate = LLVMRealOGE; break; default: fprintf(stderr, "Unknown comparison operation: %d\n", operation); exit(EXIT_FAILURE); } if (opcode == LLVMICmp) { res->llvm_value = LLVMBuildICmp(vm->builder, int_predicate, lhs->llvm_value, rhs->llvm_value, ""); } else { res->llvm_value = LLVMBuildFCmp(vm->builder, float_predicate, lhs->llvm_value, rhs->llvm_value, ""); } return res; }