Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ SPDX-License-Identifier: MIT
#include "common/LLVMWarningsPop.hpp"
#include <llvmWrapper/IR/Instructions.h>
#include <llvmWrapper/IR/IRBuilder.h>
#include <algorithm>

using namespace llvm;
using namespace IGC;
Expand Down Expand Up @@ -69,9 +70,11 @@ void LowerByValAttribute::visitCallInst(CallInst &CI) {

if (CI.paramHasAttr(i, llvm::Attribute::ByVal) && !CI.paramHasAttr(i, llvm::Attribute::ReadOnly)) {
Type *ElTy = CI.getParamByValType(i);
Align SrcAlign = std::max(DL.getABITypeAlign(ElTy), CI.getParamAlign(i).valueOrOne());
IGCLLVM::IRBuilder<> builder(&CI);
Value *AI = builder.CreateAlloca(ElTy);
builder.CreateMemCpy(AI, OpI, DL.getTypeAllocSize(ElTy), DL.getABITypeAlign(ElTy).value());
AllocaInst *AI = builder.CreateAlloca(ElTy);
AI->setAlignment(std::max(AI->getAlign(), SrcAlign));
builder.CreateMemCpy(AI, AI->getAlign(), OpI, SrcAlign, DL.getTypeAllocSize(ElTy));
auto AC = builder.CreateAddrSpaceCast(AI, OpITy);
CI.replaceUsesOfWith(OpI, AC);
m_changed = true;
Expand Down
58 changes: 58 additions & 0 deletions IGC/Compiler/tests/LowerByValAttribute/byval-explicit-alignment.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
;=========================== begin_copyright_notice ============================
;
; Copyright (C) 2026 Intel Corporation
;
; SPDX-License-Identifier: MIT
;
;============================ end_copyright_notice =============================
;
; REQUIRES: llvm-16-plus
; RUN: igc_opt --opaque-pointers %s -S -o - --igc-lower-byval-attribute | FileCheck %s

; ------------------------------------------------
; LowerByValAttribute
; ------------------------------------------------
;
; The hidden copy that this pass materialises for a `byval` argument must honour
; the alignment stated by the attribute, not just the ABI alignment of the
; pointee type. `%struct.double8` is a struct of doubles, so its ABI alignment is
; only 8, but the argument is declared `align 64` and the callee (and every pass
; downstream) is entitled to rely on that. Creating the alloca with the default
; alignment leaves the copy 8-byte aligned and the callee then reads the wrong
; bytes.

%struct.double8 = type { double, double, double, double, double, double, double, double }
%struct.plain = type { i32, [10 x i32], i32 }

define spir_kernel void @kernel(ptr byval(%struct.double8) align 64 %s, ptr byval(%struct.plain) %p) {
; CHECK-LABEL: @kernel(

; COM: alignment 64 comes from the byval attribute, not from the struct layout
; CHECK: [[ALLOCA0:%.*]] = alloca %struct.double8, align 64
; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[ALLOCA0]], ptr align 64 %s, i64 64, i1 false)
; CHECK: call void @f0(ptr byval(%struct.double8) align 64 [[ALLOCA0]])
call void @f0(ptr byval(%struct.double8) align 64 %s)

; COM: without an explicit alignment on the attribute nothing changes: the alloca
; COM: keeps the preferred alignment CreateAlloca() gives it (8 for an aggregate
; COM: under the default data layout, even though the ABI alignment is only 4),
; COM: and the source is still only assumed to be ABI aligned.
; CHECK: [[ALLOCA1:%.*]] = alloca %struct.plain, align 8
; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ALLOCA1]], ptr align 4 %p, i64 48, i1 false)
; CHECK: call void @f1(ptr byval(%struct.plain) [[ALLOCA1]])
call void @f1(ptr byval(%struct.plain) %p)

ret void
}

define spir_func void @f0(ptr byval(%struct.double8) align 64 %src) #0 {
store double 2.000000e+00, ptr %src, align 64
ret void
}

define spir_func void @f1(ptr byval(%struct.plain) %src) #0 {
store i32 222, ptr %src, align 4
ret void
}

attributes #0 = { noinline }