Re: How to avoid constant propagation into functions?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
}

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux