Redundant kernels for torch.scatter() when using torch.compile()
Labels: triaged, module: functionalization, oncall: pt2, module: inductor

### 🐛 Describe the bug

Hello,
 
I have a very simple program as follows:
 
```
import torch
 
def fn(out, src, index):
  out.scatter_(0, index, src)
  return out
 
out = torch.zeros(8, dtype=torch.int64, device='cuda')
src = torch.tensor([1001, 1002, 1003], dtype=torch.int64, device='cuda')
index = torch.tensor([1, 3, 5], dtype=torch.int64, device='cuda')
 
compiled_f = torch.compile(fn, backend='inductor',
                              options={'trace.enabled':True,
                                       'trace.graph_diagram':True})
 
out = compiled_f(out, src, index)
```
 
I found out that the triton code generated using torch.compile() is as follow:
 
```
from ctypes import c_void_p, c_long
import torch
import math
import random
import os
import tempfile
from math import inf, nan
from torch._inductor.hooks import run_intermediate_hooks
from torch._inductor.utils import maybe_profile
 
from torch import empty_strided, as_strided, device
from torch._inductor.codecache import AsyncCompile
from torch._inductor.select_algorithm import extern_kernels
 
aten = torch.ops.aten
assert_size_stride = torch._C._dynamo.guards.assert_size_stride
async_compile = AsyncCompile()
 
 
# kernel path: /tmp/torchinductor_surakav/ve/cve56yx3hkxlcxgcjzkzrwkfqjk32wabeioxkqmj6wzktob6ndln.py
# Original ATen: aten.scatter
 
# aten.scatter => scatter
triton_poi_fused_scatter_0 = async_compile.triton('triton_', '''
import triton
import triton.language as tl
from torch._inductor.ir import ReductionHint
from torch._inductor.ir import TileHint
from torch._inductor.triton_heuristics import AutotuneHint, pointwise
from torch._inductor.utils import instance_descriptor
from torch._inductor import triton_helpers
 
@pointwise(size_hints=[8], filename=__file__, meta={'signature': {0: '*i64', 1: '*i64', 2: 'i32'}, 'device': 0, 'constants': {}, 'mutated_arg_names': [], 'autotune_hints': set(), 'configs': [instance_descriptor(divisible_by_16=(0, 1), equal_to_1=())]})
@triton.jit
def triton_(in_ptr0, out_ptr0, xnumel, XBLOCK : tl.constexpr):
    xnumel = 8
    xoffset = tl.program_id(0) * XBLOCK
    xindex = xoffset + tl.arange(0, XBLOCK)[:]
    xmask = xindex < xnumel
    x0 = xindex
    tmp0 = tl.load(in_ptr0 + (x0), xmask)
    tl.store(out_ptr0 + (x0), tmp0, xmask)
''')
 
import triton
import triton.language as tl
from torch._inductor.triton_heuristics import grid, start_graph, end_graph
from torch._C import _cuda_getCurrentRawStream as get_cuda_stream
 
 
# kernel path: /tmp/torchinductor_surakav/ot/cotufkhkaxlsx7zez6h2ksaw3znejjzmdja62ubpjuiga5xnawzq.py
# Original ATen: aten.scatter
 
# aten.scatter => scatter
triton_poi_fused_scatter_1 = async_compile.triton('triton_', '''
import triton
import triton.language as tl
from torch._inductor.ir import ReductionHint
from torch._inductor.ir import TileHint
from torch._inductor.triton_heuristics import AutotuneHint, pointwise
from torch._inductor.utils import instance_descriptor
from torch._inductor import triton_helpers
 
@pointwise(size_hints=[4], filename=__file__, meta={'signature': {0: '*i64', 1: '*i64', 2: '*i64', 3: 'i32'}, 'device': 0, 'constants': {}, 'mutated_arg_names': ['out_ptr0'], 'autotune_hints': set(), 'configs': [instance_descriptor(divisible_by_16=(0, 1, 2), equal_to_1=())]})
@triton.jit
def triton_(in_ptr0, in_ptr1, out_ptr0, xnumel, XBLOCK : tl.constexpr):
    xnumel = 3
    xoffset = tl.program_id(0) * XBLOCK
    xindex = xoffset + tl.arange(0, XBLOCK)[:]
    xmask = xindex < xnumel
    x0 = xindex
    tmp0 = tl.load(in_ptr0 + (x0), xmask)
    tmp1 = tl.load(in_ptr1 + (x0), xmask)
    tl.device_assert(((0 <= tmp0) & (tmp0 < 8)) | ~xmask, "index out of bounds: 0 <= tmp0 < 8")
    tl.store(out_ptr0 + (tl.broadcast_to(tmp0, [XBLOCK])), tmp1, xmask)
''')
 
 
# kernel path: /tmp/torchinductor_surakav/3i/c3igscqoaoc2w6f2rm3zzbumbrsp3453ilgp42nn463kkpl5aed2.py
# Original ATen:
 
triton_poi_fused_2 = async_compile.triton('triton_', '''
import triton
import triton.language as tl
from torch._inductor.ir import ReductionHint
from torch._inductor.ir import TileHint
from torch._inductor.triton_heuristics import AutotuneHint, pointwise
from torch._inductor.utils import instance_descriptor
from torch._inductor import triton_helpers
 
@pointwise(size_hints=[8], filename=__file__, meta={'signature': {0: '*i64', 1: '*i64', 2: 'i32'}, 'device': 0, 'constants': {}, 'mutated_arg_names': ['out_ptr0'], 'autotune_hints': set(), 'configs': [instance_descriptor(divisible_by_16=(0, 1), equal_to_1=())]})
@triton.jit
def triton_(in_ptr0, out_ptr0, xnumel, XBLOCK : tl.constexpr):
    xnumel = 8
    xoffset = tl.program_id(0) * XBLOCK
    xindex = xoffset + tl.arange(0, XBLOCK)[:]
    xmask = xindex < xnumel
    x0 = xindex
    tmp0 = tl.load(in_ptr0 + (x0), xmask)
    tl.store(out_ptr0 + (x0), tmp0, xmask)
''')
 
 
async_compile.wait(globals())
del async_compile
 
def call(args):
    arg0_1, arg1_1, arg2_1 = args
    args.clear()
    assert_size_stride(arg0_1, (8, ), (1, ))
    assert_size_stride(arg1_1, (3, ), (1, ))
    assert_size_stride(arg2_1, (3, ), (1, ))
    with torch.cuda._DeviceGuard(0):
        torch.cuda.set_device(0) # no-op to ensure context
        buf0 = empty_strided((8, ), (1, ), device='cuda', dtype=torch.int64)
        stream0 = get_cuda_stream(0)
        triton_poi_fused_scatter_0.run(arg0_1, buf0, 8, grid=grid(8), stream=stream0)
        triton_poi_fused_scatter_1.run(arg2_1, arg1_1, buf0, 3, grid=grid(3), stream=stream0)
        del arg1_1
        del arg2_1
        triton_poi_fused_2.run(buf0, arg0_1, 8, grid=grid(8), stream=stream0)
        del arg0_1
        return (buf0, )
 
 
def benchmark_compiled_module(times=10, repeat=10):
    from torch._dynamo.testing import rand_strided
    from torch._inductor.utils import print_performance
    arg0_1 = rand_strided((8, ), (1, ), device='cuda:0', dtype=torch.int64)
    arg1_1 = rand_strided((3, ), (1, ), device='cuda:0', dtype=torch.int64)
    arg2_1 = rand_strided((3, ), (1, ), device='cuda:0', dtype=torch.int64)
    return print_performance(lambda: call([arg0_1, arg1_1, arg2_1]), times=times, repeat=repeat)
 
 
if __name__ == "__main__":
    from torch._inductor.wrapper_benchmark import compiled_module_main
    compiled_module_main('None', benchmark_compiled_module)
```
 
Seems like there are two redundant kernels before and after torch.scatter() that do nothing but loading and storing the same data (triton_poi_fused_scatter_0 and triton_poi_fused_2). I am wondering if this is a bug? Is there a way to eliminate these two redundant kernels?

### Error logs

_No response_

### Minified repro

_No response_

### Versions

Collecting environment information...
PyTorch version: 2.1.0a0+git72b223c
Is debug build: False
CUDA used to build PyTorch: 11.8
ROCM used to build PyTorch: N/A

OS: Ubuntu 20.04.6 LTS (x86_64)
GCC version: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Clang version: 10.0.0-4ubuntu1 
CMake version: version 3.26.4
Libc version: glibc-2.31

Python version: 3.9.17 (main, Jul  5 2023, 20:41:20)  [GCC 11.2.0] (64-bit runtime)
Python platform: Linux-5.15.0-1038-azure-x86_64-with-glibc2.31
Is CUDA available: True
CUDA runtime version: 11.8.89
CUDA_MODULE_LOADING set to: LAZY
GPU models and configuration: 
GPU 0: Tesla T4
GPU 1: Tesla T4
GPU 2: Tesla T4
GPU 3: Tesla T4

Nvidia driver version: 520.61.05
cuDNN version: Could not collect
HIP runtime version: N/A
MIOpen runtime version: N/A
Is XNNPACK available: True

CPU:
Architecture:                    x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   48 bits physical, 48 bits virtual
CPU(s):                          64
On-line CPU(s) list:             0-63
Thread(s) per core:              1
Core(s) per socket:              32
Socket(s):                       2
NUMA node(s):                    4
Vendor ID:                       AuthenticAMD
CPU family:                      23
Model:                           49
Model name:                      AMD EPYC 7V12 64-Core Processor
Stepping:                        0
CPU MHz:                         2445.440
BogoMIPS:                        4890.88
Hypervisor vendor:               Microsoft
Virtualization type:             full
L1d cache:                       2 MiB
L1i cache:                       2 MiB
L2 cache:                        32 MiB
L3 cache:                        256 MiB
NUMA node0 CPU(s):               0-15
NUMA node1 CPU(s):               16-31
NUMA node2 CPU(s):               32-47
NUMA node3 CPU(s):               48-63
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Mmio stale data:   Not affected
Vulnerability Retbleed:          Mitigation; untrained return thunk; SMT disabled
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Vulnerability Spectre v1:        Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:        Mitigation; Retpolines, STIBP disabled, RSB filling, PBRSB-eIBRS Not affected
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl tsc_reliable nonstop_tsc cpuid extd_apicid aperfmperf pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext perfctr_core ssbd vmmcall fsgsbase bmi1 avx2 smep bmi2 rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves clzero xsaveerptr rdpru arat umip rdpid

Versions of relevant libraries:
[pip3] numpy==1.25.0
[pip3] pytorch-triton==2.1.0+440fd1bf20
[pip3] torch==2.1.0a0+git72b223c
[conda] magma-cuda118             2.6.1                         1    pytorch
[conda] mkl                       2023.1.0         h6d00ec8_46342  
[conda] mkl-include               2023.1.0         h06a4308_46342  
[conda] numpy                     1.25.0                   pypi_0    pypi
[conda] pytorch-triton            2.1.0+440fd1bf20          pypi_0    pypi
[conda] torch                     2.1.0a0+git72b223c           dev_0    <develop>

cc @ezyang @msaroufim @wconstab @bdhirsh @anijain2305 @voznesenskym @penguinwu @EikanWang @jgong5 @Guobing-Chen @XiaobingSuper @zhuhaozhe @blzheng @Xia-Weiwen @wenzhe-nrv @jiayisunx @peterbell10 @ipiszy @ngimel @yf225 @chenyang78 @kadeng @muchulee8 @aakhundov