Example #1
0
static TYPE_DESC
get_intrinsic_return_type(intrinsic_entry *ep, expv args, expv kindV) {
    BASIC_DATA_TYPE bType = TYPE_UNKNOWN;
    TYPE_DESC bTypeDsc = NULL;
    TYPE_DESC ret = NULL;
    expv a = NULL;
    
    if (INTR_RETURN_TYPE(ep) == INTR_TYPE_NONE) {
        return NULL;
    }

    if (INTR_RETURN_TYPE_SAME_AS(ep) >= 0) {
        /* return type is in args. */
        a = expr_list_get_n(args, INTR_RETURN_TYPE_SAME_AS(ep));
        if (!(isValidTypedExpv(a))) {
            return NULL;
        }
        ret = EXPV_TYPE(a);
    } else {
        switch (INTR_RETURN_TYPE_SAME_AS(ep)) {

            case -1 /* if not dynamic return type,
                        argument is scalar/array and
                        return type is scalar/array */ :
            case -6 /* if not dynamic return type,
                        argument is scalar/array, return
                        return type is scalar */ : {

                if (!(INTR_IS_RETURN_TYPE_DYNAMIC(ep)) &&
                    (INTR_RETURN_TYPE(ep) != INTR_TYPE_ALL_NUMERICS &&
                     INTR_RETURN_TYPE(ep) != INTR_TYPE_NUMERICS)) {
                    bType = intr_type_to_basic_type(INTR_RETURN_TYPE(ep));
                    if (bType == TYPE_UNKNOWN) {
                        fatal("invalid intrinsic return type (case -1/-6).");
                        /* not reached. */
                        return NULL;
                    } else {
                        if (kindV == NULL) {
                            ret = (bType != TYPE_CHAR) ? type_basic(bType) :
                                type_char(1);
                        } else {
                            /*
                             * Don't use BASIC_TYPE_DESC(bType) very
                             * here, since we need to set a kind to
                             * the TYPE_DESC.
                             */
                            ret = type_basic(bType);
                            TYPE_KIND(ret) = kindV;
                        }
                    }
                    ret = intr_convert_to_dimension_ifneeded(
                        ep, args, ret);
                } else {
                    expv shape = list0(LIST);
                    TYPE_DESC tp;

                    switch (INTR_OP(ep)) {

                    case INTR_ALL:
                    case INTR_ANY:
                    case INTR_MAXVAL:
                    case INTR_MINVAL:
                    case INTR_PRODUCT:
                    case INTR_SUM:
                    case INTR_COUNT:
                    {
                        /* intrinsic arguments */
                        expv array, dim;

                        array = expr_list_get_n(args, 0);
                        if (!(isValidTypedExpv(array))) {
                            return NULL;
                        }
                        tp = EXPV_TYPE(array);

                        dim = expr_list_get_n(args, 1);
                        if (!(isValidTypedExpv(dim))) {
                            return NULL;
                        }

                        /* set basic type of array type */
                        switch (INTR_OP(ep)) {
                        case INTR_ALL:
                        case INTR_ANY:
                            bType = TYPE_LOGICAL;
                            break;
                        case INTR_COUNT:
                            bType = TYPE_INT;
                            break;
                        default:
                            bType = get_basic_type(tp);
                            break;
                        }

                        if (kindV == NULL) {
                            bTypeDsc = BASIC_TYPE_DESC(bType);
                        } else {
                            bTypeDsc = type_basic(bType);
                            TYPE_KIND(bTypeDsc) = kindV;
                        }

                        dim = expv_reduce(dim, FALSE);

                        if(EXPV_CODE(dim) == INT_CONSTANT) {
                            int nDim;
                            nDim  = (int)EXPV_INT_VALUE(dim);

                            if(nDim > TYPE_N_DIM(tp) || nDim <= 0) {
                                error("value DIM of intrinsic %s "
                                      "out of range.", INTR_NAME(ep));
                                return NULL;
                            }

                            generate_contracted_shape_expr(
                                tp, shape, TYPE_N_DIM(tp) - nDim);
                        } else {
                            generate_assumed_shape_expr(
                                shape, TYPE_N_DIM(tp) - 1);
                        }
                    }
                    break;

                    case INTR_SPREAD:
                    {
                        /* intrinsic arguments */
                        expv array, dim, ncopies;

                        array = expr_list_get_n(args, 0);
                        if (!(isValidTypedExpv(array))) {
                            return NULL;
                        }
                        dim = expr_list_get_n(args, 1);
                        if (!(isValidTypedExpv(dim))) {
                            return NULL;
                        }
                        ncopies = expr_list_get_n(args, 2);
                        if (!(isValidTypedExpv(ncopies))) {
                            return NULL;
                        }

                        tp = EXPV_TYPE(array);
                        bType = get_basic_type(tp);
                        if (kindV == NULL) {
                            bTypeDsc = BASIC_TYPE_DESC(bType);
                        } else {
                            bTypeDsc = type_basic(bType);
                            TYPE_KIND(bTypeDsc) = kindV;
                        }

                        dim = expv_reduce(dim, FALSE);

                        if(EXPR_CODE(dim) == INT_CONSTANT) {
                            int nDim;
                            nDim  = (int)EXPV_INT_VALUE(dim);

                            if(nDim > (TYPE_N_DIM(tp) + 1) || nDim <= 0) {
                                error("value DIM of intrinsic %s "
                                      "out of range.", INTR_NAME(ep));
                                return NULL;
                            }

                            generate_expand_shape_expr(
                                tp, shape, ncopies, TYPE_N_DIM(tp) + 1 - nDim);
                        } else {
                            generate_assumed_shape_expr(
                                shape, TYPE_N_DIM(tp) - 1);
                        }
                    }
                    break;

                    case INTR_RESHAPE:
                    {
                        /* intrinsic arguments */
                        expv source, arg_shape;

                        source = expr_list_get_n(args, 0);
                        if (!(isValidTypedExpv(source))) {
                            return NULL;
                        }
                        arg_shape = expr_list_get_n(args, 1);
                        if (!(isValidTypedExpv(arg_shape))) {
                            return NULL;
                        }

                        tp = EXPV_TYPE(source);
                        bType = get_basic_type(tp);
                        if (kindV == NULL) {
                            bTypeDsc = BASIC_TYPE_DESC(bType);
                        } else {
                            bTypeDsc = type_basic(bType);
                            TYPE_KIND(bTypeDsc) = kindV;
                        }

                        tp = EXPV_TYPE(arg_shape);
                        if (TYPE_N_DIM(tp) != 1) {
                            error("SHAPE argument of intrinsic "
                                  "RESHAPE is not vector.");
                            return NULL;
                        }

                        /*
                         * We can't determine # of the elements in
                         * this array that represents dimension of the
                         * return type, which is identical to the
                         * reshaped array. In order to express this,
                         * we introduce a special TYPE_DESC, which is
                         * having a flag to specify that the type is
                         * generated by the reshape() intrinsic.
                         */

                        /*
                         * dummy one dimensional assumed array.
                         */
                        generate_assumed_shape_expr(shape, 2);
                        ret = compile_dimensions(bTypeDsc, shape);
                        fix_array_dimensions(ret);
                        TYPE_IS_RESHAPED(ret) = TRUE;

                        return ret;
                    }
                    break;

                    case INTR_MATMUL:
                    {
                        expv m1 = expr_list_get_n(args, 0);
                        expv m2 = expr_list_get_n(args, 1);
                        TYPE_DESC t1 = EXPV_TYPE(m1);
                        TYPE_DESC t2 = EXPV_TYPE(m2);
                        expv s1 = list0(LIST);
                        expv s2 = list0(LIST);

                        /*
                         * FIXME:
                         *	Should we use
                         *	get_binary_numeric_intrinsic_operation_type()
                         *	instead of max_type()? I think so but
                         *	not sure at this moment.
                         */
                        bType = get_basic_type(max_type(t1, t2));

                        if (kindV == NULL) {
                            bTypeDsc = BASIC_TYPE_DESC(bType);
                        } else {
                            bTypeDsc = type_basic(bType);
                            TYPE_KIND(bTypeDsc) = kindV;
                        }

                        generate_shape_expr(t1, s1);
                        generate_shape_expr(t2, s2);

                        if (TYPE_N_DIM(t1) == 2 &&
                            TYPE_N_DIM(t2) == 2) {
                            /*
                             * (n, m) * (m, k) => (n, k).
                             */
                            shape = list2(LIST,
                                          EXPR_ARG1(s1), EXPR_ARG2(s2));
                        } else if (TYPE_N_DIM(t1) == 2 &&
                                   TYPE_N_DIM(t2) == 1) {
                            /*
                             * (n, m) * (m) => (n).
                             */
                            shape = list1(LIST, EXPR_ARG1(s1));
                        } else if (TYPE_N_DIM(t1) == 1 &&
                                   TYPE_N_DIM(t2) == 2) {
                            /*
                             * (m) * (m, k) => (k).
                             */
                            shape = list1(LIST, EXPR_ARG2(s2));
                        } else {
                            error("an invalid dimension combination for "
                                  "matmul(), %d and %d.",
                                  TYPE_N_DIM(t1), TYPE_N_DIM(t2));
                            return NULL;
                        }

                        ret = compile_dimensions(bTypeDsc, shape);
                        fix_array_dimensions(ret);

                        return ret;
                    }
                    break;

                    case INTR_DOT_PRODUCT:
                    {
                        expv m1 = expr_list_get_n(args, 0);
                        expv m2 = expr_list_get_n(args, 1);
                        TYPE_DESC t1 = EXPV_TYPE(m1);
                        TYPE_DESC t2 = EXPV_TYPE(m2);

                        if (TYPE_N_DIM(t1) == 1 &&
                            TYPE_N_DIM(t2) == 1) {
                            TYPE_DESC tp =
                                get_binary_numeric_intrinsic_operation_type(
                                    t1, t2);
                            return array_element_type(tp);
                        } else {
                            error("argument(s) is not a one-dimensional "
                                  "array.");
                            return NULL;
                        }
                    }
                    break;

		    case INTR_PACK:
		    {

		      if (INTR_N_ARGS(ep) == 3){
			expv v = expr_list_get_n(args, 2);
			return EXPV_TYPE(v);
		      }
		      else {
			a = expr_list_get_n(args, 0);
			if (!(isValidTypedExpv(a))) {
			  return NULL;
			}

			bType = get_basic_type(EXPV_TYPE(a));
			bTypeDsc = BASIC_TYPE_DESC(bType);
			expr dims = list1(LIST, NULL);
			ret = compile_dimensions(bTypeDsc, dims);
			fix_array_dimensions(ret);
			return ret;
		      }
		    }
		    break;

		    case INTR_UNPACK:
		    {
			a = expr_list_get_n(args, 0);
			if (!(isValidTypedExpv(a))) {
			  return NULL;
			}
			bType = get_basic_type(EXPV_TYPE(a));
			bTypeDsc = BASIC_TYPE_DESC(bType);

			a = expr_list_get_n(args, 1);
			if (!(isValidTypedExpv(a))) {
			  return NULL;
			}
			TYPE_DESC tp = EXPV_TYPE(a);
			ret = copy_dimension(tp, bTypeDsc);
			fix_array_dimensions(ret);
			return ret;
		    }
		    break;

                    default:
                    {
                        /* not  reached ! */
                        ret = BASIC_TYPE_DESC(TYPE_GNUMERIC_ALL);
                    }

                    }

                    ret = compile_dimensions(bTypeDsc, shape);
                    fix_array_dimensions(ret);
                }

                break;
            }

            case -2: {
                /*
                 * Returns BASIC_TYPE of the first arg.
                 */
                a = expr_list_get_n(args, 0);
                if (!(isValidTypedExpv(a))) {
                    return NULL;
                }
                bType = get_basic_type(EXPV_TYPE(a));
                if (kindV == NULL) {
                    ret = BASIC_TYPE_DESC(bType);
                } else {
                    ret = type_basic(bType);
                    TYPE_KIND(ret) = kindV;
                }
                break;
            }

            case -3: {
                /*
                 * Returns single dimension array of integer having
                 * elemnets that equals to the first arg's dimension.
                 */
                /*
                 * FIXME:
                 *	No need to check kindV?? I believe we don't, though.
                 */
                bTypeDsc = BASIC_TYPE_DESC(TYPE_INT);
                TYPE_DESC tp = NULL;
                expr dims = NULL;
                int nDims = 0;
                a = expr_list_get_n(args, 0);
                if (!(isValidTypedExpv(a))) {
                    return NULL;
                }

                bTypeDsc = BASIC_TYPE_DESC(TYPE_INT);
                tp = EXPV_TYPE(a);
                nDims = TYPE_N_DIM(tp);
                dims = list1(LIST, make_int_enode(nDims));
                ret = compile_dimensions(bTypeDsc, dims);
                fix_array_dimensions(ret);

                break;
            }

            case -4:{
                /*
                 * Returns transpose of the first arg (matrix).
                 */
                TYPE_DESC tp = NULL;
                expr dims = list0(LIST);

                a = expr_list_get_n(args, 0);
                if (!(isValidTypedExpv(a))) {
                    return NULL;
                }
                tp = EXPV_TYPE(a);
                bType = get_basic_type(tp);
                if (kindV == NULL) {
                    bTypeDsc = BASIC_TYPE_DESC(bType);
                } else {
                    bTypeDsc = type_basic(bType);
                    TYPE_KIND(bTypeDsc) = kindV;
                }

                if (TYPE_N_DIM(tp) != 2) {
                    error("Dimension is not two.");
                    return NULL;
                }

                generate_reverse_dimension_expr(tp, dims);
                ret = compile_dimensions(bTypeDsc, dims);
                fix_array_dimensions(ret);

                break;
            }

            case -5: {
                /*
                 * -5 : BASIC_TYPE of return type is 'returnType' and
                 * kind of return type is same as first arg.
                 */
                int nDims = 0;
                TYPE_DESC tp = NULL;

                a = expr_list_get_n(args, 0);
                if (!(isValidTypedExpv(a))) {
                    return NULL;
                }

                tp = EXPV_TYPE(a);

                switch (INTR_OP(ep)) {
                    case INTR_AIMAG: case INTR_DIMAG: {
                        bType = get_basic_type(tp);
                        if (bType != TYPE_COMPLEX &&
                            bType != TYPE_DCOMPLEX) {
                            error("argument is not a complex type.");
                            return NULL;
                        }
                        bType = (bType == TYPE_COMPLEX) ?
                            TYPE_REAL : TYPE_DREAL;
                        break;
                    }
                    default: {
                        bType = intr_type_to_basic_type(INTR_RETURN_TYPE(ep));
                        break;
                    }
                }

                if (bType == TYPE_UNKNOWN) {
                    fatal("invalid intrinsic return type (case -5).");
                    /* not reached. */
                    return NULL;
                }
                bTypeDsc = type_basic(bType);
                TYPE_KIND(bTypeDsc) = TYPE_KIND(tp);

                if ((nDims = TYPE_N_DIM(tp)) > 0) {
                    ret = copy_dimension(tp, bTypeDsc);
                    fix_array_dimensions(ret);
                } else {
                    ret = bTypeDsc;
                }

                break;
            }

            case -7: {
                TYPE_DESC lhsTp = new_type_desc();
                TYPE_BASIC_TYPE(lhsTp) = TYPE_LHS;
                TYPE_ATTR_FLAGS(lhsTp) |= TYPE_ATTR_TARGET;
                ret = lhsTp;
                break;
            }

            case -8: {
                bType = intr_type_to_basic_type(INTR_RETURN_TYPE(ep));
                if (bType == TYPE_UNKNOWN) {
                    fatal("invalid intrinsic return type (case -8).");
                    return NULL;
                } else {
                    ret = type_basic(bType);
                }
                TYPE_SET_EXTERNAL(ret);
                break;
            }

            case -9: {
                bType = intr_type_to_basic_type(INTR_RETURN_TYPE(ep));
                ret = type_basic(bType);
                break;
            }

            default: {
                fatal("%s: Unknown return type specification.", __func__);
                break;
            }
        }
    }

    return ret;
}
Example #2
0
void CodeTypeInference::on_visit(CodeArrayIndexerExpression *object) {
  auto tmp = CodeTypeInference::get_type_reference(object->target_object());
  if (tmp != nullptr) {
    this->m_result = tmp->array_element_type();
  }
}