diff --git a/configure b/configure index 1cc9ab1fe4..df1cb6041a 100755 --- a/configure +++ b/configure @@ -350,6 +350,8 @@ Developer options (useful when working on FFmpeg itself): --enable-ftrapv Trap arithmetic overflows --samples=PATH location of test samples for FATE, if not set use \$FATE_SAMPLES at make invocation time. + --enable-neon-clobber-test check NEON registers for clobbering (should be + used only for debugging purposes) --enable-xmm-clobber-test check XMM registers for clobbering (Win64-only; should be used only for debugging purposes) --enable-random randomly enable/disable components @@ -1371,6 +1373,7 @@ CONFIG_LIST=" mdct memalign_hack memory_poisoning + neon_clobber_test network nonfree pic @@ -4629,6 +4632,16 @@ test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic # -wN '..@*' is more selective than -x, but not available everywhere. check_stripflags -wN \'..@*\' || check_stripflags -x +enabled neon_clobber_test && + check_ldflags -Wl,--wrap,avcodec_open2 \ + -Wl,--wrap,avcodec_decode_audio4 \ + -Wl,--wrap,avcodec_decode_video2 \ + -Wl,--wrap,avcodec_decode_subtitle2 \ + -Wl,--wrap,avcodec_encode_audio2 \ + -Wl,--wrap,avcodec_encode_video2 \ + -Wl,--wrap,avcodec_encode_subtitle || + disable neon_clobber_test + enabled xmm_clobber_test && check_ldflags -Wl,--wrap,avcodec_open2 \ -Wl,--wrap,avcodec_decode_audio4 \ diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile index 277abd98ea..8bdccbdee1 100644 --- a/libavcodec/arm/Makefile +++ b/libavcodec/arm/Makefile @@ -23,6 +23,7 @@ OBJS-$(CONFIG_HPELDSP) += arm/hpeldsp_init_arm.o \ arm/hpeldsp_arm.o OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_init_arm.o OBJS-$(CONFIG_MPEGVIDEO) += arm/mpegvideo_arm.o +OBJS-$(CONFIG_NEON_CLOBBER_TEST) += arm/neontest.o OBJS-$(CONFIG_VC1_DECODER) += arm/vc1dsp_init_arm.o OBJS-$(CONFIG_VORBIS_DECODER) += arm/vorbisdsp_init_arm.o OBJS-$(CONFIG_VP3DSP) += arm/vp3dsp_init_arm.o diff --git a/libavcodec/arm/neontest.c b/libavcodec/arm/neontest.c new file mode 100644 index 0000000000..a3b5b8e2e3 --- /dev/null +++ b/libavcodec/arm/neontest.c @@ -0,0 +1,79 @@ +/* + * check NEON registers for clobbers + * Copyright (c) 2013 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/avcodec.h" +#include "libavutil/arm/neontest.h" + +wrap(avcodec_open2(AVCodecContext *avctx, + AVCodec *codec, + AVDictionary **options)) +{ + testneonclobbers(avcodec_open2, avctx, codec, options); +} + +wrap(avcodec_decode_audio4(AVCodecContext *avctx, + AVFrame *frame, + int *got_frame_ptr, + AVPacket *avpkt)) +{ + testneonclobbers(avcodec_decode_audio4, avctx, frame, + got_frame_ptr, avpkt); +} + +wrap(avcodec_decode_video2(AVCodecContext *avctx, + AVFrame *picture, + int *got_picture_ptr, + AVPacket *avpkt)) +{ + testneonclobbers(avcodec_decode_video2, avctx, picture, + got_picture_ptr, avpkt); +} + +wrap(avcodec_decode_subtitle2(AVCodecContext *avctx, + AVSubtitle *sub, + int *got_sub_ptr, + AVPacket *avpkt)) +{ + testneonclobbers(avcodec_decode_subtitle2, avctx, sub, + got_sub_ptr, avpkt); +} + +wrap(avcodec_encode_audio2(AVCodecContext *avctx, + AVPacket *avpkt, + const AVFrame *frame, + int *got_packet_ptr)) +{ + testneonclobbers(avcodec_encode_audio2, avctx, avpkt, frame, + got_packet_ptr); +} + +wrap(avcodec_encode_subtitle(AVCodecContext *avctx, + uint8_t *buf, int buf_size, + const AVSubtitle *sub)) +{ + testneonclobbers(avcodec_encode_subtitle, avctx, buf, buf_size, sub); +} + +wrap(avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr)) +{ + testneonclobbers(avcodec_encode_video2, avctx, avpkt, frame, got_packet_ptr); +} diff --git a/libavutil/arm/neontest.h b/libavutil/arm/neontest.h new file mode 100644 index 0000000000..f668c00733 --- /dev/null +++ b/libavutil/arm/neontest.h @@ -0,0 +1,62 @@ +/* + * check NEON registers for clobbering + * Copyright (c) 2008 Ramiro Polla + * Copyright (c) 2013 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "libavutil/bswap.h" + +#define storeneonregs(mem) \ + __asm__ volatile( \ + "vstm %0, {d8-d15}\n\t" \ + :: "r"(mem) : "memory") + +#define testneonclobbers(func, ctx, ...) \ + uint64_t neon[2][8]; \ + int ret; \ + storeneonregs(neon[0]); \ + ret = __real_ ## func(ctx, __VA_ARGS__); \ + storeneonregs(neon[1]); \ + if (memcmp(neon[0], neon[1], sizeof(neon[0]))) { \ + int i; \ + av_log(ctx, AV_LOG_ERROR, \ + "NEON REGS CLOBBERED IN %s!\n", #func); \ + for (i = 0; i < 8; i ++) \ + if (neon[0][i] != neon[1][i]) { \ + av_log(ctx, AV_LOG_ERROR, \ + "d%-2d = %016"PRIx64"\n", \ + 8 + i, av_bswap64(neon[0][i])); \ + av_log(ctx, AV_LOG_ERROR, \ + " -> %016"PRIx64"\n", \ + av_bswap64(neon[1][i])); \ + } \ + abort(); \ + } \ + return ret + +#define wrap(func) \ +int __real_ ## func; \ +int __wrap_ ## func; \ +int __wrap_ ## func