LLVMModuleRef r600_tgsi_llvm(
	struct radeon_llvm_context * ctx,
	const struct tgsi_token * tokens)
{
	struct tgsi_shader_info shader_info;
	struct lp_build_tgsi_context * bld_base = &ctx->soa.bld_base;
	radeon_llvm_context_init(ctx);
#if HAVE_LLVM >= 0x0304
	LLVMTypeRef Arguments[32];
	unsigned ArgumentsCount = 0;
	for (unsigned i = 0; i < ctx->inputs_count; i++)
		Arguments[ArgumentsCount++] = LLVMVectorType(bld_base->base.elem_type, 4);
	radeon_llvm_create_func(ctx, Arguments, ArgumentsCount);
	for (unsigned i = 0; i < ctx->inputs_count; i++) {
		LLVMValueRef P = LLVMGetParam(ctx->main_fn, i);
		LLVMAddAttribute(P, LLVMInRegAttribute);
	}
#else
	radeon_llvm_create_func(ctx, NULL, 0);
#endif
	tgsi_scan_shader(tokens, &shader_info);

	bld_base->info = &shader_info;
	bld_base->userdata = ctx;
	bld_base->emit_fetch_funcs[TGSI_FILE_CONSTANT] = llvm_fetch_const;
	bld_base->emit_prologue = llvm_emit_prologue;
	bld_base->emit_epilogue = llvm_emit_epilogue;
	ctx->userdata = ctx;
	ctx->load_input = llvm_load_input;
	ctx->load_system_value = llvm_load_system_value;

	bld_base->op_actions[TGSI_OPCODE_DP2] = dot_action;
	bld_base->op_actions[TGSI_OPCODE_DP3] = dot_action;
	bld_base->op_actions[TGSI_OPCODE_DP4] = dot_action;
	bld_base->op_actions[TGSI_OPCODE_DPH] = dot_action;
	bld_base->op_actions[TGSI_OPCODE_DDX].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_DDY].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TEX].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TEX2].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TXB].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TXB2].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TXD].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TXL].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TXL2].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TXF].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TXQ].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_TXP].emit = llvm_emit_tex;
	bld_base->op_actions[TGSI_OPCODE_CMP].emit = emit_cndlt;

	lp_build_tgsi_llvm(bld_base, tokens);

	radeon_llvm_finalize_module(ctx);

	return ctx->gallivm.module;
}
Ejemplo n.º 2
0
void
lp_add_function_attr(LLVMValueRef function_or_call,
                     int attr_idx, enum lp_func_attr attr)
{

#if HAVE_LLVM < 0x0400
   LLVMAttribute llvm_attr = lp_attr_to_llvm_attr(attr);
   if (LLVMIsAFunction(function_or_call)) {
      if (attr_idx == -1) {
         LLVMAddFunctionAttr(function_or_call, llvm_attr);
      } else {
         LLVMAddAttribute(LLVMGetParam(function_or_call, attr_idx - 1), llvm_attr);
      }
   } else {
      LLVMAddInstrAttribute(function_or_call, attr_idx, llvm_attr);
   }
#else

   LLVMModuleRef module;
   if (LLVMIsAFunction(function_or_call)) {
      module = LLVMGetGlobalParent(function_or_call);
   } else {
      LLVMBasicBlockRef bb = LLVMGetInstructionParent(function_or_call);
      LLVMValueRef function = LLVMGetBasicBlockParent(bb);
      module = LLVMGetGlobalParent(function);
   }
   LLVMContextRef ctx = LLVMGetModuleContext(module);

   const char *attr_name = attr_to_str(attr);
   unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name,
                                                      strlen(attr_name));
   LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(ctx, kind_id, 0);

   if (LLVMIsAFunction(function_or_call))
      LLVMAddAttributeAtIndex(function_or_call, attr_idx, llvm_attr);
   else
      LLVMAddCallSiteAttribute(function_or_call, attr_idx, llvm_attr);
#endif
}
Ejemplo n.º 3
0
Archivo: codegen.c Proyecto: dckc/ponyc
LLVMValueRef codegen_addfun(compile_t* c, const char* name, LLVMTypeRef type)
{
  // Add the function and set the calling convention.
  LLVMValueRef fun = LLVMAddFunction(c->module, name, type);

  if(!c->opt->library)
    LLVMSetFunctionCallConv(fun, GEN_CALLCONV);

  LLVMValueRef arg = LLVMGetFirstParam(fun);
  uint32_t i = 1;

  while(arg != NULL)
  {
    LLVMTypeRef type = LLVMTypeOf(arg);

    if(LLVMGetTypeKind(type) == LLVMPointerTypeKind)
    {
      LLVMTypeRef elem = LLVMGetElementType(type);

      if(LLVMGetTypeKind(elem) == LLVMStructTypeKind)
      {
        uint64_t size = LLVMABISizeOfType(c->target_data, elem);
        LLVMSetDereferenceable(fun, i, size);
      }

      // Set the noalias attribute on all arguments. This is fortran-like
      // semantics for parameter aliasing, similar to C restrict.
      if(!c->opt->no_restrict)
        LLVMAddAttribute(arg, LLVMNoAliasAttribute);
    }

    arg = LLVMGetNextParam(arg);
    i++;
  }

  return fun;
}
Ejemplo n.º 4
0
static LLVMValueRef get_stritem_len_fn(struct llvm_ctx *ctx)
{
	if(ctx->stritem_len_fn != NULL) return ctx->stritem_len_fn;

	/* returns (i32 len, i32 new_tpos)
	 * params (word *utcbptr, i32 tpos)
	 *
	 * when return value "new_tpos" > tmax + 1, the result is invalid. the function
	 * should also not be called when tpos > tmax + 1.
	 */
	LLVMTypeRef ret_types[2] = { ctx->i32t, ctx->i32t },
		parm_types[2] = { LLVMPointerType(ctx->wordt, 0), ctx->i32t },
		ret_type = LLVMStructTypeInContext(ctx->ctx, ret_types, 2, 0),
		fn_type = LLVMFunctionType(ret_type, parm_types, 2, 0);
	LLVMValueRef fn = LLVMAddFunction(ctx->module, "__muidl_get_stritem_len",
		fn_type);
	LLVMSetVisibility(fn, LLVMHiddenVisibility);
	LLVMSetLinkage(fn, LLVMInternalLinkage);
	V fn_args[2];
	LLVMGetParams(fn, fn_args);
	LLVMAddAttribute(fn_args[0], LLVMNoCaptureAttribute);
	for(int i=0; i<2; i++) {
		LLVMAddAttribute(fn_args[i], LLVMInRegAttribute);
	}
	ctx->stritem_len_fn = fn;

	LLVMBuilderRef old_builder = ctx->builder;
	ctx->builder = LLVMCreateBuilderInContext(ctx->ctx);
	LLVMBasicBlockRef entry_bb = LLVMAppendBasicBlockInContext(ctx->ctx, fn,
			"EntryBlock"),
		loop_bb = LLVMAppendBasicBlockInContext(ctx->ctx, fn, "loop"),
		valid_bb = LLVMAppendBasicBlockInContext(ctx->ctx, fn, "valid"),
		exit_bb = LLVMAppendBasicBlockInContext(ctx->ctx, fn, "exit");

	LLVMPositionBuilderAtEnd(ctx->builder, entry_bb);
	LLVMValueRef old_utcb = ctx->utcb, old_tpos = ctx->tpos;
	ctx->utcb = fn_args[0];
	ctx->tpos = fn_args[1];
	LLVMBuildBr(ctx->builder, loop_bb);

	LLVMPositionBuilderAtEnd(ctx->builder, exit_bb);
	LLVMValueRef exit_len_phi = LLVMBuildPhi(ctx->builder, ctx->i32t,
			"exit.len.phi"),
		exit_tpos_phi = LLVMBuildPhi(ctx->builder, ctx->i32t,
			"exit.tpos.phi");
	LLVMValueRef rvals[2] = { exit_len_phi, exit_tpos_phi };
	LLVMBuildAggregateRet(ctx->builder, rvals, 2);

	LLVMPositionBuilderAtEnd(ctx->builder, loop_bb);
	LLVMValueRef len_phi = LLVMBuildPhi(ctx->builder, ctx->i32t, "len.phi"),
		tpos_phi = LLVMBuildPhi(ctx->builder, ctx->i32t, "tpos.phi");
	LLVMAddIncoming(len_phi, &ctx->zero, &entry_bb, 1);
	LLVMAddIncoming(tpos_phi, &ctx->tpos, &entry_bb, 1);
	ctx->tpos = tpos_phi;
	/* test: if *tpos doesn't look like a string item, conk out. */
	LLVMValueRef infoword = build_utcb_load(ctx, ctx->tpos, "si.info");
	LLVMValueRef is_cond = LLVMBuildICmp(ctx->builder, LLVMIntEQ,
		ctx->zero, LLVMBuildAnd(ctx->builder, infoword,
			CONST_WORD(1 << 4), "infoword.si.mask"),
		"infoword.si.cond");
	/* anything + 100 is sure to be > tmax + 1. */
	LLVMValueRef fucked_tpos = LLVMBuildAdd(ctx->builder, tpos_phi,
		CONST_INT(100), "f****d.tpos");
	branch_set_phi(ctx, exit_len_phi, len_phi);
	branch_set_phi(ctx, exit_tpos_phi, fucked_tpos);
	LLVMBuildCondBr(ctx->builder, is_cond, valid_bb, exit_bb);

	LLVMPositionBuilderAtEnd(ctx->builder, valid_bb);
	LLVMValueRef string_length = LLVMBuildTruncOrBitCast(ctx->builder,
			LLVMBuildLShr(ctx->builder, infoword,
				CONST_INT(10), "si.info.len"),
			ctx->i32t, "si.info.len.int"),
		string_j = LLVMBuildTruncOrBitCast(ctx->builder,
			LLVMBuildAnd(ctx->builder, CONST_WORD(0x1f),
				LLVMBuildLShr(ctx->builder, infoword, CONST_WORD(4),
					"si.info.j.shift"),
				"si.info.j.masked"),
			ctx->i32t, "si.info.j"),
		string_c = LLVMBuildTruncOrBitCast(ctx->builder,
			LLVMBuildAnd(ctx->builder, CONST_WORD(1 << 9),
				infoword, "si.info.c.masked"),
			ctx->i32t, "si.info.c.masked.int"),
		c_cond = LLVMBuildICmp(ctx->builder, LLVMIntNE,
			string_c, CONST_WORD(0), "si.info.c.cond"),
		new_len = LLVMBuildAdd(ctx->builder, len_phi,
			LLVMBuildMul(ctx->builder, string_length,
				LLVMBuildAdd(ctx->builder, string_j,
					CONST_INT(1), "j.plus.one"),
				"len.incr"),
			"len.new"),
		new_tpos = LLVMBuildAdd(ctx->builder, ctx->tpos,
			LLVMBuildSelect(ctx->builder, c_cond,
				LLVMBuildAdd(ctx->builder, CONST_INT(2),
					string_j, "cont.tpos.bump"),
				CONST_INT(2), "tpos.bump"),
			"tpos.new");
	LLVMAddIncoming(len_phi, &new_len, &valid_bb, 1);
	LLVMAddIncoming(tpos_phi, &new_tpos, &valid_bb, 1);
	LLVMAddIncoming(exit_len_phi, &new_len, &valid_bb, 1);
	LLVMAddIncoming(exit_tpos_phi, &new_tpos, &valid_bb, 1);
	LLVMBuildCondBr(ctx->builder, c_cond, loop_bb, exit_bb);

	LLVMDisposeBuilder(ctx->builder);
	ctx->builder = old_builder;
	ctx->utcb = old_utcb;
	ctx->tpos = old_tpos;

	return ctx->stritem_len_fn;
}
Ejemplo n.º 5
0
static void init_runtime(compile_t* c)
{
  c->str_builtin = stringtab("$0");
  c->str_Bool = stringtab("Bool");
  c->str_I8 = stringtab("I8");
  c->str_I16 = stringtab("I16");
  c->str_I32 = stringtab("I32");
  c->str_I64 = stringtab("I64");
  c->str_I128 = stringtab("I128");
  c->str_ILong = stringtab("ILong");
  c->str_ISize = stringtab("ISize");
  c->str_U8 = stringtab("U8");
  c->str_U16 = stringtab("U16");
  c->str_U32 = stringtab("U32");
  c->str_U64 = stringtab("U64");
  c->str_U128 = stringtab("U128");
  c->str_ULong = stringtab("ULong");
  c->str_USize = stringtab("USize");
  c->str_F32 = stringtab("F32");
  c->str_F64 = stringtab("F64");
  c->str_Pointer = stringtab("Pointer");
  c->str_Maybe = stringtab("MaybePointer");
  c->str_DoNotOptimise = stringtab("DoNotOptimise");
  c->str_Array = stringtab("Array");
  c->str_String = stringtab("String");
  c->str_Platform = stringtab("Platform");
  c->str_Main = stringtab("Main");
  c->str_Env = stringtab("Env");

  c->str_add = stringtab("add");
  c->str_sub = stringtab("sub");
  c->str_mul = stringtab("mul");
  c->str_div = stringtab("div");
  c->str_mod = stringtab("mod");
  c->str_neg = stringtab("neg");
  c->str_add_unsafe = stringtab("add_unsafe");
  c->str_sub_unsafe = stringtab("sub_unsafe");
  c->str_mul_unsafe = stringtab("mul_unsafe");
  c->str_div_unsafe = stringtab("div_unsafe");
  c->str_mod_unsafe = stringtab("mod_unsafe");
  c->str_neg_unsafe = stringtab("neg_unsafe");
  c->str_and = stringtab("op_and");
  c->str_or = stringtab("op_or");
  c->str_xor = stringtab("op_xor");
  c->str_not = stringtab("op_not");
  c->str_shl = stringtab("shl");
  c->str_shr = stringtab("shr");
  c->str_shl_unsafe = stringtab("shl_unsafe");
  c->str_shr_unsafe = stringtab("shr_unsafe");
  c->str_eq = stringtab("eq");
  c->str_ne = stringtab("ne");
  c->str_lt = stringtab("lt");
  c->str_le = stringtab("le");
  c->str_ge = stringtab("ge");
  c->str_gt = stringtab("gt");
  c->str_eq_unsafe = stringtab("eq_unsafe");
  c->str_ne_unsafe = stringtab("ne_unsafe");
  c->str_lt_unsafe = stringtab("lt_unsafe");
  c->str_le_unsafe = stringtab("le_unsafe");
  c->str_ge_unsafe = stringtab("ge_unsafe");
  c->str_gt_unsafe = stringtab("gt_unsafe");

  c->str_this = stringtab("this");
  c->str_create = stringtab("create");
  c->str__create = stringtab("_create");
  c->str__init = stringtab("_init");
  c->str__final = stringtab("_final");
  c->str__event_notify = stringtab("_event_notify");
  c->str__serialise_space = stringtab("_serialise_space");
  c->str__serialise = stringtab("_serialise");
  c->str__deserialise = stringtab("_deserialise");

  LLVMTypeRef type;
  LLVMTypeRef params[5];
  LLVMValueRef value;

  c->void_type = LLVMVoidTypeInContext(c->context);
  c->i1 = LLVMInt1TypeInContext(c->context);
  c->i8 = LLVMInt8TypeInContext(c->context);
  c->i16 = LLVMInt16TypeInContext(c->context);
  c->i32 = LLVMInt32TypeInContext(c->context);
  c->i64 = LLVMInt64TypeInContext(c->context);
  c->i128 = LLVMIntTypeInContext(c->context, 128);
  c->f32 = LLVMFloatTypeInContext(c->context);
  c->f64 = LLVMDoubleTypeInContext(c->context);
  c->intptr = LLVMIntPtrTypeInContext(c->context, c->target_data);

  // i8*
  c->void_ptr = LLVMPointerType(c->i8, 0);

  // forward declare object
  c->object_type = LLVMStructCreateNamed(c->context, "__object");
  c->object_ptr = LLVMPointerType(c->object_type, 0);

  // padding required in an actor between the descriptor and fields
  c->actor_pad = LLVMArrayType(c->i8, PONY_ACTOR_PAD_SIZE);

  // message
  params[0] = c->i32; // size
  params[1] = c->i32; // id
  c->msg_type = LLVMStructCreateNamed(c->context, "__message");
  c->msg_ptr = LLVMPointerType(c->msg_type, 0);
  LLVMStructSetBody(c->msg_type, params, 2, false);

  // trace
  // void (*)(i8*, __object*)
  params[0] = c->void_ptr;
  params[1] = c->object_ptr;
  c->trace_type = LLVMFunctionType(c->void_type, params, 2, false);
  c->trace_fn = LLVMPointerType(c->trace_type, 0);

  // serialise
  // void (*)(i8*, __object*, i8*, intptr, i32)
  params[0] = c->void_ptr;
  params[1] = c->object_ptr;
  params[2] = c->void_ptr;
  params[3] = c->intptr;
  params[4] = c->i32;
  c->serialise_type = LLVMFunctionType(c->void_type, params, 5, false);
  c->serialise_fn = LLVMPointerType(c->serialise_type, 0);

  // serialise_space
  // i64 (__object*)
  params[0] = c->object_ptr;
  c->custom_serialise_space_fn = LLVMPointerType(
    LLVMFunctionType(c->i64, params, 1, false), 0);

  // custom_deserialise
  // void (*)(__object*, void*)
  params[0] = c->object_ptr;
  params[1] = c->void_ptr;
  c->custom_deserialise_fn = LLVMPointerType(
  LLVMFunctionType(c->void_type, params, 2, false), 0);

  // dispatch
  // void (*)(i8*, __object*, $message*)
  params[0] = c->void_ptr;
  params[1] = c->object_ptr;
  params[2] = c->msg_ptr;
  c->dispatch_type = LLVMFunctionType(c->void_type, params, 3, false);
  c->dispatch_fn = LLVMPointerType(c->dispatch_type, 0);

  // void (*)(__object*)
  params[0] = c->object_ptr;
  c->final_fn = LLVMPointerType(
    LLVMFunctionType(c->void_type, params, 1, false), 0);

  // descriptor, opaque version
  // We need this in order to build our own structure.
  const char* desc_name = genname_descriptor(NULL);
  c->descriptor_type = LLVMStructCreateNamed(c->context, desc_name);
  c->descriptor_ptr = LLVMPointerType(c->descriptor_type, 0);

  // field descriptor
  // Also needed to build a descriptor structure.
  params[0] = c->i32;
  params[1] = c->descriptor_ptr;
  c->field_descriptor = LLVMStructTypeInContext(c->context, params, 2, false);

  // descriptor, filled in
  gendesc_basetype(c, c->descriptor_type);

  // define object
  params[0] = c->descriptor_ptr;
  LLVMStructSetBody(c->object_type, params, 1, false);

#if PONY_LLVM >= 309
  LLVM_DECLARE_ATTRIBUTEREF(nounwind_attr, nounwind, 0);
  LLVM_DECLARE_ATTRIBUTEREF(readnone_attr, readnone, 0);
  LLVM_DECLARE_ATTRIBUTEREF(readonly_attr, readonly, 0);
  LLVM_DECLARE_ATTRIBUTEREF(inacc_or_arg_mem_attr,
    inaccessiblemem_or_argmemonly, 0);
  LLVM_DECLARE_ATTRIBUTEREF(noalias_attr, noalias, 0);
  LLVM_DECLARE_ATTRIBUTEREF(noreturn_attr, noreturn, 0);
  LLVM_DECLARE_ATTRIBUTEREF(deref_actor_attr, dereferenceable,
    PONY_ACTOR_PAD_SIZE + (target_is_ilp32(c->opt->triple) ? 4 : 8));
  LLVM_DECLARE_ATTRIBUTEREF(align_pool_attr, align, ponyint_pool_size(0));
  LLVM_DECLARE_ATTRIBUTEREF(align_heap_attr, align, HEAP_MIN);
  LLVM_DECLARE_ATTRIBUTEREF(deref_or_null_alloc_attr, dereferenceable_or_null,
    HEAP_MIN);
  LLVM_DECLARE_ATTRIBUTEREF(deref_alloc_small_attr, dereferenceable, HEAP_MIN);
  LLVM_DECLARE_ATTRIBUTEREF(deref_alloc_large_attr, dereferenceable,
    HEAP_MAX << 1);
#endif

  // i8* pony_ctx()
  type = LLVMFunctionType(c->void_ptr, NULL, 0, false);
  value = LLVMAddFunction(c->module, "pony_ctx", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, readnone_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
  LLVMAddFunctionAttr(value, LLVMReadNoneAttribute);
#endif

  // __object* pony_create(i8*, __Desc*)
  params[0] = c->void_ptr;
  params[1] = c->descriptor_ptr;
  type = LLVMFunctionType(c->object_ptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_create", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, deref_actor_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_pool_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
  LLVMSetDereferenceable(value, 0, PONY_ACTOR_PAD_SIZE +
    (target_is_ilp32(c->opt->triple) ? 4 : 8));
#endif

  // void ponyint_destroy(__object*)
  params[0] = c->object_ptr;
  type = LLVMFunctionType(c->void_type, params, 1, false);
  value = LLVMAddFunction(c->module, "ponyint_destroy", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
#endif

  // void pony_sendv(i8*, __object*, $message*, $message*)
  params[0] = c->void_ptr;
  params[1] = c->object_ptr;
  params[2] = c->msg_ptr;
  params[3] = c->msg_ptr;
  type = LLVMFunctionType(c->void_type, params, 4, false);
  value = LLVMAddFunction(c->module, "pony_sendv", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
#endif

  // void pony_sendv_single(i8*, __object*, $message*, $message*)
  params[0] = c->void_ptr;
  params[1] = c->object_ptr;
  params[2] = c->msg_ptr;
  params[3] = c->msg_ptr;
  type = LLVMFunctionType(c->void_type, params, 4, false);
  value = LLVMAddFunction(c->module, "pony_sendv_single", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
#endif

  // i8* pony_alloc(i8*, intptr)
  params[0] = c->void_ptr;
  params[1] = c->intptr;
  type = LLVMFunctionType(c->void_ptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_alloc", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex,
    deref_or_null_alloc_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_heap_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
  LLVMSetDereferenceableOrNull(value, 0, HEAP_MIN);
#endif

  // i8* pony_alloc_small(i8*, i32)
  params[0] = c->void_ptr;
  params[1] = c->i32;
  type = LLVMFunctionType(c->void_ptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_alloc_small", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex,
    deref_alloc_small_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_heap_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
  LLVMSetDereferenceable(value, 0, HEAP_MIN);
#endif

  // i8* pony_alloc_large(i8*, intptr)
  params[0] = c->void_ptr;
  params[1] = c->intptr;
  type = LLVMFunctionType(c->void_ptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_alloc_large", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex,
    deref_alloc_large_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_heap_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
  LLVMSetDereferenceable(value, 0, HEAP_MAX << 1);
#endif

  // i8* pony_realloc(i8*, i8*, intptr)
  params[0] = c->void_ptr;
  params[1] = c->void_ptr;
  params[2] = c->intptr;
  type = LLVMFunctionType(c->void_ptr, params, 3, false);
  value = LLVMAddFunction(c->module, "pony_realloc", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex,
    deref_or_null_alloc_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_heap_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
  LLVMSetDereferenceableOrNull(value, 0, HEAP_MIN);
#endif

  // i8* pony_alloc_final(i8*, intptr)
  params[0] = c->void_ptr;
  params[1] = c->intptr;
  type = LLVMFunctionType(c->void_ptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_alloc_final", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex,
    deref_or_null_alloc_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_heap_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
  LLVMSetDereferenceableOrNull(value, 0, HEAP_MIN);
#endif

  // i8* pony_alloc_small_final(i8*, i32)
  params[0] = c->void_ptr;
  params[1] = c->i32;
  type = LLVMFunctionType(c->void_ptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_alloc_small_final", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex,
    deref_alloc_small_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_heap_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
  LLVMSetDereferenceable(value, 0, HEAP_MIN);
#endif

  // i8* pony_alloc_large_final(i8*, intptr)
  params[0] = c->void_ptr;
  params[1] = c->intptr;
  type = LLVMFunctionType(c->void_ptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_alloc_large_final", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex,
    deref_alloc_large_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_heap_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
  LLVMSetDereferenceable(value, 0, HEAP_MAX << 1);
#endif

  // $message* pony_alloc_msg(i32, i32)
  params[0] = c->i32;
  params[1] = c->i32;
  type = LLVMFunctionType(c->msg_ptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_alloc_msg", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, align_pool_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
#endif

  // void pony_trace(i8*, i8*)
  params[0] = c->void_ptr;
  params[1] = c->void_ptr;
  type = LLVMFunctionType(c->void_type, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_trace", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, 2, readnone_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  value = LLVMGetParam(value, 1);
  LLVMAddAttribute(value, LLVMReadNoneAttribute);
#endif

  // void pony_traceknown(i8*, __object*, __Desc*, i32)
  params[0] = c->void_ptr;
  params[1] = c->object_ptr;
  params[2] = c->descriptor_ptr;
  params[3] = c->i32;
  type = LLVMFunctionType(c->void_type, params, 4, false);
  value = LLVMAddFunction(c->module, "pony_traceknown", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, 2, readonly_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  value = LLVMGetParam(value, 1);
  LLVMAddAttribute(value, LLVMReadOnlyAttribute);
#endif

  // void pony_traceunknown(i8*, __object*, i32)
  params[0] = c->void_ptr;
  params[1] = c->object_ptr;
  params[2] = c->i32;
  type = LLVMFunctionType(c->void_type, params, 3, false);
  value = LLVMAddFunction(c->module, "pony_traceunknown", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, 2, readonly_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  value = LLVMGetParam(value, 1);
  LLVMAddAttribute(value, LLVMReadOnlyAttribute);
#endif

  // void pony_gc_send(i8*)
  params[0] = c->void_ptr;
  type = LLVMFunctionType(c->void_type, params, 1, false);
  value = LLVMAddFunction(c->module, "pony_gc_send", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
#endif

  // void pony_gc_recv(i8*)
  params[0] = c->void_ptr;
  type = LLVMFunctionType(c->void_type, params, 1, false);
  value = LLVMAddFunction(c->module, "pony_gc_recv", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
#endif

  // void pony_send_done(i8*)
  params[0] = c->void_ptr;
  type = LLVMFunctionType(c->void_type, params, 1, false);
  value = LLVMAddFunction(c->module, "pony_send_done", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#endif

  // void pony_recv_done(i8*)
  params[0] = c->void_ptr;
  type = LLVMFunctionType(c->void_type, params, 1, false);
  value = LLVMAddFunction(c->module, "pony_recv_done", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#endif

  // void pony_serialise_reserve(i8*, i8*, intptr)
  params[0] = c->void_ptr;
  params[1] = c->void_ptr;
  params[2] = c->intptr;
  type = LLVMFunctionType(c->void_type, params, 3, false);
  value = LLVMAddFunction(c->module, "pony_serialise_reserve", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, 2, readnone_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  value = LLVMGetParam(value, 1);
  LLVMAddAttribute(value, LLVMReadNoneAttribute);
#endif

  // intptr pony_serialise_offset(i8*, i8*)
  params[0] = c->void_ptr;
  params[1] = c->void_ptr;
  type = LLVMFunctionType(c->intptr, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_serialise_offset", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, 2, readonly_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  value = LLVMGetParam(value, 1);
  LLVMAddAttribute(value, LLVMReadOnlyAttribute);
#endif

  // i8* pony_deserialise_offset(i8*, __desc*, intptr)
  params[0] = c->void_ptr;
  params[1] = c->descriptor_ptr;
  params[2] = c->intptr;
  type = LLVMFunctionType(c->void_ptr, params, 3, false);
  value = LLVMAddFunction(c->module, "pony_deserialise_offset", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#elif PONY_LLVM == 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#endif

  // i8* pony_deserialise_block(i8*, intptr, intptr)
  params[0] = c->void_ptr;
  params[1] = c->intptr;
  params[2] = c->intptr;
  type = LLVMFunctionType(c->void_ptr, params, 3, false);
  value = LLVMAddFunction(c->module, "pony_deserialise_block", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeReturnIndex, noalias_attr);
#else
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
  LLVMSetReturnNoAlias(value);
#endif

  // i32 pony_init(i32, i8**)
  params[0] = c->i32;
  params[1] = LLVMPointerType(c->void_ptr, 0);
  type = LLVMFunctionType(c->i32, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_init", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
#endif

  // void pony_become(i8*, __object*)
  params[0] = c->void_ptr;
  params[1] = c->object_ptr;
  type = LLVMFunctionType(c->void_type, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_become", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
#endif

  // i32 pony_start(i32, i32)
  params[0] = c->i32;
  params[1] = c->i32;
  type = LLVMFunctionType(c->i32, params, 2, false);
  value = LLVMAddFunction(c->module, "pony_start", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex,
    inacc_or_arg_mem_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
#  if PONY_LLVM >= 308
  LLVMSetInaccessibleMemOrArgMemOnly(value);
#  endif
#endif

  // i32 pony_get_exitcode()
  type = LLVMFunctionType(c->i32, NULL, 0, false);
  value = LLVMAddFunction(c->module, "pony_get_exitcode", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, readonly_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
  LLVMAddFunctionAttr(value, LLVMReadOnlyAttribute);
#endif

  // void pony_throw()
  type = LLVMFunctionType(c->void_type, NULL, 0, false);
  value = LLVMAddFunction(c->module, "pony_throw", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, noreturn_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoReturnAttribute);
#endif

  // i32 pony_personality_v0(...)
  type = LLVMFunctionType(c->i32, NULL, 0, true);
  c->personality = LLVMAddFunction(c->module, "pony_personality_v0", type);

  // i32 memcmp(i8*, i8*, intptr)
  params[0] = c->void_ptr;
  params[1] = c->void_ptr;
  params[2] = c->intptr;
  type = LLVMFunctionType(c->i32, params, 3, false);
  value = LLVMAddFunction(c->module, "memcmp", type);
#if PONY_LLVM >= 309
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, nounwind_attr);
  LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, readonly_attr);
  LLVMAddAttributeAtIndex(value, 1, readonly_attr);
  LLVMAddAttributeAtIndex(value, 2, readonly_attr);
#else
  LLVMAddFunctionAttr(value, LLVMNoUnwindAttribute);
  LLVMAddFunctionAttr(value, LLVMReadOnlyAttribute);
  LLVMValueRef param = LLVMGetParam(value, 0);
  LLVMAddAttribute(param, LLVMReadOnlyAttribute);
  param = LLVMGetParam(value, 1);
  LLVMAddAttribute(param, LLVMReadOnlyAttribute);
#endif
}
Ejemplo n.º 6
0
LLVMValueRef get_struct_fn(
	struct llvm_ctx *ctx,
	IDL_tree ctyp,
	bool for_encode)
{
	const char *s_id = IDL_IDENT(IDL_TYPE_STRUCT(ctyp).ident).repo_id;
	char *lookup_name = talloc_asprintf(ctx, "%c%s",
		for_encode ? 'e' : 'd', s_id);
	LLVMValueRef fn = strmap_get(&ctx->struct_decoder_fns, lookup_name);
	if(fn != NULL) {
		talloc_free(lookup_name);
		return fn;
	}

	const struct packed_format *fmt = packed_format_of(ctyp);
	assert(fmt != NULL);	/* only sane for packable structs */
	int namelen = strlen(s_id);
	char flatname[namelen + 1];
	/* FIXME: make this proper, i.e. use a name mangler that works */
	for(int i=0; i < namelen; i++) {
		flatname[i] = isalnum(s_id[i]) ? s_id[i] : '_';
	}
	flatname[namelen] = '\0';
	T types[3], rettyp = LLVMVoidTypeInContext(ctx->ctx);
	types[0] = LLVMPointerType(llvm_rigid_type(ctx, ctyp), 0);
	int nparms;
	if(!for_encode) {
		/* decoder */
		types[1] = ctx->i32t;
		types[2] = ctx->i32t;
		nparms = fmt->num_bits < BITS_PER_WORD ? 3 : 2;
	} else if(fmt->num_bits < BITS_PER_WORD) {
		/* subword encoder */
		rettyp = ctx->wordt;
		types[1] = ctx->wordt;
		types[2] = ctx->i32t;
		nparms = 3;
	} else {
		/* non-subword encoder */
		types[1] = ctx->i32t;
		nparms = 2;
	}
	T fntype = LLVMFunctionType(rettyp, types, nparms, 0);
	char *fnname = g_strdup_printf("__muidl_idl_%scode__%s",
		for_encode ? "en" : "de", flatname);
	fn = LLVMAddFunction(ctx->module, fnname, fntype);
	LLVMSetLinkage(fn, LLVMExternalLinkage);
	V params[nparms];
	assert(LLVMCountParams(fn) == nparms);
	LLVMGetParams(fn, params);
	LLVMAddAttribute(params[0], LLVMNoAliasAttribute);
	LLVMAddAttribute(params[0], LLVMNoCaptureAttribute);
	for(int i=0; i<nparms; i++) {
		LLVMAddAttribute(params[i], LLVMInRegAttribute);
	}
	g_free(fnname);
	bool ok = strmap_add(&ctx->struct_decoder_fns, lookup_name, fn);
	assert(ok || errno != EEXIST);

	return fn;
}
Ejemplo n.º 7
0
/**
 * Generate the runtime callable function for the whole fragment pipeline.
 * Note that the function which we generate operates on a block of 16
 * pixels at at time.  The block contains 2x2 quads.  Each quad contains
 * 2x2 pixels.
 */
static void
generate_fragment(struct llvmpipe_context *lp,
                  struct lp_fragment_shader *shader,
                  struct lp_fragment_shader_variant *variant,
                  unsigned do_tri_test)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
   const struct lp_fragment_shader_variant_key *key = &variant->key;
   struct lp_type fs_type;
   struct lp_type blend_type;
   LLVMTypeRef fs_elem_type;
   LLVMTypeRef fs_vec_type;
   LLVMTypeRef fs_int_vec_type;
   LLVMTypeRef blend_vec_type;
   LLVMTypeRef blend_int_vec_type;
   LLVMTypeRef arg_types[14];
   LLVMTypeRef func_type;
   LLVMTypeRef int32_vec4_type = lp_build_int32_vec4_type();
   LLVMValueRef context_ptr;
   LLVMValueRef x;
   LLVMValueRef y;
   LLVMValueRef a0_ptr;
   LLVMValueRef dadx_ptr;
   LLVMValueRef dady_ptr;
   LLVMValueRef color_ptr_ptr;
   LLVMValueRef depth_ptr;
   LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr;
   LLVMBasicBlockRef block;
   LLVMBuilderRef builder;
   LLVMValueRef x0;
   LLVMValueRef y0;
   struct lp_build_sampler_soa *sampler;
   struct lp_build_interp_soa_context interp;
   LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH];
   LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
   LLVMValueRef blend_mask;
   LLVMValueRef blend_in_color[NUM_CHANNELS];
   LLVMValueRef function;
   unsigned num_fs;
   unsigned i;
   unsigned chan;
   unsigned cbuf;


   /* TODO: actually pick these based on the fs and color buffer
    * characteristics. */

   memset(&fs_type, 0, sizeof fs_type);
   fs_type.floating = TRUE; /* floating point values */
   fs_type.sign = TRUE;     /* values are signed */
   fs_type.norm = FALSE;    /* values are not limited to [0,1] or [-1,1] */
   fs_type.width = 32;      /* 32-bit float */
   fs_type.length = 4;      /* 4 elements per vector */
   num_fs = 4;              /* number of quads per block */

   memset(&blend_type, 0, sizeof blend_type);
   blend_type.floating = FALSE; /* values are integers */
   blend_type.sign = FALSE;     /* values are unsigned */
   blend_type.norm = TRUE;      /* values are in [0,1] or [-1,1] */
   blend_type.width = 8;        /* 8-bit ubyte values */
   blend_type.length = 16;      /* 16 elements per vector */

   /* 
    * Generate the function prototype. Any change here must be reflected in
    * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
    */

   fs_elem_type = lp_build_elem_type(fs_type);
   fs_vec_type = lp_build_vec_type(fs_type);
   fs_int_vec_type = lp_build_int_vec_type(fs_type);

   blend_vec_type = lp_build_vec_type(blend_type);
   blend_int_vec_type = lp_build_int_vec_type(blend_type);

   arg_types[0] = screen->context_ptr_type;            /* context */
   arg_types[1] = LLVMInt32Type();                     /* x */
   arg_types[2] = LLVMInt32Type();                     /* y */
   arg_types[3] = LLVMPointerType(fs_elem_type, 0);    /* a0 */
   arg_types[4] = LLVMPointerType(fs_elem_type, 0);    /* dadx */
   arg_types[5] = LLVMPointerType(fs_elem_type, 0);    /* dady */
   arg_types[6] = LLVMPointerType(LLVMPointerType(blend_vec_type, 0), 0);  /* color */
   arg_types[7] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
   arg_types[8] = LLVMInt32Type();                     /* c0 */
   arg_types[9] = LLVMInt32Type();                     /* c1 */
   arg_types[10] = LLVMInt32Type();                    /* c2 */
   /* Note: the step arrays are built as int32[16] but we interpret
    * them here as int32_vec4[4].
    */
   arg_types[11] = LLVMPointerType(int32_vec4_type, 0);/* step0 */
   arg_types[12] = LLVMPointerType(int32_vec4_type, 0);/* step1 */
   arg_types[13] = LLVMPointerType(int32_vec4_type, 0);/* step2 */

   func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);

   function = LLVMAddFunction(screen->module, "shader", func_type);
   LLVMSetFunctionCallConv(function, LLVMCCallConv);

   variant->function[do_tri_test] = function;


   /* XXX: need to propagate noalias down into color param now we are
    * passing a pointer-to-pointer?
    */
   for(i = 0; i < Elements(arg_types); ++i)
      if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
         LLVMAddAttribute(LLVMGetParam(function, i), LLVMNoAliasAttribute);

   context_ptr  = LLVMGetParam(function, 0);
   x            = LLVMGetParam(function, 1);
   y            = LLVMGetParam(function, 2);
   a0_ptr       = LLVMGetParam(function, 3);
   dadx_ptr     = LLVMGetParam(function, 4);
   dady_ptr     = LLVMGetParam(function, 5);
   color_ptr_ptr = LLVMGetParam(function, 6);
   depth_ptr    = LLVMGetParam(function, 7);
   c0           = LLVMGetParam(function, 8);
   c1           = LLVMGetParam(function, 9);
   c2           = LLVMGetParam(function, 10);
   step0_ptr    = LLVMGetParam(function, 11);
   step1_ptr    = LLVMGetParam(function, 12);
   step2_ptr    = LLVMGetParam(function, 13);

   lp_build_name(context_ptr, "context");
   lp_build_name(x, "x");
   lp_build_name(y, "y");
   lp_build_name(a0_ptr, "a0");
   lp_build_name(dadx_ptr, "dadx");
   lp_build_name(dady_ptr, "dady");
   lp_build_name(color_ptr_ptr, "color_ptr");
   lp_build_name(depth_ptr, "depth");
   lp_build_name(c0, "c0");
   lp_build_name(c1, "c1");
   lp_build_name(c2, "c2");
   lp_build_name(step0_ptr, "step0");
   lp_build_name(step1_ptr, "step1");
   lp_build_name(step2_ptr, "step2");

   /*
    * Function body
    */

   block = LLVMAppendBasicBlock(function, "entry");
   builder = LLVMCreateBuilder();
   LLVMPositionBuilderAtEnd(builder, block);

   generate_pos0(builder, x, y, &x0, &y0);

   lp_build_interp_soa_init(&interp, 
                            shader->base.tokens,
                            key->flatshade,
                            builder, fs_type,
                            a0_ptr, dadx_ptr, dady_ptr,
                            x0, y0);

   /* code generated texture sampling */
   sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);

   /* loop over quads in the block */
   for(i = 0; i < num_fs; ++i) {
      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
      LLVMValueRef out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS];
      LLVMValueRef depth_ptr_i;
      int cbuf;

      if(i != 0)
         lp_build_interp_soa_update(&interp, i);

      depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");

      generate_fs(lp, shader, key,
                  builder,
                  fs_type,
                  context_ptr,
                  i,
                  &interp,
                  sampler,
                  &fs_mask[i], /* output */
                  out_color,
                  depth_ptr_i,
                  do_tri_test,
                  c0, c1, c2,
                  step0_ptr, step1_ptr, step2_ptr);

      for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++)
	 for(chan = 0; chan < NUM_CHANNELS; ++chan)
	    fs_out_color[cbuf][chan][i] = out_color[cbuf][chan];
   }

   sampler->destroy(sampler);

   /* Loop over color outputs / color buffers to do blending.
    */
   for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) {
      LLVMValueRef color_ptr;
      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), cbuf, 0);

      /* 
       * Convert the fs's output color and mask to fit to the blending type. 
       */
      for(chan = 0; chan < NUM_CHANNELS; ++chan) {
	 lp_build_conv(builder, fs_type, blend_type,
		       fs_out_color[cbuf][chan], num_fs,
		       &blend_in_color[chan], 1);
	 lp_build_name(blend_in_color[chan], "color%d.%c", cbuf, "rgba"[chan]);
      }

      lp_build_conv_mask(builder, fs_type, blend_type,
			 fs_mask, num_fs,
			 &blend_mask, 1);

      color_ptr = LLVMBuildLoad(builder, 
				LLVMBuildGEP(builder, color_ptr_ptr, &index, 1, ""),
				"");
      lp_build_name(color_ptr, "color_ptr%d", cbuf);

      /*
       * Blending.
       */
      generate_blend(&key->blend,
		     builder,
		     blend_type,
		     context_ptr,
		     blend_mask,
		     blend_in_color,
		     color_ptr);
   }

   LLVMBuildRetVoid(builder);

   LLVMDisposeBuilder(builder);


   /* Verify the LLVM IR.  If invalid, dump and abort */
#ifdef DEBUG
   if(LLVMVerifyFunction(function, LLVMPrintMessageAction)) {
      if (1)
         LLVMDumpValue(function);
      abort();
   }
#endif

   /* Apply optimizations to LLVM IR */
   if (1)
      LLVMRunFunctionPassManager(screen->pass, function);

   if (LP_DEBUG & DEBUG_JIT) {
      /* Print the LLVM IR to stderr */
      LLVMDumpValue(function);
      debug_printf("\n");
   }

   /*
    * Translate the LLVM IR into machine code.
    */
   variant->jit_function[do_tri_test] = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, function);

   if (LP_DEBUG & DEBUG_ASM)
      lp_disassemble(variant->jit_function[do_tri_test]);
}
Ejemplo n.º 8
0
/**
 * Generate the runtime callable function for the whole fragment pipeline.
 */
static struct lp_fragment_shader_variant *
generate_fragment(struct llvmpipe_context *lp,
                  struct lp_fragment_shader *shader,
                  const struct lp_fragment_shader_variant_key *key)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
   struct lp_fragment_shader_variant *variant;
   struct lp_type fs_type;
   struct lp_type blend_type;
   LLVMTypeRef fs_elem_type;
   LLVMTypeRef fs_vec_type;
   LLVMTypeRef fs_int_vec_type;
   LLVMTypeRef blend_vec_type;
   LLVMTypeRef blend_int_vec_type;
   LLVMTypeRef arg_types[9];
   LLVMTypeRef func_type;
   LLVMValueRef context_ptr;
   LLVMValueRef x;
   LLVMValueRef y;
   LLVMValueRef a0_ptr;
   LLVMValueRef dadx_ptr;
   LLVMValueRef dady_ptr;
   LLVMValueRef mask_ptr;
   LLVMValueRef color_ptr;
   LLVMValueRef depth_ptr;
   LLVMBasicBlockRef block;
   LLVMBuilderRef builder;
   LLVMValueRef x0;
   LLVMValueRef y0;
   struct lp_build_sampler_soa *sampler;
   struct lp_build_interp_soa_context interp;
   LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH];
   LLVMValueRef fs_out_color[NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
   LLVMValueRef blend_mask;
   LLVMValueRef blend_in_color[NUM_CHANNELS];
   unsigned num_fs;
   unsigned i;
   unsigned chan;

#ifdef DEBUG
   tgsi_dump(shader->base.tokens, 0);
   if(key->depth.enabled) {
      debug_printf("depth.format = %s\n", pf_name(key->zsbuf_format));
      debug_printf("depth.func = %s\n", debug_dump_func(key->depth.func, TRUE));
      debug_printf("depth.writemask = %u\n", key->depth.writemask);
   }
   if(key->alpha.enabled) {
      debug_printf("alpha.func = %s\n", debug_dump_func(key->alpha.func, TRUE));
      debug_printf("alpha.ref_value = %f\n", key->alpha.ref_value);
   }
   if(key->blend.logicop_enable) {
      debug_printf("blend.logicop_func = %u\n", key->blend.logicop_func);
   }
   else if(key->blend.blend_enable) {
      debug_printf("blend.rgb_func = %s\n",   debug_dump_blend_func  (key->blend.rgb_func, TRUE));
      debug_printf("rgb_src_factor = %s\n",   debug_dump_blend_factor(key->blend.rgb_src_factor, TRUE));
      debug_printf("rgb_dst_factor = %s\n",   debug_dump_blend_factor(key->blend.rgb_dst_factor, TRUE));
      debug_printf("alpha_func = %s\n",       debug_dump_blend_func  (key->blend.alpha_func, TRUE));
      debug_printf("alpha_src_factor = %s\n", debug_dump_blend_factor(key->blend.alpha_src_factor, TRUE));
      debug_printf("alpha_dst_factor = %s\n", debug_dump_blend_factor(key->blend.alpha_dst_factor, TRUE));
   }
   debug_printf("blend.colormask = 0x%x\n", key->blend.colormask);
   for(i = 0; i < PIPE_MAX_SAMPLERS; ++i) {
      if(key->sampler[i].format) {
         debug_printf("sampler[%u] = \n", i);
         debug_printf("  .format = %s\n",
                      pf_name(key->sampler[i].format));
         debug_printf("  .target = %s\n",
                      debug_dump_tex_target(key->sampler[i].target, TRUE));
         debug_printf("  .pot = %u %u %u\n",
                      key->sampler[i].pot_width,
                      key->sampler[i].pot_height,
                      key->sampler[i].pot_depth);
         debug_printf("  .wrap = %s %s %s\n",
                      debug_dump_tex_wrap(key->sampler[i].wrap_s, TRUE),
                      debug_dump_tex_wrap(key->sampler[i].wrap_t, TRUE),
                      debug_dump_tex_wrap(key->sampler[i].wrap_r, TRUE));
         debug_printf("  .min_img_filter = %s\n",
                      debug_dump_tex_filter(key->sampler[i].min_img_filter, TRUE));
         debug_printf("  .min_mip_filter = %s\n",
                      debug_dump_tex_mipfilter(key->sampler[i].min_mip_filter, TRUE));
         debug_printf("  .mag_img_filter = %s\n",
                      debug_dump_tex_filter(key->sampler[i].mag_img_filter, TRUE));
         if(key->sampler[i].compare_mode)
            debug_printf("  .compare_mode = %s\n", debug_dump_func(key->sampler[i].compare_func, TRUE));
         debug_printf("  .normalized_coords = %u\n", key->sampler[i].normalized_coords);
         debug_printf("  .prefilter = %u\n", key->sampler[i].prefilter);
      }
   }

#endif

   variant = CALLOC_STRUCT(lp_fragment_shader_variant);
   if(!variant)
      return NULL;

   variant->shader = shader;
   memcpy(&variant->key, key, sizeof *key);

   /* TODO: actually pick these based on the fs and color buffer
    * characteristics. */

   memset(&fs_type, 0, sizeof fs_type);
   fs_type.floating = TRUE; /* floating point values */
   fs_type.sign = TRUE;     /* values are signed */
   fs_type.norm = FALSE;    /* values are not limited to [0,1] or [-1,1] */
   fs_type.width = 32;      /* 32-bit float */
   fs_type.length = 4;      /* 4 element per vector */
   num_fs = 4;

   memset(&blend_type, 0, sizeof blend_type);
   blend_type.floating = FALSE; /* values are integers */
   blend_type.sign = FALSE;     /* values are unsigned */
   blend_type.norm = TRUE;      /* values are in [0,1] or [-1,1] */
   blend_type.width = 8;        /* 8-bit ubyte values */
   blend_type.length = 16;      /* 16 elements per vector */

   /* 
    * Generate the function prototype. Any change here must be reflected in
    * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
    */

   fs_elem_type = lp_build_elem_type(fs_type);
   fs_vec_type = lp_build_vec_type(fs_type);
   fs_int_vec_type = lp_build_int_vec_type(fs_type);

   blend_vec_type = lp_build_vec_type(blend_type);
   blend_int_vec_type = lp_build_int_vec_type(blend_type);

   arg_types[0] = screen->context_ptr_type;            /* context */
   arg_types[1] = LLVMInt32Type();                     /* x */
   arg_types[2] = LLVMInt32Type();                     /* y */
   arg_types[3] = LLVMPointerType(fs_elem_type, 0);    /* a0 */
   arg_types[4] = LLVMPointerType(fs_elem_type, 0);    /* dadx */
   arg_types[5] = LLVMPointerType(fs_elem_type, 0);    /* dady */
   arg_types[6] = LLVMPointerType(fs_int_vec_type, 0); /* mask */
   arg_types[7] = LLVMPointerType(blend_vec_type, 0);  /* color */
   arg_types[8] = LLVMPointerType(fs_int_vec_type, 0); /* depth */

   func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);

   variant->function = LLVMAddFunction(screen->module, "shader", func_type);
   LLVMSetFunctionCallConv(variant->function, LLVMCCallConv);
   for(i = 0; i < Elements(arg_types); ++i)
      if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
         LLVMAddAttribute(LLVMGetParam(variant->function, i), LLVMNoAliasAttribute);

   context_ptr  = LLVMGetParam(variant->function, 0);
   x            = LLVMGetParam(variant->function, 1);
   y            = LLVMGetParam(variant->function, 2);
   a0_ptr       = LLVMGetParam(variant->function, 3);
   dadx_ptr     = LLVMGetParam(variant->function, 4);
   dady_ptr     = LLVMGetParam(variant->function, 5);
   mask_ptr     = LLVMGetParam(variant->function, 6);
   color_ptr    = LLVMGetParam(variant->function, 7);
   depth_ptr    = LLVMGetParam(variant->function, 8);

   lp_build_name(context_ptr, "context");
   lp_build_name(x, "x");
   lp_build_name(y, "y");
   lp_build_name(a0_ptr, "a0");
   lp_build_name(dadx_ptr, "dadx");
   lp_build_name(dady_ptr, "dady");
   lp_build_name(mask_ptr, "mask");
   lp_build_name(color_ptr, "color");
   lp_build_name(depth_ptr, "depth");

   /*
    * Function body
    */

   block = LLVMAppendBasicBlock(variant->function, "entry");
   builder = LLVMCreateBuilder();
   LLVMPositionBuilderAtEnd(builder, block);

   generate_pos0(builder, x, y, &x0, &y0);

   lp_build_interp_soa_init(&interp, shader->base.tokens, builder, fs_type,
                            a0_ptr, dadx_ptr, dady_ptr,
                            x0, y0, 2, 0);

#if 0
   /* C texture sampling */
   sampler = lp_c_sampler_soa_create(context_ptr);
#else
   /* code generated texture sampling */
   sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);
#endif

   for(i = 0; i < num_fs; ++i) {
      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
      LLVMValueRef out_color[NUM_CHANNELS];
      LLVMValueRef depth_ptr_i;

      if(i != 0)
         lp_build_interp_soa_update(&interp);

      fs_mask[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, mask_ptr, &index, 1, ""), "");
      depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");

      generate_fs(lp, shader, key,
                  builder,
                  fs_type,
                  context_ptr,
                  i,
                  &interp,
                  sampler,
                  &fs_mask[i],
                  out_color,
                  depth_ptr_i);

      for(chan = 0; chan < NUM_CHANNELS; ++chan)
         fs_out_color[chan][i] = out_color[chan];
   }

   sampler->destroy(sampler);

   /* 
    * Convert the fs's output color and mask to fit to the blending type. 
    */

   for(chan = 0; chan < NUM_CHANNELS; ++chan) {
      lp_build_conv(builder, fs_type, blend_type,
                    fs_out_color[chan], num_fs,
                    &blend_in_color[chan], 1);
      lp_build_name(blend_in_color[chan], "color.%c", "rgba"[chan]);

   }

   lp_build_conv_mask(builder, fs_type, blend_type,
                               fs_mask, num_fs,
                               &blend_mask, 1);

   /*
    * Blending.
    */

   generate_blend(&key->blend,
                  builder,
                  blend_type,
                  context_ptr,
                  blend_mask,
                  blend_in_color,
                  color_ptr);

   LLVMBuildRetVoid(builder);

   LLVMDisposeBuilder(builder);

   /*
    * Translate the LLVM IR into machine code.
    */

   if(LLVMVerifyFunction(variant->function, LLVMPrintMessageAction)) {
      LLVMDumpValue(variant->function);
      abort();
   }

   LLVMRunFunctionPassManager(screen->pass, variant->function);

#ifdef DEBUG
   LLVMDumpValue(variant->function);
   debug_printf("\n");
#endif

   variant->jit_function = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, variant->function);

#ifdef DEBUG
   lp_disassemble(variant->jit_function);
#endif

   variant->next = shader->variants;
   shader->variants = variant;

   return variant;
}
Ejemplo n.º 9
0
/**
 * Generate the runtime callable function for the whole fragment pipeline.
 * Note that the function which we generate operates on a block of 16
 * pixels at at time.  The block contains 2x2 quads.  Each quad contains
 * 2x2 pixels.
 */
static void
generate_fragment(struct llvmpipe_context *lp,
                  struct lp_fragment_shader *shader,
                  struct lp_fragment_shader_variant *variant,
                  unsigned partial_mask)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
   const struct lp_fragment_shader_variant_key *key = &variant->key;
   char func_name[256];
   struct lp_type fs_type;
   struct lp_type blend_type;
   LLVMTypeRef fs_elem_type;
   LLVMTypeRef fs_int_vec_type;
   LLVMTypeRef blend_vec_type;
   LLVMTypeRef arg_types[11];
   LLVMTypeRef func_type;
   LLVMValueRef context_ptr;
   LLVMValueRef x;
   LLVMValueRef y;
   LLVMValueRef a0_ptr;
   LLVMValueRef dadx_ptr;
   LLVMValueRef dady_ptr;
   LLVMValueRef color_ptr_ptr;
   LLVMValueRef depth_ptr;
   LLVMValueRef mask_input;
   LLVMValueRef counter = NULL;
   LLVMBasicBlockRef block;
   LLVMBuilderRef builder;
   struct lp_build_sampler_soa *sampler;
   struct lp_build_interp_soa_context interp;
   LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH];
   LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
   LLVMValueRef blend_mask;
   LLVMValueRef function;
   LLVMValueRef facing;
   unsigned num_fs;
   unsigned i;
   unsigned chan;
   unsigned cbuf;


   /* TODO: actually pick these based on the fs and color buffer
    * characteristics. */

   memset(&fs_type, 0, sizeof fs_type);
   fs_type.floating = TRUE; /* floating point values */
   fs_type.sign = TRUE;     /* values are signed */
   fs_type.norm = FALSE;    /* values are not limited to [0,1] or [-1,1] */
   fs_type.width = 32;      /* 32-bit float */
   fs_type.length = 4;      /* 4 elements per vector */
   num_fs = 4;              /* number of quads per block */

   memset(&blend_type, 0, sizeof blend_type);
   blend_type.floating = FALSE; /* values are integers */
   blend_type.sign = FALSE;     /* values are unsigned */
   blend_type.norm = TRUE;      /* values are in [0,1] or [-1,1] */
   blend_type.width = 8;        /* 8-bit ubyte values */
   blend_type.length = 16;      /* 16 elements per vector */

   /* 
    * Generate the function prototype. Any change here must be reflected in
    * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
    */

   fs_elem_type = lp_build_elem_type(fs_type);
   fs_int_vec_type = lp_build_int_vec_type(fs_type);

   blend_vec_type = lp_build_vec_type(blend_type);

   util_snprintf(func_name, sizeof(func_name), "fs%u_variant%u_%s", 
		 shader->no, variant->no, partial_mask ? "partial" : "whole");

   arg_types[0] = screen->context_ptr_type;            /* context */
   arg_types[1] = LLVMInt32Type();                     /* x */
   arg_types[2] = LLVMInt32Type();                     /* y */
   arg_types[3] = LLVMFloatType();                     /* facing */
   arg_types[4] = LLVMPointerType(fs_elem_type, 0);    /* a0 */
   arg_types[5] = LLVMPointerType(fs_elem_type, 0);    /* dadx */
   arg_types[6] = LLVMPointerType(fs_elem_type, 0);    /* dady */
   arg_types[7] = LLVMPointerType(LLVMPointerType(blend_vec_type, 0), 0);  /* color */
   arg_types[8] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
   arg_types[9] = LLVMInt32Type();                     /* mask_input */
   arg_types[10] = LLVMPointerType(LLVMInt32Type(), 0);/* counter */

   func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);

   function = LLVMAddFunction(screen->module, func_name, func_type);
   LLVMSetFunctionCallConv(function, LLVMCCallConv);

   variant->function[partial_mask] = function;


   /* XXX: need to propagate noalias down into color param now we are
    * passing a pointer-to-pointer?
    */
   for(i = 0; i < Elements(arg_types); ++i)
      if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
         LLVMAddAttribute(LLVMGetParam(function, i), LLVMNoAliasAttribute);

   context_ptr  = LLVMGetParam(function, 0);
   x            = LLVMGetParam(function, 1);
   y            = LLVMGetParam(function, 2);
   facing       = LLVMGetParam(function, 3);
   a0_ptr       = LLVMGetParam(function, 4);
   dadx_ptr     = LLVMGetParam(function, 5);
   dady_ptr     = LLVMGetParam(function, 6);
   color_ptr_ptr = LLVMGetParam(function, 7);
   depth_ptr    = LLVMGetParam(function, 8);
   mask_input   = LLVMGetParam(function, 9);

   lp_build_name(context_ptr, "context");
   lp_build_name(x, "x");
   lp_build_name(y, "y");
   lp_build_name(a0_ptr, "a0");
   lp_build_name(dadx_ptr, "dadx");
   lp_build_name(dady_ptr, "dady");
   lp_build_name(color_ptr_ptr, "color_ptr_ptr");
   lp_build_name(depth_ptr, "depth");
   lp_build_name(mask_input, "mask_input");

   if (key->occlusion_count) {
      counter = LLVMGetParam(function, 10);
      lp_build_name(counter, "counter");
   }

   /*
    * Function body
    */

   block = LLVMAppendBasicBlock(function, "entry");
   builder = LLVMCreateBuilder();
   LLVMPositionBuilderAtEnd(builder, block);

   /*
    * The shader input interpolation info is not explicitely baked in the
    * shader key, but everything it derives from (TGSI, and flatshade) is
    * already included in the shader key.
    */
   lp_build_interp_soa_init(&interp, 
                            lp->num_inputs,
                            lp->inputs,
                            builder, fs_type,
                            a0_ptr, dadx_ptr, dady_ptr,
                            x, y);

   /* code generated texture sampling */
   sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);

   /* loop over quads in the block */
   for(i = 0; i < num_fs; ++i) {
      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
      LLVMValueRef out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS];
      LLVMValueRef depth_ptr_i;

      if(i != 0)
         lp_build_interp_soa_update(&interp, i);

      depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");

      generate_fs(lp, shader, key,
                  builder,
                  fs_type,
                  context_ptr,
                  i,
                  &interp,
                  sampler,
                  &fs_mask[i], /* output */
                  out_color,
                  depth_ptr_i,
                  facing,
                  partial_mask,
                  mask_input,
                  counter);

      for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++)
	 for(chan = 0; chan < NUM_CHANNELS; ++chan)
	    fs_out_color[cbuf][chan][i] = out_color[cbuf][chan];
   }

   sampler->destroy(sampler);

   /* Loop over color outputs / color buffers to do blending.
    */
   for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) {
      LLVMValueRef color_ptr;
      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), cbuf, 0);
      LLVMValueRef blend_in_color[NUM_CHANNELS];
      unsigned rt;

      /* 
       * Convert the fs's output color and mask to fit to the blending type. 
       */
      for(chan = 0; chan < NUM_CHANNELS; ++chan) {
	 lp_build_conv(builder, fs_type, blend_type,
		       fs_out_color[cbuf][chan], num_fs,
		       &blend_in_color[chan], 1);
	 lp_build_name(blend_in_color[chan], "color%d.%c", cbuf, "rgba"[chan]);
      }

      if (partial_mask || !variant->opaque) {
         lp_build_conv_mask(builder, fs_type, blend_type,
                            fs_mask, num_fs,
                            &blend_mask, 1);
      } else {
         blend_mask = lp_build_const_int_vec(blend_type, ~0);
      }

      color_ptr = LLVMBuildLoad(builder, 
				LLVMBuildGEP(builder, color_ptr_ptr, &index, 1, ""),
				"");
      lp_build_name(color_ptr, "color_ptr%d", cbuf);

      /* which blend/colormask state to use */
      rt = key->blend.independent_blend_enable ? cbuf : 0;

      /*
       * Blending.
       */
      generate_blend(&key->blend,
                     rt,
		     builder,
		     blend_type,
		     context_ptr,
		     blend_mask,
		     blend_in_color,
		     color_ptr);
   }

#ifdef PIPE_ARCH_X86
   /* Avoid corrupting the FPU stack on 32bit OSes. */
   lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0);
#endif

   LLVMBuildRetVoid(builder);

   LLVMDisposeBuilder(builder);


   /* Verify the LLVM IR.  If invalid, dump and abort */
#ifdef DEBUG
   if(LLVMVerifyFunction(function, LLVMPrintMessageAction)) {
      if (1)
         lp_debug_dump_value(function);
      abort();
   }
#endif

   /* Apply optimizations to LLVM IR */
   LLVMRunFunctionPassManager(screen->pass, function);

   if (gallivm_debug & GALLIVM_DEBUG_IR) {
      /* Print the LLVM IR to stderr */
      lp_debug_dump_value(function);
      debug_printf("\n");
   }

   /*
    * Translate the LLVM IR into machine code.
    */
   {
      void *f = LLVMGetPointerToGlobal(screen->engine, function);

      variant->jit_function[partial_mask] = (lp_jit_frag_func)pointer_to_func(f);

      if (gallivm_debug & GALLIVM_DEBUG_ASM) {
         lp_disassemble(f);
      }
      lp_func_delete_body(function);
   }
}