ac/nir: fix out-of-bound access when loading constants from global
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Tue, 10 Dec 2019 16:46:26 +0000 (17:46 +0100)
committerSamuel Pitoiset <samuel.pitoiset@gmail.com>
Thu, 12 Dec 2019 10:12:56 +0000 (10:12 +0000)
Global load/store instructions can't know if the offset is
out-of-bound because they don't use descriptors (no range).

Fix this by clamping the offset for arrays that are indexed
with a non-constant offset that's greater or equal to the array
size.

This fixes VM faults and GPU hangs with Dead Rising 4.

Closes: https://gitlab.freedesktop.org/mesa/mesa/issues/2148
Fixes: 71a67942003 ("ac/nir: Enable nir_opt_large_constants")
Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
src/amd/llvm/ac_nir_to_llvm.c

index 4c8216dbe73d7601196775ddab11b4446d0b4ce5..d69b8c90238442868172cb760e0e530dd802b83e 100644 (file)
@@ -3758,11 +3758,21 @@ static void visit_intrinsic(struct ac_nir_context *ctx,
                break;
        }
        case nir_intrinsic_load_constant: {
                break;
        }
        case nir_intrinsic_load_constant: {
+               unsigned base = nir_intrinsic_base(instr);
+               unsigned range = nir_intrinsic_range(instr);
+
                LLVMValueRef offset = get_src(ctx, instr->src[0]);
                LLVMValueRef offset = get_src(ctx, instr->src[0]);
-               LLVMValueRef base = LLVMConstInt(ctx->ac.i32,
-                                                nir_intrinsic_base(instr),
-                                                false);
-               offset = LLVMBuildAdd(ctx->ac.builder, offset, base, "");
+               offset = LLVMBuildAdd(ctx->ac.builder, offset,
+                                     LLVMConstInt(ctx->ac.i32, base, false), "");
+
+               /* Clamp the offset to avoid out-of-bound access because global
+                * instructions can't handle them.
+                */
+               LLVMValueRef size = LLVMConstInt(ctx->ac.i32, base + range, false);
+               LLVMValueRef cond = LLVMBuildICmp(ctx->ac.builder, LLVMIntULT,
+                                                 offset, size, "");
+               offset = LLVMBuildSelect(ctx->ac.builder, cond, offset, size, "");
+
                LLVMValueRef ptr = ac_build_gep0(&ctx->ac, ctx->constant_data,
                                                 offset);
                LLVMTypeRef comp_type =
                LLVMValueRef ptr = ac_build_gep0(&ctx->ac, ctx->constant_data,
                                                 offset);
                LLVMTypeRef comp_type =