[Mesa-dev] [PATCH 3/3] gallivm: obey clarified shift behavior

sroland at vmware.com sroland at vmware.com
Tue Jul 30 09:13:06 PDT 2013


From: Roland Scheidegger <sroland at vmware.com>

llvm shifts are undefined for shift counts exceeding (or matching) bit width,
so need to apply a mask.
NOTE: there's internal callers using this which guarantee the shift count
is smaller than the type width. However, all of these use constant shift
counts hence the additional AND will get dropped by llvm (hopefully, some
quick observation at least showed it working). There is also code using shifts
where we know the shift count must be smaller than type width but llvm does
not, however these all seem to be using LLVMBuildLShr/AShr/Shl directly (like
lp_build_minify for mip level minification), hence at this point don't
introduce additional lp_build_shl/shr functions which skip the masking.
---
 src/gallium/auxiliary/gallivm/lp_bld_bitarit.c |   14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/gallium/auxiliary/gallivm/lp_bld_bitarit.c b/src/gallium/auxiliary/gallivm/lp_bld_bitarit.c
index 97ae162..7cae09d 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_bitarit.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_bitarit.c
@@ -168,6 +168,7 @@ lp_build_not(struct lp_build_context *bld, LLVMValueRef a)
 
 /**
  * Shift left.
+ * The shift count is masked to type width - 1.
  */
 LLVMValueRef
 lp_build_shl(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
@@ -181,6 +182,9 @@ lp_build_shl(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
    assert(lp_check_value(type, a));
    assert(lp_check_value(type, b));
 
+   b = LLVMBuildAnd(builder, b,
+                    lp_build_const_vec(bld->gallivm, type, type.width - 1), "");
+
    res = LLVMBuildShl(builder, a, b, "");
 
    return res;
@@ -189,6 +193,7 @@ lp_build_shl(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
 
 /**
  * Shift right.
+ * The shift count is masked to type width - 1.
  */
 LLVMValueRef
 lp_build_shr(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
@@ -202,6 +207,9 @@ lp_build_shr(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
    assert(lp_check_value(type, a));
    assert(lp_check_value(type, b));
 
+   b = LLVMBuildAnd(builder, b,
+                    lp_build_const_vec(bld->gallivm, type, type.width - 1), "");
+
    if (type.sign) {
       res = LLVMBuildAShr(builder, a, b, "");
    } else {
@@ -214,23 +222,25 @@ lp_build_shr(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
 
 /**
  * Shift left with immediate.
+ * The immediate shift count must be smaller than the type width.
  */
 LLVMValueRef
 lp_build_shl_imm(struct lp_build_context *bld, LLVMValueRef a, unsigned imm)
 {
    LLVMValueRef b = lp_build_const_int_vec(bld->gallivm, bld->type, imm);
-   assert(imm <= bld->type.width);
+   assert(imm < bld->type.width);
    return lp_build_shl(bld, a, b);
 }
 
 
 /**
  * Shift right with immediate.
+ * The immediate shift count must be smaller than the type width.
  */
 LLVMValueRef
 lp_build_shr_imm(struct lp_build_context *bld, LLVMValueRef a, unsigned imm)
 {
    LLVMValueRef b = lp_build_const_int_vec(bld->gallivm, bld->type, imm);
-   assert(imm <= bld->type.width);
+   assert(imm < bld->type.width);
    return lp_build_shr(bld, a, b);
 }
-- 
1.7.9.5


More information about the mesa-dev mailing list