void decode_packed_struct_inline( struct llvm_ctx *ctx, LLVMValueRef dst, IDL_tree ctyp, LLVMValueRef first_mr, LLVMValueRef bit_offset) { const struct packed_format *fmt = packed_format_of(ctyp); assert(fmt != NULL); char **names = NULL; T s_type = llvm_struct_type(ctx, &names, ctyp); int names_len = 0; while(names[names_len] != NULL) names_len++; assert(names_len == fmt->num_items); assert(LLVMCountStructElementTypes(s_type) == names_len); T types[MAX(names_len, 1)]; LLVMGetStructElementTypes(s_type, types); int cur_word = 0; V wordval = NULL; for(int i=0; i<fmt->num_items; i++) { const struct packed_item *pi = fmt->items[i]; int field_ix = strv_lookup(names, pi->name); if(field_ix < 0) { fprintf(stderr, "%s: not the way to go.\n", __func__); abort(); } V start_mr = LLVMBuildAdd(ctx->builder, first_mr, CONST_INT(pi->word), tmp_f(ctx->pr, "%s.start.mr", pi->name)); V dstptr = LLVMBuildStructGEP(ctx->builder, dst, field_ix, tmp_f(ctx->pr, "%s.start.ptr", pi->name)); if(pi->dim > 1) { /* array types. TODO */ fprintf(stderr, "%s: struct-member arrays not implemented\n", __func__); abort(); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_STRUCT) { decode_packed_struct(ctx, &dstptr, pi->type, start_mr, CONST_INT(pi->bit)); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_UNION) { fprintf(stderr, "%s: union-member types not implemented\n", __func__); abort(); } else if(IS_LONGLONG_TYPE(pi->type)) { /* long long on a 32-bit architecture. can be #ifdef'd out for * 64-bit targets, where it'd be just a value type. */ V dtmp = NULL; build_read_ipc_parameter(ctx, &dtmp, pi->type, start_mr); LLVMBuildStore(ctx->builder, dtmp, dstptr); } else if(is_value_type(pi->type)) { /* word-size and smaller items. */ if(cur_word != pi->word || wordval == NULL) { cur_word = pi->word; V old_wv = wordval; wordval = build_ipc_input_val_ix(ctx, start_mr, tmp_f(ctx->pr, "st.word%d", pi->word)); if(old_wv == NULL) { /* shift it down, since we start at an offset. */ wordval = LLVMBuildLShr(ctx->builder, wordval, bit_offset, "st.bitoffs.shifted"); } } V subval = LLVMBuildLShr(ctx->builder, wordval, CONST_INT(pi->bit), tmp_f(ctx->pr, "st.word%d.shr%d", pi->word, pi->bit)); if(pi->len < BITS_PER_WORD) { subval = LLVMBuildAnd(ctx->builder, subval, CONST_WORD((1 << pi->len) - 1), tmp_f(ctx->pr, "st.word%d.s%d.m%d", pi->word, pi->bit, pi->len)); } subval = LLVMBuildTruncOrBitCast(ctx->builder, subval, types[field_ix], "st.val.cast"); LLVMBuildStore(ctx->builder, subval, dstptr); } else if(IS_MAPGRANT_TYPE(pi->type)) { /* two words, like peas in a pod */ assert(pi->bit == 0); build_read_ipc_parameter(ctx, &dstptr, pi->type, start_mr); } else { NOTDEFINED(pi->type); } } g_strfreev(names); }
LLVMValueRef encode_packed_struct_inline( struct llvm_ctx *ctx, LLVMValueRef first_mr_word, LLVMValueRef bit_offset, IDL_tree ctyp, LLVMValueRef src_base) { const struct packed_format *fmt = packed_format_of(ctyp); assert(fmt != NULL); /* for sub-word items, bit_offset is required. for word and larger ones it * is forbidden. */ assert(bit_offset == NULL || (fmt->num_bits < BITS_PER_WORD && fmt->num_words == 1)); assert(bit_offset != NULL || fmt->num_bits >= BITS_PER_WORD); char **names = NULL; T s_type = llvm_struct_type(ctx, &names, ctyp); int names_len = 0; while(names[names_len] != NULL) names_len++; assert(names_len == fmt->num_items); assert(LLVMCountStructElementTypes(s_type) == names_len); T types[MAX(names_len, 1)]; LLVMGetStructElementTypes(s_type, types); V wordval = CONST_WORD(0); int cur_word = 0, wordval_fill = 0; for(int i=0; i<fmt->num_items; i++) { assert(wordval_fill <= BITS_PER_WORD); const struct packed_item *pi = fmt->items[i]; assert(bit_offset == NULL || pi->word == 0); int field_ix = strv_lookup(names, pi->name); if(field_ix < 0) { fprintf(stderr, "%s: not the way to go.\n", __func__); abort(); } V start_mr = NULL; if(bit_offset == NULL) { start_mr = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(pi->word), "word.ix"); } /* flush previous word? */ if(wordval_fill > 0 && cur_word != pi->word) { assert(bit_offset == NULL); V mr_ix = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(cur_word), tmp_f(ctx->pr, "flush.w%d.ix", cur_word)); LLVMBuildStore(ctx->builder, wordval, UTCB_ADDR_VAL(ctx, mr_ix, tmp_f(ctx->pr, "flush.w%d.addr", cur_word))); wordval = CONST_WORD(0); wordval_fill = 0; cur_word = pi->word; } V valptr = LLVMBuildStructGEP(ctx->builder, src_base, field_ix, tmp_f(ctx->pr, "%s.start.ptr", pi->name)); if(pi->dim > 1) { /* array types. TODO */ fprintf(stderr, "%s: struct-member arrays not implemented\n", __func__); abort(); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_STRUCT) { if(pi->len < BITS_PER_WORD) { wordval = encode_packed_struct(ctx, wordval, CONST_INT(pi->bit), pi->type, valptr); wordval_fill = (wordval_fill + pi->len) % BITS_PER_WORD; } else { encode_packed_struct(ctx, start_mr, NULL, pi->type, valptr); } } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_UNION) { fprintf(stderr, "%s: union-member types not implemented\n", __func__); abort(); } else if(IS_LONGLONG_TYPE(pi->type)) { assert(bit_offset == NULL); assert(pi->bit == 0 && wordval_fill == 0); V val = LLVMBuildLoad(ctx->builder, valptr, "longlong.fld"); build_write_ipc_parameter(ctx, start_mr, pi->type, &val); } else if(is_value_type(pi->type)) { /* word-size and smaller items. */ V val = LLVMBuildLoad(ctx->builder, valptr, tmp_f(ctx->pr, "fld.%s.val", pi->name)); val = LLVMBuildZExtOrBitCast(ctx->builder, val, ctx->wordt, tmp_f(ctx->pr, "fld.%s.word", pi->name)); V bitoffs = CONST_INT(pi->bit); V shifted = LLVMBuildShl(ctx->builder, val, bitoffs, tmp_f(ctx->pr, "fld.%s.shifted", pi->name)); wordval = LLVMBuildOr(ctx->builder, shifted, wordval, tmp_f(ctx->pr, "word%d.%s.merged", cur_word, pi->name)); wordval_fill += pi->len; } else if(IS_MAPGRANT_TYPE(pi->type)) { assert(bit_offset == NULL); assert(pi->bit == 0 && wordval_fill == 0); build_write_ipc_parameter(ctx, start_mr, pi->type, &valptr); } else { NOTDEFINED(pi->type); } } if(bit_offset == NULL && wordval_fill > 0) { /* flush final partial word if the last item was sub-word */ V mr_ix = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(cur_word), tmp_f(ctx->pr, "flush.w%d.ix", cur_word)); LLVMBuildStore(ctx->builder, wordval, UTCB_ADDR_VAL(ctx, mr_ix, tmp_f(ctx->pr, "flush.w%d.addr", cur_word))); wordval = NULL; } else if(bit_offset != NULL) { /* shift and merge */ wordval = LLVMBuildOr(ctx->builder, first_mr_word, LLVMBuildShl(ctx->builder, wordval, bit_offset, "short.shifted"), "rv.merged"); } g_strfreev(names); return wordval; }
bool operator()(Qualified_type const& t) { return is_value_type(t.type()); }