ac/nir: Support load_constant intrinsics
authorConnor Abbott <cwabbott0@gmail.com>
Thu, 29 Aug 2019 15:28:01 +0000 (17:28 +0200)
committerConnor Abbott <cwabbott0@gmail.com>
Thu, 5 Sep 2019 10:21:42 +0000 (12:21 +0200)
Setup a constant global variable that LLVM will stick in a .rodata
section and generate PC-relative loads for.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/amd/common/ac_nir_to_llvm.c

index baac8e5ec97a8369d0f7e6468692b66341bfe968..13578770d4a81f7228da2461a54e617aebaec02f 100644 (file)
@@ -43,6 +43,7 @@ struct ac_nir_context {
        LLVMValueRef *ssa_defs;
 
        LLVMValueRef scratch;
+       LLVMValueRef constant_data;
 
        struct hash_table *defs;
        struct hash_table *phis;
@@ -3770,6 +3771,25 @@ static void visit_intrinsic(struct ac_nir_context *ctx,
                }
                break;
        }
+       case nir_intrinsic_load_constant: {
+               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, "");
+               LLVMValueRef ptr = ac_build_gep0(&ctx->ac, ctx->constant_data,
+                                                offset);
+               LLVMTypeRef comp_type =
+                       LLVMIntTypeInContext(ctx->ac.context, instr->dest.ssa.bit_size);
+               LLVMTypeRef vec_type =
+                       instr->dest.ssa.num_components == 1 ? comp_type :
+                       LLVMVectorType(comp_type, instr->dest.ssa.num_components);
+               unsigned addr_space = LLVMGetPointerAddressSpace(LLVMTypeOf(ptr));
+               ptr = LLVMBuildBitCast(ctx->ac.builder, ptr,
+                                      LLVMPointerType(vec_type, addr_space), "");
+               result = LLVMBuildLoad(ctx->ac.builder, ptr, "");
+               break;
+       }
        default:
                fprintf(stderr, "Unknown intrinsic: ");
                nir_print_instr(&instr->instr, stderr);
@@ -4682,6 +4702,40 @@ setup_scratch(struct ac_nir_context *ctx,
                                             "scratch");
 }
 
+static void
+setup_constant_data(struct ac_nir_context *ctx,
+                   struct nir_shader *shader)
+{
+       if (!shader->constant_data)
+               return;
+
+       LLVMValueRef data =
+               LLVMConstStringInContext(ctx->ac.context,
+                                        shader->constant_data,
+                                        shader->constant_data_size,
+                                        true);
+       LLVMTypeRef type = LLVMArrayType(ctx->ac.i8, shader->constant_data_size);
+
+       /* We want to put the constant data in the CONST address space so that
+        * we can use scalar loads. However, LLVM versions before 10 put these
+        * variables in the same section as the code, which is unacceptable
+        * for RadeonSI as it needs to relocate all the data sections after
+        * the code sections. See https://reviews.llvm.org/D65813.
+        */
+       unsigned address_space =
+               HAVE_LLVM < 0x1000 ? AC_ADDR_SPACE_GLOBAL : AC_ADDR_SPACE_CONST;
+
+       LLVMValueRef global =
+               LLVMAddGlobalInAddressSpace(ctx->ac.module, type,
+                                           "const_data",
+                                           address_space);
+
+       LLVMSetInitializer(global, data);
+       LLVMSetGlobalConstant(global, true);
+       LLVMSetVisibility(global, LLVMHiddenVisibility);
+       ctx->constant_data = global;
+}
+
 static void
 setup_shared(struct ac_nir_context *ctx,
             struct nir_shader *nir)
@@ -4728,6 +4782,7 @@ void ac_nir_translate(struct ac_llvm_context *ac, struct ac_shader_abi *abi,
 
        setup_locals(&ctx, func);
        setup_scratch(&ctx, nir);
+       setup_constant_data(&ctx, nir);
 
        if (gl_shader_stage_is_compute(nir->info.stage))
                setup_shared(&ctx, nir);