On 05.12.2016 17:40, Georg-Johann Lay wrote:
On 05.12.2016 17:33, Tim Prince wrote:
Hi, I just came across a small test program that propagates a constant
value from a function to a callee, even though the callee has attribute
"noclone".
From the gcc documentation I would conclude that "noclone" should
prevent such propagations?
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007bnoclone_007d-function-attribute-3345
noclone
This function attribute prevents a function from being
considered for cloning -- a mechanism that produces specialized
copies of functions and which is (currently) performed by
interprocedural constant propagation.
I see this with gcc 5.4 (x86_64) and current trunk.
Johann
Maybe you want -fno-inline-functions ?
The function has __attribute((noinline,noclone)). This is not sufficient?
Johann
...to be more specific, attached is a C test case.
Function mod_mul is noinline + noclone, and is called with
n=317. mod_mul itself does not use "317" anywhere.
Yet when compiling with
$ gcc mod.c -Os -save-temps -dp
$ gcc --version
gcc (GCC) 7.0.0 20161202 (experimental) [trunk revision 227650]
and reading asm, there is:
mod_mul:
.LFB1:
.cfi_startproc
cmpl $316, %edx # 9 *cmpsi_1/1 [length = 6]
pushq %rbx # 84 *pushdi2_rex64/1 [length = 1]
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
movl %esi, %ebx # 3 *movsi_internal/1 [length = 2]
movl %edx, %esi # 4 *movsi_internal/1 [length = 2]
jbe .L2 # 10 *jcc_1 [length = 2]
movl $1, %edx # 12 *movsi_internal/1 [length = 5]
movl $317, %edi # 14 *movsi_internal/1 [length = 5]
call mod_mul # 15 *call_value [length = 5]
So the constant 317 made its way into the code of mod_mul (insn 14),
and insn 9 also uses this value.
From my understanding "noclone" should avoid any such propagations?
Johann
#include <stdio.h>
typedef unsigned T;
static T mod_mul (T n, T a, T b);
// Return a mod n im kleinsten, nicht-negativen Restsystem (T ist unsigned).
#define NIC __attribute((noinline,noclone))
static T mod_norm (T n, T a)
{
if (a < n)
return a;
if (n < 2)
return 0;
return mod_mul (n, a, 1);
}
// Return a*b mod n
NIC
static T mod_mul (T n, T a, T b)
{
// Anstatt "return (a * b) % n" berechnen wir das Produkt von Hand,
// was den Bereich erlaubter Moduli von [sqrt (max_T)] auf
// [max_T / 2] erweitert.
// Im folgenden gehen wir davon aus, dass b normiert ist.
b = mod_norm (n, b);
for (T ab = 0;;)
{
if (a % 2 == 1)
{
ab += b;
if (ab >= n)
ab -= n;
}
if (a < 2)
return ab;
a = a / 2;
b = b * 2;
if (b >= n)
b -= n;
}
}
// Return a^k mod n
//
// Exponentiation mit dem gleichen Ansatz wie oben, nur dass
// anstatt eines Faktors der Exponent binaer expandiert wird.
static T mod_pow (T n, T a, unsigned k)
{
if (n == 1)
return 0;
for (T a_k = 1;;)
{
if (k % 2 == 1)
a_k = mod_mul (n, a, a_k);
if (k < 2)
return a_k;
k = k / 2;
a = mod_mul (n, a, a);
}
}
int main (void)
{
printf ("erg= %u\n", mod_pow (317, 4378, 120));
return 0;
}