Skip to content

[KeyInstr][Clang] Coerced store atoms #134653

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 3, 2025
Merged
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
23 changes: 15 additions & 8 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1424,24 +1424,30 @@ void CodeGenFunction::CreateCoercedStore(llvm::Value *Src, Address Dst,
SrcSize == CGM.getDataLayout().getTypeAllocSize(Dst.getElementType())) {
// If the value is supposed to be a pointer, convert it before storing it.
Src = CoerceIntOrPtrToIntOrPtr(Src, Dst.getElementType(), *this);
Builder.CreateStore(Src, Dst, DstIsVolatile);
auto *I = Builder.CreateStore(Src, Dst, DstIsVolatile);
addInstToCurrentSourceAtom(I, Src);
} else if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(Src->getType())) {
// Prefer scalar stores to first-class aggregate stores.
Dst = Dst.withElementType(SrcTy);
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
Address EltPtr = Builder.CreateStructGEP(Dst, i);
llvm::Value *Elt = Builder.CreateExtractValue(Src, i);
Builder.CreateStore(Elt, EltPtr, DstIsVolatile);
auto *I = Builder.CreateStore(Elt, EltPtr, DstIsVolatile);
addInstToCurrentSourceAtom(I, Elt);
}
} else {
Builder.CreateStore(Src, Dst.withElementType(SrcTy), DstIsVolatile);
auto *I =
Builder.CreateStore(Src, Dst.withElementType(SrcTy), DstIsVolatile);
addInstToCurrentSourceAtom(I, Src);
}
} else if (SrcTy->isIntegerTy()) {
// If the source is a simple integer, coerce it directly.
llvm::Type *DstIntTy = Builder.getIntNTy(DstSize.getFixedValue() * 8);
Src = CoerceIntOrPtrToIntOrPtr(Src, DstIntTy, *this);
Builder.CreateStore(Src, Dst.withElementType(DstIntTy), DstIsVolatile);
auto *I =
Builder.CreateStore(Src, Dst.withElementType(DstIntTy), DstIsVolatile);
addInstToCurrentSourceAtom(I, Src);
} else {
// Otherwise do coercion through memory. This is stupid, but
// simple.
Expand All @@ -1455,10 +1461,11 @@ void CodeGenFunction::CreateCoercedStore(llvm::Value *Src, Address Dst,
RawAddress Tmp =
CreateTempAllocaForCoercion(*this, SrcTy, Dst.getAlignment());
Builder.CreateStore(Src, Tmp);
Builder.CreateMemCpy(Dst.emitRawPointer(*this),
Dst.getAlignment().getAsAlign(), Tmp.getPointer(),
Tmp.getAlignment().getAsAlign(),
Builder.CreateTypeSize(IntPtrTy, DstSize));
auto *I = Builder.CreateMemCpy(
Dst.emitRawPointer(*this), Dst.getAlignment().getAsAlign(),
Tmp.getPointer(), Tmp.getAlignment().getAsAlign(),
Builder.CreateTypeSize(IntPtrTy, DstSize));
addInstToCurrentSourceAtom(I, Src);
}
}

Expand Down
20 changes: 20 additions & 0 deletions clang/test/DebugInfo/KeyInstructions/coerced-packed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %clang_cc1 -gkey-instructions -gno-column-info -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - -triple arm64-apple-ios11 \
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank

// RUN: %clang_cc1 -gkey-instructions -gno-column-info -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - -triple arm64-apple-ios11 \
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank

typedef struct {
char a;
int x;
} __attribute((packed)) S;

S getS();
void f() {
// CHECK: [[call:%.*]] = call i40{{.*}}getS{{.*}}, !dbg [[G1R2:!.*]]
// CHECK: store i40 [[call]], ptr %s, align 1, !dbg [[G1R1:!.*]]
S s = getS();
}

// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
19 changes: 19 additions & 0 deletions clang/test/DebugInfo/KeyInstructions/coerced-ptr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %clang_cc1 -gkey-instructions -gno-column-info -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - -triple x86_64-windows-msvc \
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank

// RUN: %clang_cc1 -gkey-instructions -gno-column-info -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - -triple x86_64-windows-msvc \
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank

typedef struct { int *p; } Ptr;
Ptr getPtr();
void f() {
// CHECK: %call = call i64{{.*}}, !dbg [[G1R3:!.*]]
// CHECK: [[gep:%.*]] = getelementptr inbounds nuw %struct.Ptr, ptr %p, i32 0, i32 0
// CHECK: [[i2p:%.*]] = inttoptr i64 %call to ptr, !dbg [[G1R2:!.*]]
// CHECK: store ptr [[i2p]], ptr [[gep]], align 8, !dbg [[G1R1:!.*]]
Ptr p = getPtr();
}

// CHECK: [[G1R3]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 3)
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
24 changes: 24 additions & 0 deletions clang/test/DebugInfo/KeyInstructions/coerced-through-memory.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_cc1 -gkey-instructions -gno-column-info -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - -triple aarch64-windows-msvc \
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank

// RUN: %clang_cc1 -gkey-instructions -gno-column-info -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - -triple aarch64-windows-msvc \
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank

typedef struct {
short a;
int b;
short c;
} S;

S getS(void);

void f() {
// CHECK: %call = call [2 x i64] {{.*}}getS{{.*}}(), !dbg [[G1R2:!.*]]
//// Note: The store to the tmp alloca isn't part of the atom.
// CHECK: store [2 x i64] %call, ptr %tmp.coerce, align 8
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %s, ptr align 8 %tmp.coerce, i64 12, i1 false), !dbg [[G1R1:!.*]]
S s = getS();
}

// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
36 changes: 36 additions & 0 deletions clang/test/DebugInfo/KeyInstructions/coerced.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %clang_cc1 -gkey-instructions -gno-column-info -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - -triple x86_64-unknown-linux \
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank --check-prefixes=CHECK,CHECK-CXX

// RUN: %clang_cc1 -gkey-instructions -gno-column-info -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - -triple x86_64-unknown-linux \
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank --check-prefixes=CHECK,CHECK-C

typedef struct {
void* a;
void* b;
} Struct;
Struct get();

void test() {
// CHECK: %1 = extractvalue { ptr, ptr } %call, 0, !dbg [[G1R2:!.*]]
// CHECK: store ptr %1, ptr {{.*}}, !dbg [[G1R1:!.*]]
// CHECK: %3 = extractvalue { ptr, ptr } %call, 1, !dbg [[G1R2]]
// CHECK: store ptr %3, ptr {{.*}}, !dbg [[G1R1:!.*]]
Struct s = get();
}

typedef struct { int i; } Int;
Int getInt(void);

// CHECK-C: @test2
// CHECK-CXX: @_Z5test2v
void test2() {
// CHECK: %call = call i32 @{{(_Z6)?}}getInt{{v?}}(), !dbg [[T2_G1R2:!.*]]
// CHECK: [[gep:%.*]] = getelementptr inbounds nuw %struct.Int, ptr %i, i32 0, i32 0
// CHECK: store i32 %call, ptr [[gep]]{{.*}}, !dbg [[T2_G1R1:!.*]]
Int i = getInt();
}

// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
// CHECK: [[T2_G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[T2_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)