written and does not escape
'w' or 'W' specifies that the memory pointed to by the parameter does not
escape
+ '1'....'9' specifies that the memory pointed to by the parameter is
+ copied to memory pointed to by different parameter
+ (as in memcpy).
'.' specifies that nothing is known.
The uppercase letter in addition specifies that the memory pointed to
by the parameter is not dereferenced. For 'r' only read applies
' ' nothing is known
't' the size of value written/read corresponds to the size of
of the pointed-to type of the argument type
- '1'...'9' the size of value written/read is given by the specified
- argument
+ '1'...'9' specifies the size of value written/read is given by the
+ specified argument
*/
#ifndef ATTR_FNSPEC_H
{
unsigned int idx = arg_idx (i);
gcc_checking_assert (arg_specified_p (i));
- return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'W';
+ return str[idx] == 'R' || str[idx] == 'O'
+ || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9');
}
/* True if argument is used. */
unsigned int idx = arg_idx (i);
gcc_checking_assert (arg_specified_p (i));
return str[idx] != 'r' && str[idx] != 'R'
+ && (str[idx] < '1' || str[idx] > '9')
&& str[idx] != 'x' && str[idx] != 'X';
}
return str[idx + 1] == 't';
}
+ /* Return true if memory pointer to by argument is copied to a memory
+ pointed to by a different argument (as in memcpy).
+ In this case set ARG. */
+ bool
+ arg_copied_to_arg_p (unsigned int i, unsigned int *arg)
+ {
+ unsigned int idx = arg_idx (i);
+ gcc_checking_assert (arg_specified_p (i));
+ if (str[idx] < '1' || str[idx] > '9')
+ return false;
+ *arg = str[idx] - '1';
+ return true;
+ }
+
+
/* True if the argument does not escape. */
bool
arg_noescape_p (unsigned int i)
return str[1] != 'c' && str[1] != 'C';
}
- /* Return true if all memory written by the function
+ /* Return true if all memory written by the function
is specified by fnspec. */
bool
global_memory_written_p ()
argument. */
case BUILT_IN_STRCAT:
case BUILT_IN_STRCAT_CHK:
- return "1cW R ";
+ return "1cW 1 ";
case BUILT_IN_STRNCAT:
case BUILT_IN_STRNCAT_CHK:
- return "1cW R3";
+ return "1cW 13";
case BUILT_IN_STRCPY:
case BUILT_IN_STRCPY_CHK:
- return "1cO R ";
+ return "1cO 1 ";
case BUILT_IN_STPCPY:
case BUILT_IN_STPCPY_CHK:
- return ".cO R ";
+ return ".cO 1 ";
case BUILT_IN_STRNCPY:
case BUILT_IN_MEMCPY:
case BUILT_IN_MEMMOVE:
case BUILT_IN_STRNCPY_CHK:
case BUILT_IN_MEMCPY_CHK:
case BUILT_IN_MEMMOVE_CHK:
- return "1cO3R3";
+ return "1cO313";
case BUILT_IN_MEMPCPY:
case BUILT_IN_MEMPCPY_CHK:
- return ".cO3R3";
+ return ".cO313";
case BUILT_IN_STPNCPY:
case BUILT_IN_STPNCPY_CHK:
- return ".cO3R3";
+ return ".cO313";
case BUILT_IN_BCOPY:
- return ".cR3O3";
+ return ".c23O3";
case BUILT_IN_BZERO:
return ".cO2";
case BUILT_IN_MEMCMP:
default:
err = true;
}
+ if (err)
+ internal_error ("invalid fn spec attribute \"%s\"", str);
/* Now check all parameters. */
for (unsigned int i = 0; arg_specified_p (i); i++)
case 'w':
case 'W':
case '.':
+ if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
+ || str[idx + 1] == 't')
+ {
+ if (str[idx] != 'r' && str[idx] != 'R'
+ && str[idx] != 'w' && str[idx] != 'W'
+ && str[idx] != 'o' && str[idx] != 'O')
+ err = true;
+ if (str[idx] != 't'
+ /* Size specified is scalar, so it should be described
+ by ". " if specified at all. */
+ && (arg_specified_p (str[idx + 1] - '1')
+ && str[arg_idx (str[idx + 1] - '1')] != '.'))
+ err = true;
+ }
+ else if (str[idx + 1] != ' ')
+ err = true;
break;
default:
- err = true;
+ if (str[idx] < '1' || str[idx] > '9')
+ err = true;
}
- if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
- || str[idx + 1] == 't')
- {
- if (str[idx] != 'r' && str[idx] != 'R'
- && str[idx] != 'w' && str[idx] != 'W'
- && str[idx] != 'o' && str[idx] != 'O')
- err = true;
- }
- else if (str[idx + 1] != ' ')
- err = true;
+ if (err)
+ internal_error ("invalid fn spec attribute \"%s\" arg %i", str, i);
}
- if (err)
- internal_error ("invalid fn spec attribute \"%s\"", str);
}