From: Marek Olšák <marek.ol...@amd.com> --- docs/GL3.txt | 2 +- .../drivers/radeon/radeon_setup_tgsi_llvm.c | 92 ++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/docs/GL3.txt b/docs/GL3.txt index 0487cdf..8fd2f4a 100644 --- a/docs/GL3.txt +++ b/docs/GL3.txt @@ -102,7 +102,7 @@ GL 4.0, GLSL 4.00: - Dynamically uniform UBO array indices DONE (r600) - Implicit signed -> unsigned conversions DONE - Fused multiply-add DONE () - - Packing/bitfield/conversion functions DONE (r600) + - Packing/bitfield/conversion functions DONE (r600, radeonsi) - Enhanced textureGather DONE (r600, radeonsi) - Geometry shader instancing DONE (r600) - Geometry shader multiple streams DONE () diff --git a/src/gallium/drivers/radeon/radeon_setup_tgsi_llvm.c b/src/gallium/drivers/radeon/radeon_setup_tgsi_llvm.c index c6132d3..6379c7f 100644 --- a/src/gallium/drivers/radeon/radeon_setup_tgsi_llvm.c +++ b/src/gallium/drivers/radeon/radeon_setup_tgsi_llvm.c @@ -1261,6 +1261,95 @@ static void emit_bfi(const struct lp_build_tgsi_action * action, Elements(bfi_args), LLVMReadNoneAttribute); } +/* this is ffs in C */ +static void emit_lsb(const struct lp_build_tgsi_action * action, + struct lp_build_tgsi_context * bld_base, + struct lp_build_emit_data * emit_data) +{ + struct gallivm_state *gallivm = bld_base->base.gallivm; + LLVMValueRef args[2] = { + emit_data->args[0], + + /* The value of 1 means that ffs(x=0) = undef, so LLVM won't + * add special code to check for x=0. The reason is that + * the LLVM behavior for x=0 is different from what we + * need here. + * + * The hardware already implements the correct behavior. + */ + lp_build_const_int32(gallivm, 1) + }; + + emit_data->output[emit_data->chan] = + build_intrinsic(gallivm->builder, "llvm.cttz.i32", + emit_data->dst_type, args, Elements(args), + LLVMReadNoneAttribute); +} + +/* Find the last bit set. */ +static void emit_umsb(const struct lp_build_tgsi_action * action, + struct lp_build_tgsi_context * bld_base, + struct lp_build_emit_data * emit_data) +{ + struct gallivm_state *gallivm = bld_base->base.gallivm; + LLVMBuilderRef builder = gallivm->builder; + LLVMValueRef args[2] = { + emit_data->args[0], + /* Don't generate code for handling zero: */ + lp_build_const_int32(gallivm, 1) + }; + + LLVMValueRef msb = + build_intrinsic(builder, "llvm.ctlz.i32", + emit_data->dst_type, args, Elements(args), + LLVMReadNoneAttribute); + + /* The HW returns the last bit index from MSB, but TGSI wants + * the index from LSB. Invert it by doing "31 - msb". */ + msb = LLVMBuildSub(builder, lp_build_const_int32(gallivm, 31), + msb, ""); + + /* Check for zero: */ + emit_data->output[emit_data->chan] = + LLVMBuildSelect(builder, + LLVMBuildICmp(builder, LLVMIntEQ, args[0], + bld_base->uint_bld.zero, ""), + lp_build_const_int32(gallivm, -1), msb, ""); +} + +/* Find the last bit opposite of the sign bit. */ +static void emit_imsb(const struct lp_build_tgsi_action * action, + struct lp_build_tgsi_context * bld_base, + struct lp_build_emit_data * emit_data) +{ + struct gallivm_state *gallivm = bld_base->base.gallivm; + LLVMBuilderRef builder = gallivm->builder; + LLVMValueRef arg = emit_data->args[0]; + + LLVMValueRef msb = + build_intrinsic(builder, "llvm.AMDGPU.flbit.i32", + emit_data->dst_type, &arg, 1, + LLVMReadNoneAttribute); + + /* The HW returns the last bit index from MSB, but TGSI wants + * the index from LSB. Invert it by doing "31 - msb". */ + msb = LLVMBuildSub(builder, lp_build_const_int32(gallivm, 31), + msb, ""); + + /* If arg == 0 || arg == -1 (0xffffffff), return -1. */ + LLVMValueRef all_ones = lp_build_const_int32(gallivm, -1); + + LLVMValueRef cond = + LLVMBuildOr(builder, + LLVMBuildICmp(builder, LLVMIntEQ, arg, + bld_base->uint_bld.zero, ""), + LLVMBuildICmp(builder, LLVMIntEQ, arg, + all_ones, ""), ""); + + emit_data->output[emit_data->chan] = + LLVMBuildSelect(builder, cond, all_ones, msb, ""); +} + void radeon_llvm_context_init(struct radeon_llvm_context * ctx) { struct lp_type type; @@ -1365,6 +1454,7 @@ void radeon_llvm_context_init(struct radeon_llvm_context * ctx) bld_base->op_actions[TGSI_OPCODE_IMAX].intr_name = "llvm.AMDGPU.imax"; bld_base->op_actions[TGSI_OPCODE_IMIN].emit = build_tgsi_intrinsic_nomem; bld_base->op_actions[TGSI_OPCODE_IMIN].intr_name = "llvm.AMDGPU.imin"; + bld_base->op_actions[TGSI_OPCODE_IMSB].emit = emit_imsb; bld_base->op_actions[TGSI_OPCODE_INEG].emit = emit_ineg; bld_base->op_actions[TGSI_OPCODE_ISHR].emit = emit_ishr; bld_base->op_actions[TGSI_OPCODE_ISGE].emit = emit_icmp; @@ -1375,11 +1465,13 @@ void radeon_llvm_context_init(struct radeon_llvm_context * ctx) bld_base->op_actions[TGSI_OPCODE_KILL_IF].intr_name = "llvm.AMDGPU.kill"; bld_base->op_actions[TGSI_OPCODE_KILL].emit = lp_build_tgsi_intrinsic; bld_base->op_actions[TGSI_OPCODE_KILL].intr_name = "llvm.AMDGPU.kilp"; + bld_base->op_actions[TGSI_OPCODE_LSB].emit = emit_lsb; bld_base->op_actions[TGSI_OPCODE_LG2].emit = build_tgsi_intrinsic_nomem; bld_base->op_actions[TGSI_OPCODE_LG2].intr_name = "llvm.log2.f32"; bld_base->op_actions[TGSI_OPCODE_LRP].emit = build_tgsi_intrinsic_nomem; bld_base->op_actions[TGSI_OPCODE_LRP].intr_name = "llvm.AMDGPU.lrp"; bld_base->op_actions[TGSI_OPCODE_MOD].emit = emit_mod; + bld_base->op_actions[TGSI_OPCODE_UMSB].emit = emit_umsb; bld_base->op_actions[TGSI_OPCODE_NOT].emit = emit_not; bld_base->op_actions[TGSI_OPCODE_OR].emit = emit_or; bld_base->op_actions[TGSI_OPCODE_POPC].emit = build_tgsi_intrinsic_nomem; -- 2.1.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev