/* Return a tree expression for a call to the overloaded builtin function OB_FNDECL at LOC with arguments PASSED_ARGLIST. */ tree s390_resolve_overloaded_builtin (location_t loc, tree ob_fndecl, void *passed_arglist) { vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> (passed_arglist); unsigned int in_args_num = vec_safe_length (arglist); unsigned int ob_args_num = 0; unsigned int ob_fcode = DECL_FUNCTION_CODE (ob_fndecl); enum s390_overloaded_builtin_vars bindex; unsigned int i; int last_match_type = INT_MAX; int last_match_index = -1; unsigned int all_op_flags; int num_matches = 0; tree target_builtin_decl, b_arg_chain, return_type; enum s390_builtin_ov_type_index last_match_fntype_index; if (TARGET_DEBUG_ARG) fprintf (stderr, "s390_resolve_overloaded_builtin, code = %4d, %s - %s overloaded\n", (int)ob_fcode, IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)), ob_fcode < S390_BUILTIN_MAX ? "not" : ""); /* 0...S390_BUILTIN_MAX-1 is for non-overloaded builtins. */ if (ob_fcode < S390_BUILTIN_MAX) { if (bflags_for_builtin(ob_fcode) & B_INT) { error_at (loc, "Builtin %qF is for GCC internal use only.", ob_fndecl); return error_mark_node; } return NULL_TREE; } ob_fcode -= S390_BUILTIN_MAX; for (b_arg_chain = TYPE_ARG_TYPES (TREE_TYPE (ob_fndecl)); !VOID_TYPE_P (TREE_VALUE (b_arg_chain)); b_arg_chain = TREE_CHAIN (b_arg_chain)) ob_args_num++; if (ob_args_num != in_args_num) { error_at (loc, "Mismatch in number of arguments for builtin %qF. " "Expected: %d got %d", ob_fndecl, ob_args_num, in_args_num); return error_mark_node; } for (i = 0; i < in_args_num; i++) if ((*arglist)[i] == error_mark_node) return error_mark_node; /* Overloaded builtins without any variants are directly expanded here. */ if (desc_start_for_overloaded_builtin[ob_fcode] == S390_OVERLOADED_BUILTIN_VAR_MAX) return s390_expand_overloaded_builtin (loc, ob_fcode, arglist, NULL_TREE); for (bindex = desc_start_for_overloaded_builtin[ob_fcode]; bindex <= desc_end_for_overloaded_builtin[ob_fcode]; bindex = (enum s390_overloaded_builtin_vars)((int)bindex + 1)) { int match_type; enum s390_builtin_ov_type_index type_index = type_for_overloaded_builtin_var[bindex]; if (TARGET_DEBUG_ARG) fprintf (stderr, "checking variant number: %d", (int)bindex); match_type = s390_fn_types_compatible (type_index, arglist); if (match_type == INT_MAX) continue; if (TARGET_DEBUG_ARG) fprintf (stderr, " %s match score: %d\n", match_type == 0 ? "perfect" : "imperfect", match_type); if (match_type < last_match_type) { num_matches = 1; last_match_type = match_type; last_match_fntype_index = type_index; last_match_index = bindex; } else if (match_type == last_match_type) num_matches++; } if (last_match_type == INT_MAX) { error_at (loc, "invalid parameter combination for intrinsic %qs", IDENTIFIER_POINTER (DECL_NAME (ob_fndecl))); return error_mark_node; } else if (num_matches > 1) { error_at (loc, "ambiguous overload for intrinsic %qs", IDENTIFIER_POINTER (DECL_NAME (ob_fndecl))); return error_mark_node; } if (bt_for_overloaded_builtin_var[last_match_index] == S390_BUILTIN_MAX) target_builtin_decl = ob_fndecl; else target_builtin_decl = s390_builtin_decls[bt_for_overloaded_builtin_var[last_match_index]]; all_op_flags = opflags_overloaded_builtin_var[last_match_index]; return_type = s390_builtin_types[s390_builtin_ov_types[last_match_fntype_index][0]]; /* Check for the operand flags in the overloaded builtin variant. */ for (i = 0; i < ob_args_num; i++) { unsigned int op_flags = all_op_flags & ((1 << O_SHIFT) - 1); tree arg = (*arglist)[i]; tree type = s390_builtin_types[s390_builtin_ov_types[last_match_fntype_index][i + 1]]; all_op_flags = all_op_flags >> O_SHIFT; if (op_flags == O_ELEM) { int n_elem = s390_vec_n_elem (target_builtin_decl); gcc_assert (n_elem > 0); gcc_assert (type == integer_type_node); (*arglist)[i] = build2 (BIT_AND_EXPR, integer_type_node, fold_convert (integer_type_node, arg), build_int_cst (NULL_TREE, n_elem - 1)); } if (TREE_CODE (arg) != INTEGER_CST || !O_IMM_P (op_flags)) continue; if ((TYPE_UNSIGNED (type) && !int_fits_type_p (arg, c_common_unsigned_type (type))) || (!TYPE_UNSIGNED (type) && !int_fits_type_p (arg, c_common_signed_type (type)))) { error("constant argument %d for builtin %qF is out " "of range for target type", i + 1, target_builtin_decl); return error_mark_node; } if (TREE_CODE (arg) == INTEGER_CST && !s390_const_operand_ok (arg, i + 1, op_flags, target_builtin_decl)) return error_mark_node; } /* Handle builtins we expand directly - without mapping it to a low level builtin. */ if (bt_for_overloaded_builtin_var[last_match_index] == S390_BUILTIN_MAX) return s390_expand_overloaded_builtin (loc, ob_fcode, arglist, return_type); s390_adjust_builtin_arglist (ob_fcode, target_builtin_decl, &arglist); if (VOID_TYPE_P (return_type)) return build_function_call_vec (loc, vNULL, target_builtin_decl, arglist, NULL); else return fully_fold_convert (return_type, build_function_call_vec (loc, vNULL, target_builtin_decl, arglist, NULL)); }
static tree avr_resolve_overloaded_builtin (unsigned int iloc, tree fndecl, void *vargs) { tree type0, type1, fold = NULL_TREE; enum avr_builtin_id id = AVR_BUILTIN_COUNT; location_t loc = (location_t) iloc; vec<tree, va_gc> &args = * (vec<tree, va_gc>*) vargs; switch (DECL_FUNCTION_CODE (fndecl)) { default: break; case AVR_BUILTIN_ABSFX: if (args.length() != 1) { error_at (loc, "%qs expects 1 argument but %d given", "absfx", (int) args.length()); fold = error_mark_node; break; } type0 = TREE_TYPE (args[0]); if (!FIXED_POINT_TYPE_P (type0)) { error_at (loc, "%qs expects a fixed-point value as argument", "absfx"); fold = error_mark_node; } switch (TYPE_MODE (type0)) { case QQmode: id = AVR_BUILTIN_ABSHR; break; case HQmode: id = AVR_BUILTIN_ABSR; break; case SQmode: id = AVR_BUILTIN_ABSLR; break; case DQmode: id = AVR_BUILTIN_ABSLLR; break; case HAmode: id = AVR_BUILTIN_ABSHK; break; case SAmode: id = AVR_BUILTIN_ABSK; break; case DAmode: id = AVR_BUILTIN_ABSLK; break; case TAmode: id = AVR_BUILTIN_ABSLLK; break; case UQQmode: case UHQmode: case USQmode: case UDQmode: case UHAmode: case USAmode: case UDAmode: case UTAmode: warning_at (loc, 0, "using %qs with unsigned type has no effect", "absfx"); return args[0]; default: error_at (loc, "no matching fixed-point overload found for %qs", "absfx"); fold = error_mark_node; break; } fold = targetm.builtin_decl (id, true); if (fold != error_mark_node) fold = build_function_call_vec (loc, vNULL, fold, &args, NULL); break; // absfx case AVR_BUILTIN_ROUNDFX: if (args.length() != 2) { error_at (loc, "%qs expects 2 arguments but %d given", "roundfx", (int) args.length()); fold = error_mark_node; break; } type0 = TREE_TYPE (args[0]); type1 = TREE_TYPE (args[1]); if (!FIXED_POINT_TYPE_P (type0)) { error_at (loc, "%qs expects a fixed-point value as first argument", "roundfx"); fold = error_mark_node; } if (!INTEGRAL_TYPE_P (type1)) { error_at (loc, "%qs expects an integer value as second argument", "roundfx"); fold = error_mark_node; } switch (TYPE_MODE (type0)) { case QQmode: id = AVR_BUILTIN_ROUNDHR; break; case HQmode: id = AVR_BUILTIN_ROUNDR; break; case SQmode: id = AVR_BUILTIN_ROUNDLR; break; case DQmode: id = AVR_BUILTIN_ROUNDLLR; break; case UQQmode: id = AVR_BUILTIN_ROUNDUHR; break; case UHQmode: id = AVR_BUILTIN_ROUNDUR; break; case USQmode: id = AVR_BUILTIN_ROUNDULR; break; case UDQmode: id = AVR_BUILTIN_ROUNDULLR; break; case HAmode: id = AVR_BUILTIN_ROUNDHK; break; case SAmode: id = AVR_BUILTIN_ROUNDK; break; case DAmode: id = AVR_BUILTIN_ROUNDLK; break; case TAmode: id = AVR_BUILTIN_ROUNDLLK; break; case UHAmode: id = AVR_BUILTIN_ROUNDUHK; break; case USAmode: id = AVR_BUILTIN_ROUNDUK; break; case UDAmode: id = AVR_BUILTIN_ROUNDULK; break; case UTAmode: id = AVR_BUILTIN_ROUNDULLK; break; default: error_at (loc, "no matching fixed-point overload found for %qs", "roundfx"); fold = error_mark_node; break; } fold = targetm.builtin_decl (id, true); if (fold != error_mark_node) fold = build_function_call_vec (loc, vNULL, fold, &args, NULL); break; // roundfx case AVR_BUILTIN_COUNTLSFX: if (args.length() != 1) { error_at (loc, "%qs expects 1 argument but %d given", "countlsfx", (int) args.length()); fold = error_mark_node; break; } type0 = TREE_TYPE (args[0]); if (!FIXED_POINT_TYPE_P (type0)) { error_at (loc, "%qs expects a fixed-point value as first argument", "countlsfx"); fold = error_mark_node; } switch (TYPE_MODE (type0)) { case QQmode: id = AVR_BUILTIN_COUNTLSHR; break; case HQmode: id = AVR_BUILTIN_COUNTLSR; break; case SQmode: id = AVR_BUILTIN_COUNTLSLR; break; case DQmode: id = AVR_BUILTIN_COUNTLSLLR; break; case UQQmode: id = AVR_BUILTIN_COUNTLSUHR; break; case UHQmode: id = AVR_BUILTIN_COUNTLSUR; break; case USQmode: id = AVR_BUILTIN_COUNTLSULR; break; case UDQmode: id = AVR_BUILTIN_COUNTLSULLR; break; case HAmode: id = AVR_BUILTIN_COUNTLSHK; break; case SAmode: id = AVR_BUILTIN_COUNTLSK; break; case DAmode: id = AVR_BUILTIN_COUNTLSLK; break; case TAmode: id = AVR_BUILTIN_COUNTLSLLK; break; case UHAmode: id = AVR_BUILTIN_COUNTLSUHK; break; case USAmode: id = AVR_BUILTIN_COUNTLSUK; break; case UDAmode: id = AVR_BUILTIN_COUNTLSULK; break; case UTAmode: id = AVR_BUILTIN_COUNTLSULLK; break; default: error_at (loc, "no matching fixed-point overload found for %qs", "countlsfx"); fold = error_mark_node; break; } fold = targetm.builtin_decl (id, true); if (fold != error_mark_node) fold = build_function_call_vec (loc, vNULL, fold, &args, NULL); break; // countlsfx } return fold; }
/* target hook for resolve_overloaded_builtin(). Returns a function call RTX if we can resolve the overloaded builtin */ tree spu_resolve_overloaded_builtin (location_t loc, tree fndecl, void *passed_args) { #define SCALAR_TYPE_P(t) (INTEGRAL_TYPE_P (t) \ || SCALAR_FLOAT_TYPE_P (t) \ || POINTER_TYPE_P (t)) vec<tree, va_gc> *fnargs = static_cast <vec<tree, va_gc> *> (passed_args); unsigned int nargs = vec_safe_length (fnargs); int new_fcode, fcode = DECL_FUNCTION_CODE (fndecl); struct spu_builtin_description *desc; tree match = NULL_TREE; /* The vector types are not available if the backend is not initialized. */ gcc_assert (!flag_preprocess_only); desc = &spu_builtins[fcode]; if (desc->type != B_OVERLOAD) return NULL_TREE; /* Compare the signature of each internal builtin function with the function arguments until a match is found. */ for (new_fcode = fcode + 1; spu_builtins[new_fcode].type == B_INTERNAL; new_fcode++) { tree decl = targetm.builtin_decl (new_fcode, true); tree params = TYPE_ARG_TYPES (TREE_TYPE (decl)); tree param; bool all_scalar; unsigned int p; /* Check whether all parameters are scalar. */ all_scalar = true; for (param = params; param != void_list_node; param = TREE_CHAIN (param)) if (!SCALAR_TYPE_P (TREE_VALUE (param))) all_scalar = false; for (param = params, p = 0; param != void_list_node; param = TREE_CHAIN (param), p++) { tree var, arg_type, param_type = TREE_VALUE (param); if (p >= nargs) { error ("insufficient arguments to overloaded function %s", desc->name); return error_mark_node; } var = (*fnargs)[p]; if (TREE_CODE (var) == NON_LVALUE_EXPR) var = TREE_OPERAND (var, 0); if (TREE_CODE (var) == ERROR_MARK) return NULL_TREE; /* Let somebody else deal with the problem. */ arg_type = TREE_TYPE (var); /* The intrinsics spec does not specify precisely how to resolve generic intrinsics. We require an exact match for vector types and let C do it's usual parameter type checking/promotions for scalar arguments, except for the first argument of intrinsics which don't have a vector parameter. */ if ((!SCALAR_TYPE_P (param_type) || !SCALAR_TYPE_P (arg_type) || (all_scalar && p == 0)) && !lang_hooks.types_compatible_p (param_type, arg_type)) break; } if (param == void_list_node) { if (p != nargs) { error ("too many arguments to overloaded function %s", desc->name); return error_mark_node; } match = decl; break; } } if (match == NULL_TREE) { error ("parameter list does not match a valid signature for %s()", desc->name); return error_mark_node; } return build_function_call_vec (loc, vNULL, match, fnargs, NULL); #undef SCALAR_TYPE_P }