1 /*
2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 
12 /*
13  * This file contains implementations of the divisions
14  * WebRtcSpl_DivU32U16()
15  * WebRtcSpl_DivW32W16()
16  * WebRtcSpl_DivW32W16ResW16()
17  * WebRtcSpl_DivResultInQ31()
18  * WebRtcSpl_DivW32HiLow()
19  *
20  * The description header can be found in signal_processing_library.h
21  *
22  */
23 
24 #include "common_audio/signal_processing/include/signal_processing_library.h"
25 #include "rtc_base/sanitizer.h"
26 
WebRtcSpl_DivU32U16(uint32_t num,uint16_t den)27 uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den)
28 {
29     // Guard against division with 0
30     if (den != 0)
31     {
32         return (uint32_t)(num / den);
33     } else
34     {
35         return (uint32_t)0xFFFFFFFF;
36     }
37 }
38 
WebRtcSpl_DivW32W16(int32_t num,int16_t den)39 int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den)
40 {
41     // Guard against division with 0
42     if (den != 0)
43     {
44         return (int32_t)(num / den);
45     } else
46     {
47         return (int32_t)0x7FFFFFFF;
48     }
49 }
50 
WebRtcSpl_DivW32W16ResW16(int32_t num,int16_t den)51 int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den)
52 {
53     // Guard against division with 0
54     if (den != 0)
55     {
56         return (int16_t)(num / den);
57     } else
58     {
59         return (int16_t)0x7FFF;
60     }
61 }
62 
WebRtcSpl_DivResultInQ31(int32_t num,int32_t den)63 int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den)
64 {
65     int32_t L_num = num;
66     int32_t L_den = den;
67     int32_t div = 0;
68     int k = 31;
69     int change_sign = 0;
70 
71     if (num == 0)
72         return 0;
73 
74     if (num < 0)
75     {
76         change_sign++;
77         L_num = -num;
78     }
79     if (den < 0)
80     {
81         change_sign++;
82         L_den = -den;
83     }
84     while (k--)
85     {
86         div <<= 1;
87         L_num <<= 1;
88         if (L_num >= L_den)
89         {
90             L_num -= L_den;
91             div++;
92         }
93     }
94     if (change_sign == 1)
95     {
96         div = -div;
97     }
98     return div;
99 }
100 
101 int32_t RTC_NO_SANITIZE("signed-integer-overflow")  // bugs.webrtc.org/5486
WebRtcSpl_DivW32HiLow(int32_t num,int16_t den_hi,int16_t den_low)102 WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
103 {
104     int16_t approx, tmp_hi, tmp_low, num_hi, num_low;
105     int32_t tmpW32;
106 
107     approx = (int16_t)WebRtcSpl_DivW32W16((int32_t)0x1FFFFFFF, den_hi);
108     // result in Q14 (Note: 3FFFFFFF = 0.5 in Q30)
109 
110     // tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30)
111     tmpW32 = (den_hi * approx << 1) + ((den_low * approx >> 15) << 1);
112     // tmpW32 = den * approx
113 
114     tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
115     // UBSan: 2147483647 - -2 cannot be represented in type 'int'
116 
117     // Store tmpW32 in hi and low format
118     tmp_hi = (int16_t)(tmpW32 >> 16);
119     tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);
120 
121     // tmpW32 = 1/den in Q29
122     tmpW32 = (tmp_hi * approx + (tmp_low * approx >> 15)) << 1;
123 
124     // 1/den in hi and low format
125     tmp_hi = (int16_t)(tmpW32 >> 16);
126     tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);
127 
128     // Store num in hi and low format
129     num_hi = (int16_t)(num >> 16);
130     num_low = (int16_t)((num - ((int32_t)num_hi << 16)) >> 1);
131 
132     // num * (1/den) by 32 bit multiplication (result in Q28)
133 
134     tmpW32 = num_hi * tmp_hi + (num_hi * tmp_low >> 15) +
135         (num_low * tmp_hi >> 15);
136 
137     // Put result in Q31 (convert from Q28)
138     tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3);
139 
140     return tmpW32;
141 }
142