function signatures( dtypes ) {
	var casts;
	var out;
	var ch1;
	var ch2;
	var ch3;
	var ch4;
	var t1;
	var t2;
	var t3;
	var t4;
	var N;
	var s;
	var i;
	var j;
	var k;

	N = dtypes.length;

	// Generate the list of signatures:
	out = [];
	for ( i = 0; i < N; i++ ) {
		t1 = dtypes[ i ];
		ch1 = dtypeChar( t1 );
		for ( j = 0; j < N; j++ ) {
			t2 = dtypes[ j ];

			// Resolve the promoted type for the current dtype pair:
			t3 = promotionRules( t1, t2 );
			if ( t3 === -1 ) {
				continue;
			}
			// Resolve single-letter dtype abbreviations:
			ch2 = dtypeChar( t2 );
			ch3 = dtypeChar( t3 );

			// Generate the input/output array signature:
			s = ch1+ch2+'_'+ch3;

			// If the dtypes are not equal, require that the callback signature have the promoted dtype for input and output arguments...
			if ( ch1 === ch2 && ch2 === ch3 ) {
				out.push( s ); // e.g., `ff_f`
			} else {
				out.push( s+'_as_'+ch3+ch3+'_'+ch3 ); // e.g., `fd_d` => `fd_d_as_dd_d`
			}
			// Resolve the list of safe casts for the promoted dtype:
			casts = safeCasts( t3 );

			// Remove the excluded dtypes:
			casts = filter( casts, EXCLUDE_DTYPES );

			// Generate signatures for allowed casts:
			for ( k = 0; k < casts.length; k++ ) {
				t4 = casts[ k ];
				if ( t4 === t3 ) {
					// For float dtypes, allow downcasting from a higher precision...
					if ( ch3 === 'f' ) {
						out.push( ch1+ch2+'_'+ch3+'_as_dd_d' ); // e.g., `bf_f` => `bf_f_as_dd_d`
					} else if ( ch3 === 'c' ) {
						out.push( ch1+ch2+'_'+ch3+'_as_zz_z' ); // e.g., `bf_c` => `bf_c_as_zz_z`
					}
					continue;
				}
				ch4 = dtypeChar( t4 );
				s = ch1+ch2+'_'+ch4;
				if ( ch1 === ch2 ) {
					out.push( s ); // e.g., `ff_d`
				}
				out.push( s+'_as_'+ch4+ch4+'_'+ch4 ); // e.g., `ff_d_as_dd_d`

				// For float dtypes, allow downcasting from a higher precision...
				if ( ch4 === 'f' ) {
					out.push( s+'_as_dd_d' ); // e.g., `bb_f` => `bb_f_as_dd_d`
				} else if ( ch4 === 'c' ) {
					out.push( s+'_as_zz_z' ); // e.g., `bb_c` => `bb_c_as_zz_z`
				}
			}
		}
	}
	// Append any special loops:
	for ( i = 0; i < SPECIAL_LOOPS.length; i++ ) {
		out.push( SPECIAL_LOOPS[ i ] );
	}
	return out.sort();
}
Generates a list of loop signatures from a list of strided array data types.

@private
@param {StringArray} dtypes - list of data types
@returns {StringArray} list of loop signatures