본문으로 건너뛰기

[Triton] AMD ConvertToBufferOps에서 i64 offset 지원

들어가며

AMD GPU의 buffer 명령어(buffer_load/buffer_store)는 32비트 offset만 지원한다. 기존 Triton의 ConvertToBufferOps 패스는 64비트 offset을 사용하는 load/store를 무조건 거부하여, flex attention 같은 64비트 포인터 연산을 사용하는 커널이 느린 일반 load로 fallback되었다. 이 PR은 offset이 안전하다고 증명 가능할 때 자동으로 32비트로 truncate하여 빠른 buffer 명령어를 사용하도록 한다.

핵심 코드 분석

Before

i64 offset이 있는 load는 tt.load로 남아 buffer 변환이 일어나지 않았다:

%ptr = tt.addptr %base, %offset : tensor<1024x!tt.ptr<f32>>, tensor<1024xi64>
%val = tt.load %ptr : tensor<1024x!tt.ptr<f32>>

After

offset이 안전한 범위(non-negative, bounded)라고 증명되면 trunci 후 buffer 연산으로 변환된다:

%truncated = arith.trunci %offset : tensor<1024xi64> to tensor<1024xi32>
%val = amdg.buffer_load %base_ptr[%truncated] : tensor<1024xf32>

안전성 증명은 세 가지 경로로 수행된다:

  1. Range analysis: make_range + extsi + 상수 곱셈이면 값 범위를 추론할 수 있다
  2. tt.pointer_range 속성: 커널 인자에 tt.pointer_range = 32가 설정되어 있으면 32비트 범위 보장
  3. 음수 가능성 검사: offset이 음수일 수 있으면 변환하지 않는다
// 안전한 케이스: make_range [0, 256) * 1024 => 항상 non-negative, bounded
%range = tt.make_range {end = 256, start = 0}
%range_ext = arith.extsi %range : tensor<256xi32> to tensor<256xi64>
%offset = arith.muli %range_ext, %stride  // stride=1024

// 위험한 케이스: 임의 i64 값 => 변환 안 함
%splat_off = tt.splat %arg1 : i64 -> tensor<256xi64>

왜 이게 좋은가

  • 성능 향상: flex attention 등 대형 텐서 커널에서 buffer 명령어를 사용할 수 있게 되어 메모리 접근 성능이 개선된다.
  • 안전한 변환: 증명 불가능한 경우 변환하지 않아 정확성을 보장한다.
  • 루프 내 지원: scf.for 루프 내에서도 offset 범위를 추적하여 변환한다.

정리

+193/-104의 변경으로, 정적 분석 기반 최적화의 좋은 사례를 보여준다. "안전하면 최적화, 불확실하면 보수적으로"라는 컴파일러 최적화의 원칙이 잘 드러난다.

참고 자료


이 글은 AI(Claude)의 도움을 받아 작성되었습니다. 코드 분석 내용은 실제 PR diff를 기반으로 합니다.

댓글