static tsf_bool_t generate_converter()

in benchmarks/JetStream2/wasm/TSF/tsf_gpc_code_gen.c [1829:2887]


static tsf_bool_t generate_converter(gpc_proto_t *proto,
                                     tsf_type_t *dest_type,
                                     tsf_type_t *src_type,
                                     gpc_cell_t dest_offset,
                                     gpc_cell_t src_offset,
                                     gpc_cell_t label) {
    uint32_t i;
    gpc_cell_t done_label,really_done_label;
    gpc_cell_t loop_label;
    gpc_cell_t label_offset;
    gpc_cell_t *targets;
    tsf_bool_t result;
    
    if (dest_type->kind_code == TSF_TK_VOID) {
        return tsf_true;
    }
    
    if (!tsf_type_instanceof(src_type, dest_type)) {
	C(generate_set_default_copier(proto, dest_type, dest_offset));
    }
    
    /* reason why we don't memcpy primitives: if we see a primitive at
       this point, then it is just one word - so a primitive copy
       operation will be faster than memcpy.
       
       interestingly, if we see a struct that contains exactly one
       primitive, we will still use memcpy (unless it is a byte).  this
       is not optimal, but oh well. */
    if (!tsf_type_kind_is_primitive(tsf_type_get_kind_code(src_type)) &&
        tsf_native_type_can_blit(dest_type,src_type)) {
        switch (tsf_native_type_get_size(src_type)) {
	case 0:
	    break;
	case 1:
	    C(append(proto,
		     GPC_I_COPY_C,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    C(append(proto,
		     GPC_I_MEMCPY,
		     dest_offset,
		     src_offset,
		     tsf_native_type_get_size(src_type)));
	    break;
        }
        return tsf_true;
    }
    
    switch (src_type->kind_code) {
    case TSF_TK_BIT:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    tsf_abort("bit-to-bit copies should have been handled elsewhere");
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_BIT_TO_S,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_BIT_TO_L,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_BIT_TO_LL,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_BIT_TO_F,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_BIT_TO_D,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_INT8:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_C,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_C_TO_S_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_C_TO_L_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_C_TO_LL_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_C_TO_F_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_C_TO_D_E,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_UINT8:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_C,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_C_TO_S_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_C_TO_L_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_C_TO_LL_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_C_TO_F_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_C_TO_D_Z,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_INT16:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_S_TO_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_S_TO_C,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_S,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_S_TO_L_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_S_TO_LL_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_S_TO_F_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_S_TO_D_E,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_UINT16:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_S_TO_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_S_TO_C,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_S,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_S_TO_L_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_S_TO_LL_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_S_TO_F_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_S_TO_D_Z,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_INT32:
    case TSF_TK_INTEGER:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_L_TO_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_L_TO_C,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_L_TO_S,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_L,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_L_TO_LL_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_L_TO_F_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_L_TO_D_E,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_UINT32:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_L_TO_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_L_TO_C,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_L_TO_S,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_L,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_L_TO_LL_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_L_TO_F_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_L_TO_D_Z,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_INT64:
    case TSF_TK_LONG:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_C,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_S,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_L,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_LL,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_F_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_D_E,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_UINT64:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_C,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_S,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
	case TSF_TK_UINT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_L,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
	case TSF_TK_UINT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_LL,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_F_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_LL_TO_D_Z,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_FLOAT:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_F_TO_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_F_TO_C_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	    C(append(proto,
		     GPC_I_COPY_F_TO_C_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_F_TO_S_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	    C(append(proto,
		     GPC_I_COPY_F_TO_S_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_UINT32:
	    C(append(proto,
		     GPC_I_COPY_F_TO_L_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_F_TO_L_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_UINT64:
	    C(append(proto,
		     GPC_I_COPY_F_TO_LL_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_F_TO_LL_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_F,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_F_TO_D,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_DOUBLE:
	switch (dest_type->kind_code) {
	case TSF_TK_BIT:
	    C(append(proto,
		     GPC_I_COPY_D_TO_BIT,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_UINT8:
	    C(append(proto,
		     GPC_I_COPY_D_TO_C_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT8:
	    C(append(proto,
		     GPC_I_COPY_D_TO_C_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_UINT16:
	    C(append(proto,
		     GPC_I_COPY_D_TO_S_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT16:
	    C(append(proto,
		     GPC_I_COPY_D_TO_S_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_UINT32:
	    C(append(proto,
		     GPC_I_COPY_D_TO_L_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT32:
        case TSF_TK_INTEGER:
	    C(append(proto,
		     GPC_I_COPY_D_TO_L_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_UINT64:
	    C(append(proto,
		     GPC_I_COPY_D_TO_LL_Z,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_INT64:
        case TSF_TK_LONG:
	    C(append(proto,
		     GPC_I_COPY_D_TO_LL_E,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_FLOAT:
	    C(append(proto,
		     GPC_I_COPY_D_TO_F,
		     dest_offset,
		     src_offset));
	    break;
	case TSF_TK_DOUBLE:
	    C(append(proto,
		     GPC_I_COPY_D,
		     dest_offset,
		     src_offset));
	    break;
	default:
	    tsf_abort("Bad src_type/dest_type combination; "
		      "should have been caught by "
		      "tsf_type_instanceof()");
	    break;
	}
	break;
    case TSF_TK_STRUCT:
        if (dest_type->u.s.constructor != NULL ||
            dest_type->u.s.pre_destructor != NULL) {
            /* This could be optimized by adding I_CALL_2ND and I_ADD_CBACK_2ND. I don't think
               it's worth it. */
            
            C(append(proto, GPC_I_DUP_PTR_2ND));
            if (dest_type->u.s.constructor != NULL) {
                C(append(proto, GPC_I_CALL,
                         dest_offset,
                         dest_type->u.s.constructor));
            }
            if (dest_type->u.s.pre_destructor != NULL) {
                C(append(proto, GPC_I_ADD_CBACK,
                         dest_offset,
                         dest_type->u.s.pre_destructor));
            }
            C(append(proto, GPC_I_POP));
        }

	for (i = 0; i < tsf_struct_type_get_num_elements(dest_type); ++i) {
	    tsf_named_type_t *n =
		tsf_struct_type_get_element(dest_type, i);
                
	    tsf_named_type_t *n2 =
		tsf_struct_type_find_node(src_type, n->name);
	    
	    if (n2 == NULL) {
		C(generate_set_default_copier(
                      proto, n->type, dest_offset + n->offset));
	    } else {
		C(generate_converter(proto,
				     n->type,
				     n2->type,
				     dest_offset + n->offset,
				     src_offset + n2->offset,
				     label));
	    }
	}
	break;
    case TSF_TK_ARRAY:
	if (dest_type->u.a.element_type->kind_code == TSF_TK_VOID) {
	    C(append(proto,
		     GPC_I_COPY_L,
		     (gpc_cell_t)(dest_offset +
                                  tsf_offsetof(tsf_native_void_array_t, len)),
		     (gpc_cell_t)(src_offset +
                                  src_type->u.a.element_type->kind_code == TSF_TK_VOID
                                  ? tsf_offsetof(tsf_native_void_array_t, len)
                                  : (src_type->u.a.element_type->kind_code == TSF_TK_BIT
                                     ? tsf_offsetof(tsf_native_bitvector_t, num_bits)
                                     : tsf_offsetof(tsf_native_array_t, len)))));
	} else if (dest_type->u.a.element_type->kind_code == TSF_TK_BIT) {
	    switch (src_type->u.a.element_type->kind_code) {
	    case TSF_TK_BIT:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_UINT8:
	    case TSF_TK_INT8:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_FROM_C,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_UINT16:
	    case TSF_TK_INT16:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_FROM_S,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_UINT32:
	    case TSF_TK_INT32:
            case TSF_TK_INTEGER:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_FROM_L,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_UINT64:
	    case TSF_TK_INT64:
            case TSF_TK_LONG:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_FROM_LL,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_FLOAT:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_FROM_F,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_DOUBLE:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_FROM_D,
			 dest_offset,
			 src_offset));
		break;
	    default:
		tsf_abort("case missed");
		break;
	    }
	} else if (src_type->u.a.element_type->kind_code == TSF_TK_BIT) {
	    switch (dest_type->u.a.element_type->kind_code) {
	    case TSF_TK_UINT8:
	    case TSF_TK_INT8:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_TO_C,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_UINT16:
	    case TSF_TK_INT16:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_TO_S,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_UINT32:
	    case TSF_TK_INT32:
            case TSF_TK_INTEGER:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_TO_L,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_UINT64:
	    case TSF_TK_INT64:
            case TSF_TK_LONG:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_TO_LL,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_FLOAT:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_TO_F,
			 dest_offset,
			 src_offset));
		break;
	    case TSF_TK_DOUBLE:
		C(append(proto,
			 GPC_I_COPY_BITVECTOR_TO_D,
			 dest_offset,
			 src_offset));
		break;
	    default:
		tsf_abort("case missed");
	    }
	} else if (tsf_native_type_can_blit(dest_type->u.a.element_type,
					    src_type->u.a.element_type) &&
		   tsf_native_type_get_size(dest_type->u.a.element_type) ==
		   tsf_native_type_get_size(src_type->u.a.element_type)) {
	    C(append(proto,
		     GPC_I_COPY_ARRAY,
		     dest_offset,
		     src_offset,
		     tsf_native_type_get_size(dest_type->u.a.element_type)));
	} else {
	    loop_label = label++;
	    done_label = label++;
                
	    C(append(proto,
		     GPC_I_COPY_L,
		     dest_offset + tsf_offsetof(tsf_native_array_t, len),
		     src_offset + tsf_offsetof(tsf_native_array_t, len)));
	    C(append(proto,
		     GPC_I_ALLOC_ARRAY_2ND,
		     dest_offset,
		     tsf_native_type_get_size(dest_type->u.a.element_type)));
	    C(append(proto,
		     GPC_I_REPUSH_MULADD_PTR_2ND,
		     dest_offset + tsf_offsetof(tsf_native_array_t, len),
		     tsf_native_type_get_size(dest_type->u.a.element_type)));
	    C(append(proto,
		     GPC_I_PUSH_PTR_3RD,
		     src_offset + tsf_offsetof(tsf_native_array_t, data)));
	    C(append(proto,
		     GPC_I_COMPFAILJUMP_2ND,
		     done_label));
	    C(append(proto,GPC_I_LABEL, loop_label));
	    C(generate_converter(proto,
				 dest_type->u.a.element_type,
				 src_type->u.a.element_type,
				 0,
				 0,
				 label));
	    C(append(proto,
		     GPC_I_TWO_ADDCOMPJUMP,
		     tsf_native_type_get_size(dest_type->u.a.element_type),
		     tsf_native_type_get_size(src_type->u.a.element_type),
		     loop_label));
	    C(append(proto, GPC_I_LABEL, done_label));
	    C(append(proto, GPC_I_THREE_POP));
	}
	break;
    case TSF_TK_CHOICE:
	targets=malloc(sizeof(gpc_cell_t) *
		       tsf_choice_type_get_num_elements(src_type));
	if (targets == NULL) {
	    tsf_set_errno("Could not malloc array of "
			  "gpc_cell_t");
	    return tsf_false;
	}
	if (tsf_choice_type_has_non_void(src_type)) {
	    label_offset = label;
	    label += tsf_choice_type_get_num_elements(src_type);
	    done_label = label++;
	    really_done_label = label++;
	    for (i = 0; i < tsf_choice_type_get_num_elements(src_type); ++i) {
		targets[i] = label_offset + i;
	    }
	    result = append_tablejump_field(
                proto,
                src_offset + src_type->u.h.value_offset,
                tsf_choice_type_get_num_elements(src_type),
                targets);
	    free(targets);
	    if (!result) {
		return tsf_false;
	    }
	    C(append(proto,
		     GPC_I_SET_2ND_L,
		     (gpc_cell_t)(dest_offset + dest_type->u.h.value_offset),
		     (gpc_cell_t)UINT32_MAX));
	    C(append(proto, GPC_I_JUMP, really_done_label));
	    for (i = 0; i < tsf_choice_type_get_num_elements(src_type); ++i) {
		tsf_named_type_t *sn =
		    tsf_choice_type_get_element(src_type, i);
		tsf_named_type_t *dn =
		    tsf_choice_type_find_node(dest_type, sn->name);
		C(append(proto, GPC_I_LABEL, label_offset + i));
		if (dn == NULL) {
		    C(append(proto,
			     GPC_I_SET_2ND_L,
			     (gpc_cell_t)(dest_offset + dest_type->u.h.value_offset),
			     (gpc_cell_t)UINT32_MAX));
		    C(append(proto, GPC_I_JUMP, really_done_label));
		} else {
		    C(append(proto,
			     GPC_I_SET_2ND_L,
			     (gpc_cell_t)(dest_offset + dest_type->u.h.value_offset),
			     (gpc_cell_t)dn->index));
		    if (!tsf_native_choice_type_is_in_place(src_type) ||
			!tsf_native_choice_type_is_in_place(dest_type)) {
			uint32_t src_off = 0;
			uint32_t dest_off = 0;
			if (tsf_native_choice_type_is_in_place(dest_type)) {
			    C(append(proto, GPC_I_DUP_PTR_2ND));
			    dest_off = dest_offset +
				dest_type->u.h.data_offset;
			} else {
			    /* must alloc */
			    C(append(proto, GPC_I_ALLOC,
				     tsf_native_type_get_size(dn->type)));
			    C(append(proto, GPC_I_STORE_PTR_2ND,
				     dest_offset +
				     dest_type->u.h.data_offset));
			}
			if (tsf_native_choice_type_is_in_place(src_type)) {
			    C(append(proto, GPC_I_DUP_PTR_2ND));
			    src_off = src_offset +
				src_type->u.h.data_offset;
			} else {
			    /* just load */
			    C(append(proto, GPC_I_PUSH_PTR_2ND,
				     src_offset +
				     src_type->u.h.data_offset));
			}
			C(generate_converter(proto,
					     dn->type,
					     sn->type,
					     dest_off,
					     src_off,
					     label));
			C(append(proto, GPC_I_JUMP, done_label));
		    } else {
			C(generate_converter(proto,
					     dn->type,
					     sn->type,
					     dest_offset +
					     dest_type->u.h.data_offset,
					     src_offset +
					     src_type->u.h.data_offset,
					     label));
			C(append(proto, GPC_I_JUMP, really_done_label));
		    }
		}
	    }
	    C(append(proto, GPC_I_LABEL, done_label));
	    if (!tsf_native_choice_type_is_in_place(src_type) ||
		!tsf_native_choice_type_is_in_place(dest_type)) {
		C(append(proto, GPC_I_TWO_POP));
	    }
	    C(append(proto, GPC_I_LABEL, really_done_label));
	} else {
	    for (i = 0; i < tsf_choice_type_get_num_elements(src_type); ++i) {
		tsf_named_type_t *sn =
		    tsf_choice_type_get_element(src_type, i);
		tsf_named_type_t *dn =
		    tsf_choice_type_find_node(dest_type, sn->name);
		if (dn == NULL) {
		    targets[i] = UINT32_MAX;
		} else {
		    targets[i] = dn->index;
		}
	    }
	    result = append_tableset_field_to_field(
                proto,
                dest_offset + dest_type->u.h.value_offset,
                src_offset + src_type->u.h.value_offset,
                tsf_choice_type_get_num_elements(src_type),
                targets);
	    free(targets);
	    if (!result) {
		return tsf_false;
	    }
	}
	break;
    case TSF_TK_STRING:
	C(append(proto,
		 GPC_I_STRING_COPY,
		 dest_offset,
		 src_offset));
	break;
    case TSF_TK_ANY:
	C(append(proto,
		 GPC_I_ANY_COPY,
		 dest_offset,
		 src_offset));
	break;
    default:
	tsf_abort("Bad type.");
	break;
    }

    return tsf_true;
}