Added code to process NIR shared load/store intrinsic.
authorVivek Pandya <vivekvpandya@gmail.com>
Sat, 6 Feb 2021 09:22:42 +0000 (14:52 +0530)
committerVivek Pandya <vivekvpandya@gmail.com>
Sat, 6 Feb 2021 09:22:42 +0000 (14:52 +0530)
Also added code to disassemble and print X86 instructions for
egarly compiled function in ORCJIT.

src/libre-soc/vulkan/libresoc_llvm.c
src/libre-soc/vulkan/libresoc_llvm.h

index 100fc1ea2347f914765bff89fd149e3b55b1312b..06a62424300eef00c4c9c69a06151e5be7e1daba 100644 (file)
@@ -3,8 +3,13 @@
 
 void InitLLVM(struct libresoc_llvm *llvm_ref)
 {
-    LLVMInitializeNativeTarget();
-    LLVMInitializeNativeAsmPrinter();
+    // LLVMInitializeNativeTarget();
+    // LLVMInitializeNativeAsmPrinter();
+    LLVMInitializeAllAsmPrinters();
+    LLVMInitializeAllTargets();
+    LLVMInitializeAllTargetInfos();
+    LLVMInitializeAllTargetMCs();
+    LLVMInitializeAllDisassemblers();
     //LLVMLinkInMCJIT();
     char *def_triple = LLVMGetDefaultTargetTriple();   // E.g. "x86_64-linux-gnu"
     char *error;
@@ -121,6 +126,17 @@ void handle_shader_output_decl(struct libresoc_nir_tran_ctx *ctx,
    }
 }
 
+LLVMValueRef extract_components(struct libresoc_llvm_context *ctx, LLVMValueRef value, unsigned start,
+                                   unsigned channels)
+{
+   LLVMValueRef chan[channels];
+
+   for (unsigned i = 0; i < channels; i++)
+      chan[i] = llvm_extract_elem(ctx, value, i + start);
+
+   return build_gather_values(ctx, chan, channels);
+}
+
 static void build_store_values_extended(struct libresoc_llvm_context *lc, LLVMValueRef *values,
                                         unsigned value_count, unsigned value_stride,
                                         LLVMValueRef vec)
@@ -179,6 +195,26 @@ static LLVMValueRef get_src(struct libresoc_nir_tran_ctx *ctx, nir_src src)
    return ctx->ssa_defs[src.ssa->index];
 }
 
+static LLVMTypeRef get_def_type(struct libresoc_nir_tran_ctx *ctx, const nir_ssa_def *def)
+{
+   LLVMTypeRef type = LLVMIntTypeInContext(ctx->lc.context, def->bit_size);
+   if (def->num_components > 1) {
+      type = LLVMVectorType(type, def->num_components);
+   }
+   return type;
+}
+
+static LLVMValueRef get_memory_ptr(struct libresoc_nir_tran_ctx *ctx, nir_src src, unsigned bit_size)
+{
+   LLVMValueRef ptr = get_src(ctx, src);
+   ptr = LLVMBuildGEP(ctx->lc.builder, ctx->lc.lds, &ptr, 1, "");
+   int addr_space = LLVMGetPointerAddressSpace(LLVMTypeOf(ptr));
+
+   LLVMTypeRef type = LLVMIntTypeInContext(ctx->lc.context, bit_size);
+
+   return LLVMBuildBitCast(ctx->lc.builder, ptr, LLVMPointerType(type, addr_space), "");
+}
+
 static uint32_t widen_mask(uint32_t mask, unsigned multiplier)
 {
    uint32_t new_mask = 0;
@@ -683,6 +719,146 @@ static LLVMTypeRef glsl_to_llvm_type(struct libresoc_llvm_context *lc, const str
    return LLVMStructTypeInContext(lc->context, member_types, glsl_get_length(type), false);
 }
 
+// static LLVMValueRef visit_load(struct libresoc_nir_tran_ctx *ctx, nir_intrinsic_instr *instr,
+//                                bool is_output)
+// {
+//    LLVMValueRef values[8];
+//    LLVMTypeRef dest_type = get_def_type(ctx, &instr->dest.ssa);
+//    LLVMTypeRef component_type;
+//    unsigned base = nir_intrinsic_base(instr);
+//    unsigned component = nir_intrinsic_component(instr);
+//    unsigned count = instr->dest.ssa.num_components * (instr->dest.ssa.bit_size == 64 ? 2 : 1);
+//    nir_src *vertex_index_src = nir_get_io_vertex_index_src(instr);
+//    LLVMValueRef vertex_index = vertex_index_src ? get_src(ctx, *vertex_index_src) : NULL;
+//    nir_src offset = *nir_get_io_offset_src(instr);
+//    LLVMValueRef indir_index = NULL;
+
+//    if (LLVMGetTypeKind(dest_type) == LLVMVectorTypeKind)
+//       component_type = LLVMGetElementType(dest_type);
+//    else
+//       component_type = dest_type;
+
+//    if (nir_src_is_const(offset))
+//       assert(nir_src_as_uint(offset) == 0);
+//    else
+//       indir_index = get_src(ctx, offset);
+
+//    if (ctx->stage == MESA_SHADER_TESS_CTRL || (ctx->stage == MESA_SHADER_TESS_EVAL && !is_output)) {
+//       LLVMValueRef result = ctx->abi->load_tess_varyings(
+//          ctx->abi, component_type, vertex_index, indir_index, 0, 0, base * 4, component,
+//          instr->num_components, false, false, !is_output);
+//       if (instr->dest.ssa.bit_size == 16) {
+//          result = to_integer(&ctx->lc, result);
+//          result = LLVMBuildTrunc(ctx->lc.builder, result, dest_type, "");
+//       }
+//       return LLVMBuildBitCast(ctx->lc.builder, result, dest_type, "");
+//    }
+
+//    /* No indirect indexing is allowed after this point. */
+//    assert(!indir_index);
+
+//    if (ctx->stage == MESA_SHADER_GEOMETRY) {
+//       LLVMTypeRef type = LLVMIntTypeInContext(ctx->ac.context, instr->dest.ssa.bit_size);
+//       assert(nir_src_is_const(*vertex_index_src));
+
+//       return ctx->abi->load_inputs(ctx->abi, 0, base * 4, component, instr->num_components,
+//                                    nir_src_as_uint(*vertex_index_src), 0, type);
+//    }
+
+//    if (ctx->stage == MESA_SHADER_FRAGMENT && is_output &&
+//        nir_intrinsic_io_semantics(instr).fb_fetch_output)
+//       return ctx->abi->emit_fbfetch(ctx->abi);
+
+//    /* Other non-fragment cases have inputs and outputs in temporaries. */
+//    if (ctx->stage != MESA_SHADER_FRAGMENT) {
+//       for (unsigned chan = component; chan < count + component; chan++) {
+//          if (is_output) {
+//             values[chan] = LLVMBuildLoad(ctx->lc.builder, ctx->outputs[base * 4 + chan], "");
+//          } else {
+//             values[chan] = ctx->inputs[base * 4 + chan];
+//             if (!values[chan])
+//                values[chan] = LLVMGetUndef(ctx->lc.i32);
+//          }
+//       }
+//       LLVMValueRef result = build_varying_gather_values(&ctx->lc, values, count, component);
+//       return LLVMBuildBitCast(ctx->lc.builder, result, dest_type, "");
+//    }
+
+//    /* Fragment shader inputs. */
+//    unsigned vertex_id = 2; /* P0 */
+
+//    if (instr->intrinsic == nir_intrinsic_load_input_vertex) {
+//       nir_const_value *src0 = nir_src_as_const_value(instr->src[0]);
+
+//       switch (src0[0].i32) {
+//       case 0:
+//          vertex_id = 2;
+//          break;
+//       case 1:
+//          vertex_id = 0;
+//          break;
+//       case 2:
+//          vertex_id = 1;
+//          break;
+//       default:
+//          unreachable("Invalid vertex index");
+//       }
+//    }
+
+//    LLVMValueRef attr_number = LLVMConstInt(ctx->lc.i32, base, false);
+
+//    for (unsigned chan = 0; chan < count; chan++) {
+//       if (component + chan > 4)
+//          attr_number = LLVMConstInt(ctx->lc.i32, base + 1, false);
+//       LLVMValueRef llvm_chan = LLVMConstInt(ctx->lc.i32, (component + chan) % 4, false);
+//       values[chan] =
+//          build_fs_interp_mov(&ctx->lc, LLVMConstInt(ctx->lc.i32, vertex_id, false), llvm_chan,
+//                                 attr_number, get_arg(&ctx->lc, ctx->args->prim_mask));
+//       values[chan] = LLVMBuildBitCast(ctx->lc.builder, values[chan], ctx->lc.i32, "");
+//       values[chan] =
+//          LLVMBuildTruncOrBitCast(ctx->lc.builder, values[chan],
+//                                  instr->dest.ssa.bit_size == 16 ? ctx->lc.i16 : ctx->lc.i32, "");
+//    }
+
+//    LLVMValueRef result = build_gather_values(&ctx->lc, values, count);
+//    return LLVMBuildBitCast(ctx->lc.builder, result, dest_type, "");
+// }
+
+static LLVMValueRef visit_load_shared(struct libresoc_nir_tran_ctx *ctx, const nir_intrinsic_instr *instr)
+{
+   LLVMValueRef values[4], derived_ptr, index, ret;
+
+   LLVMValueRef ptr = get_memory_ptr(ctx, instr->src[0], instr->dest.ssa.bit_size);
+
+   for (int chan = 0; chan < instr->num_components; chan++) {
+      index = LLVMConstInt(ctx->lc.i32, chan, 0);
+      derived_ptr = LLVMBuildGEP(ctx->lc.builder, ptr, &index, 1, "");
+      values[chan] = LLVMBuildLoad(ctx->lc.builder, derived_ptr, "");
+   }
+
+   ret = build_gather_values(&ctx->lc, values, instr->num_components);
+   return LLVMBuildBitCast(ctx->lc.builder, ret, get_def_type(ctx, &instr->dest.ssa), "");
+}
+
+static void visit_store_shared(struct libresoc_nir_tran_ctx *ctx, const nir_intrinsic_instr *instr)
+{
+   LLVMValueRef derived_ptr, data, index;
+   LLVMBuilderRef builder = ctx->lc.builder;
+
+   LLVMValueRef ptr = get_memory_ptr(ctx, instr->src[1], instr->src[0].ssa->bit_size);
+   LLVMValueRef src = get_src(ctx, instr->src[0]);
+
+   int writemask = nir_intrinsic_write_mask(instr);
+   for (int chan = 0; chan < 4; chan++) {
+      if (!(writemask & (1 << chan))) {
+         continue;
+      }
+      data = llvm_extract_elem(&ctx->lc, src, chan);
+      index = LLVMConstInt(ctx->lc.i32, chan, 0);
+      derived_ptr = LLVMBuildGEP(builder, ptr, &index, 1, "");
+      LLVMBuildStore(builder, data, derived_ptr);
+   }
+}
 static void visit_load_const(struct libresoc_nir_tran_ctx *ctx, const nir_load_const_instr *instr)
 {
    LLVMValueRef values[4], value = NULL;
@@ -876,15 +1052,6 @@ static void visit_deref(struct libresoc_nir_tran_ctx *ctx, nir_deref_instr *inst
    ctx->ssa_defs[instr->dest.ssa.index] = result;
 }
 
-static LLVMTypeRef get_def_type(struct libresoc_nir_tran_ctx *ctx, const nir_ssa_def *def)
-{
-   LLVMTypeRef type = LLVMIntTypeInContext(ctx->lc.context, def->bit_size);
-   if (def->num_components > 1) {
-      type = LLVMVectorType(type, def->num_components);
-   }
-   return type;
-}
-
 static void visit_phi(struct libresoc_nir_tran_ctx *ctx, nir_phi_instr *instr)
 {
    LLVMTypeRef type = get_def_type(ctx, &instr->dest.ssa);
@@ -2062,10 +2229,10 @@ static void visit_intrinsic(struct libresoc_nir_tran_ctx *ctx, nir_intrinsic_ins
       visit_store_output(ctx, instr);
       break;
    case nir_intrinsic_load_shared:
-      // result = visit_load_shared(ctx, instr);
+      result = visit_load_shared(ctx, instr);
       break;
    case nir_intrinsic_store_shared:
-      // visit_store_shared(ctx, instr);
+      visit_store_shared(ctx, instr);
       break;
    case nir_intrinsic_bindless_image_samples:
    case nir_intrinsic_image_deref_samples:
@@ -2335,61 +2502,61 @@ static void visit_intrinsic(struct libresoc_nir_tran_ctx *ctx, nir_intrinsic_ins
       // result = ac_build_mbcnt(&ctx->ac, get_src(ctx, instr->src[0]));
       break;
    case nir_intrinsic_load_scratch: {
-      // LLVMValueRef offset = get_src(ctx, instr->src[0]);
-      // LLVMValueRef ptr = ac_build_gep0(&ctx->ac, ctx->scratch, 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, "");
+      LLVMValueRef offset = get_src(ctx, instr->src[0]);
+      LLVMValueRef ptr = build_gep0(&ctx->lc, ctx->scratch, offset);
+      LLVMTypeRef comp_type = LLVMIntTypeInContext(ctx->lc.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->lc.builder, ptr, LLVMPointerType(vec_type, addr_space), "");
+      result = LLVMBuildLoad(ctx->lc.builder, ptr, "");
       break;
    }
    case nir_intrinsic_store_scratch: {
-      // LLVMValueRef offset = get_src(ctx, instr->src[1]);
-      // LLVMValueRef ptr = ac_build_gep0(&ctx->ac, ctx->scratch, offset);
-      // LLVMTypeRef comp_type = LLVMIntTypeInContext(ctx->ac.context, instr->src[0].ssa->bit_size);
-      // unsigned addr_space = LLVMGetPointerAddressSpace(LLVMTypeOf(ptr));
-      // ptr = LLVMBuildBitCast(ctx->ac.builder, ptr, LLVMPointerType(comp_type, addr_space), "");
-      // LLVMValueRef src = get_src(ctx, instr->src[0]);
-      // unsigned wrmask = nir_intrinsic_write_mask(instr);
-      // while (wrmask) {
-      //    int start, count;
-      //    u_bit_scan_consecutive_range(&wrmask, &start, &count);
-
-      //    LLVMValueRef offset = LLVMConstInt(ctx->ac.i32, start, false);
-      //    LLVMValueRef offset_ptr = LLVMBuildGEP(ctx->ac.builder, ptr, &offset, 1, "");
-      //    LLVMTypeRef vec_type = count == 1 ? comp_type : LLVMVectorType(comp_type, count);
-      //    offset_ptr = LLVMBuildBitCast(ctx->ac.builder, offset_ptr,
-      //                                  LLVMPointerType(vec_type, addr_space), "");
-      //    LLVMValueRef offset_src = ac_extract_components(&ctx->ac, src, start, count);
-      //    LLVMBuildStore(ctx->ac.builder, offset_src, offset_ptr);
-      // }
+      LLVMValueRef offset = get_src(ctx, instr->src[1]);
+      LLVMValueRef ptr = build_gep0(&ctx->lc, ctx->scratch, offset);
+      LLVMTypeRef comp_type = LLVMIntTypeInContext(ctx->lc.context, instr->src[0].ssa->bit_size);
+      unsigned addr_space = LLVMGetPointerAddressSpace(LLVMTypeOf(ptr));
+      ptr = LLVMBuildBitCast(ctx->lc.builder, ptr, LLVMPointerType(comp_type, addr_space), "");
+      LLVMValueRef src = get_src(ctx, instr->src[0]);
+      unsigned wrmask = nir_intrinsic_write_mask(instr);
+      while (wrmask) {
+         int start, count;
+         u_bit_scan_consecutive_range(&wrmask, &start, &count);
+
+         LLVMValueRef offset = LLVMConstInt(ctx->lc.i32, start, false);
+         LLVMValueRef offset_ptr = LLVMBuildGEP(ctx->lc.builder, ptr, &offset, 1, "");
+         LLVMTypeRef vec_type = count == 1 ? comp_type : LLVMVectorType(comp_type, count);
+         offset_ptr = LLVMBuildBitCast(ctx->lc.builder, offset_ptr,
+                                       LLVMPointerType(vec_type, addr_space), "");
+         LLVMValueRef offset_src = extract_components(&ctx->lc, src, start, count);
+         LLVMBuildStore(ctx->lc.builder, offset_src, offset_ptr);
+      }
       break;
    }
    case nir_intrinsic_load_constant: {
-      // unsigned base = nir_intrinsic_base(instr);
-      // unsigned range = nir_intrinsic_range(instr);
+      unsigned base = nir_intrinsic_base(instr);
+      unsigned range = nir_intrinsic_range(instr);
 
-      // LLVMValueRef offset = get_src(ctx, instr->src[0]);
-      // offset = LLVMBuildAdd(ctx->ac.builder, offset, LLVMConstInt(ctx->ac.i32, base, false), "");
+      LLVMValueRef offset = get_src(ctx, instr->src[0]);
+      offset = LLVMBuildAdd(ctx->lc.builder, offset, LLVMConstInt(ctx->lc.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, "");
+      /* Clamp the offset to avoid out-of-bound access because global
+       * instructions can't handle them.
+       */
+      LLVMValueRef size = LLVMConstInt(ctx->lc.i32, base + range, false);
+      LLVMValueRef cond = LLVMBuildICmp(ctx->lc.builder, LLVMIntULT, offset, size, "");
+      offset = LLVMBuildSelect(ctx->lc.builder, cond, offset, size, "");
 
-      // 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, "");
+      LLVMValueRef ptr = build_gep0(&ctx->lc, ctx->constant_data, offset);
+      LLVMTypeRef comp_type = LLVMIntTypeInContext(ctx->lc.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->lc.builder, ptr, LLVMPointerType(vec_type, addr_space), "");
+      result = LLVMBuildLoad(ctx->lc.builder, ptr, "");
       break;
    }
    default:
@@ -2548,10 +2715,70 @@ LLVMModuleRef libresoc_nir_translate(struct libresoc_llvm *llvm_ref, struct nir_
     // if (gl_shader_stage_is_compute(nir->info.stage))
     //     setup_shared(&ctx, nir);
     visit_cf_list(&ctx, &func->impl->body);
+    LLVMBuildRetVoid(ctx.lc.builder);
     char *error = NULL;
     LLVMVerifyModule(mod, LLVMPrintMessageAction, &error);
     LLVMDumpModule(mod);
     LLVMDisposeMessage(error);
+    LLVMOrcModuleHandle mod_handle;
+    LLVMErrorRef error_ref =  LLVMOrcAddEagerlyCompiledIR(llvm_ref->orc_ref,
+            &mod_handle,
+            mod,
+            orc_sym_resolver,
+            (void *)(llvm_ref->orc_ref));
+    LLVMDumpModule(mod);
+    char *def_triple = LLVMGetDefaultTargetTriple();   // E.g. "x86_64-linux-gnu"
+    LLVMDisasmContextRef disasm = LLVMCreateDisasm(def_triple, NULL,
+                                      0, NULL,
+                                     NULL);
+    if (disasm) {
+LLVMOrcTargetAddress MainAddr;
+LLVMOrcGetSymbolAddress(llvm_ref->orc_ref, &MainAddr ,"main_function");
+   const uint8_t *bytes = (const uint8_t *)MainAddr; 
+   char outline[1024];
+uint64_t pc;
+   pc = 0;
+uint64_t extent = 200;
+   while (pc < extent) {
+      size_t Size;
+
+      /*
+       * Print address.  We use addresses relative to the start of the function,
+       * so that between runs.
+       */
+
+
+      Size = LLVMDisasmInstruction(disasm, (uint8_t *)bytes + pc, extent - pc, 0, outline,
+                                   sizeof outline);
+
+      /*
+       * Print the instruction.
+       */
+      printf("\t%s \n", outline);
+
+
+      /*
+       * Stop disassembling on return statements, if there is no record of a
+       * jump to a successive address.
+       *
+       * XXX: This currently assumes x86
+       */
+
+      if (Size == 1 && bytes[pc] == 0xc3) {
+         break;
+      }
+
+      /*
+       * Advance.
+       */
+
+      pc += Size;
+
+      if (pc >= extent) {
+         break;
+      }
+   }    
+    }
     return mod;
     // LLVMModuleRef mod = LLVMModuleCreateWithName("libresoc_mod");
     // LLVMTypeRef param_types[] = { LLVMInt32Type(), LLVMInt32Type() };
index 4668e47c15b2745f1116564eb511104ca6bb3035..6aeae357aee545d6373c91f99d04ae861b704af0 100644 (file)
@@ -6,6 +6,7 @@
 #include "libresoc_shader_args.h"
 #include <llvm-c/OrcBindings.h>
 #include <llvm-c/Core.h>
+#include <llvm-c/Disassembler.h>
 #include <llvm-c/Analysis.h>
 #include "nir/nir.h"
 #include "nir/nir_deref.h"
@@ -118,6 +119,8 @@ typedef struct libresoc_llvm_context {
 
     struct llvm_flow_state *flow;
     unsigned float_mode;
+
+    LLVMValueRef lds;
 } libresoc_llvm_context;
 
 struct libresoc_llvm {
@@ -158,6 +161,9 @@ struct libresoc_nir_tran_ctx {
 void InitLLVM(struct libresoc_llvm *llvm_ref);
 void DestroyLLVM(struct libresoc_llvm *llvm_ref);
 
+LLVMValueRef extract_components(struct libresoc_llvm_context *ctx, LLVMValueRef value, unsigned start,
+                                   unsigned channels);
+
 static inline unsigned llvm_reg_index_soa(unsigned index, unsigned chan)
 {
    return (index * 4) + chan;