[clang][codegen] Additional tests for vbptr memory size calculation (#185703)
This patch adds three vbptr and 32 bit test cases for additional coverage Follow-up to https://github.com/llvm/llvm-project/pull/184558
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
// RUN: %clang_cc1 -triple i686-windows-msvc -std=c++17 -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
// Test for the fix in EmitNullBaseClassInitialization where the calculation
|
||||
// of SplitAfterSize was incorrect when multiple vbptrs are present.
|
||||
// This is the 32-bit version of the test.
|
||||
|
||||
namespace test {
|
||||
|
||||
class Base {
|
||||
public:
|
||||
virtual ~Base() {}
|
||||
};
|
||||
|
||||
class Left : public virtual Base {
|
||||
};
|
||||
|
||||
class Right : public virtual Base {
|
||||
};
|
||||
|
||||
class Diamond : public Left, public Right {
|
||||
};
|
||||
|
||||
// Test 1: Diamond inheritance in a template that triggers the bug
|
||||
template<typename T>
|
||||
class Derived : public Diamond {
|
||||
public:
|
||||
// CHECK-LABEL: define {{.*}} @"??0?$Derived@H@test@@QAE@XZ"
|
||||
|
||||
// Layout of Derived<int> (32-bit):
|
||||
// offset 0: vbptr for Left (4 bytes)
|
||||
// offset 4: vbptr for Right (4 bytes)
|
||||
// offset 8+: virtual base Base
|
||||
|
||||
// CHECK: call {{.*}} @"??0Diamond@test@@QAE@XZ"
|
||||
// EmitNullBaseClassInitialization now correctly calculates memory regions
|
||||
// around the vbptrs without hitting negative size assertion
|
||||
|
||||
// No memset is generated since there are no gaps to zero
|
||||
// CHECK-NOT: call void @llvm.memset
|
||||
// CHECK: ret
|
||||
|
||||
Derived() : Diamond() {}
|
||||
};
|
||||
|
||||
// Explicit instantiation to trigger code generation
|
||||
template class Derived<int>;
|
||||
|
||||
// Test 2: Diamond in a template, with data members (calls memset)
|
||||
class DiamondWithData : public Left, public Right {
|
||||
public:
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class DerivedWithData : public DiamondWithData {
|
||||
public:
|
||||
DerivedWithData();
|
||||
};
|
||||
|
||||
// CHECK-LABEL: define {{.*}} @"??0?$DerivedWithData@H@test@@QAE@XZ"
|
||||
//
|
||||
// Layout of DerivedWithData<int> (32-bit):
|
||||
// offset 0: vbptr for Left (4 bytes)
|
||||
// offset 4: vbptr for Right (4 bytes)
|
||||
// offset 8: x (4 bytes)
|
||||
// offset 12: y (4 bytes)
|
||||
// offset 16+: virtual base Base
|
||||
//
|
||||
// EmitNullBaseClassInitialization zero-initializes the data members [8, 16)
|
||||
// while skipping both vbptrs [0, 8)
|
||||
//
|
||||
// memset zeros 8 bytes for x and y at offset 8
|
||||
// CHECK: call void @llvm.memset.p0.i32(ptr {{.*}}, i8 0, i32 8, i1 false)
|
||||
// CHECK: ret
|
||||
|
||||
template<typename T>
|
||||
DerivedWithData<T>::DerivedWithData() : DiamondWithData() {
|
||||
}
|
||||
|
||||
template struct DerivedWithData<int>;
|
||||
|
||||
// Test 3: Three vbptrs test case
|
||||
|
||||
// Three separate classes that virtually inherit from Base
|
||||
class Middle : public virtual Base {
|
||||
};
|
||||
|
||||
// TriDiamond has three vbptrs - one from each base class
|
||||
class TriDiamond : public Left, public Middle, public Right {
|
||||
};
|
||||
|
||||
// Test 3a: Template instantiation with three vbptrs (no data members)
|
||||
template<typename T>
|
||||
class TriDerived : public TriDiamond {
|
||||
public:
|
||||
// CHECK-LABEL: define {{.*}} @"??0?$TriDerived@H@test@@QAE@XZ"
|
||||
|
||||
// Layout of TriDerived<int> (32-bit):
|
||||
// offset 0: vbptr for Left (4 bytes)
|
||||
// offset 4: vbptr for Middle (4 bytes)
|
||||
// offset 8: vbptr for Right (4 bytes)
|
||||
// offset 12+: virtual base Base
|
||||
|
||||
// CHECK: call {{.*}} @"??0TriDiamond@test@@QAE@XZ"
|
||||
// No memset is generated since there are no gaps to zero
|
||||
// CHECK-NOT: call void @llvm.memset
|
||||
// CHECK: ret
|
||||
|
||||
TriDerived() : TriDiamond() {}
|
||||
};
|
||||
|
||||
// Explicit instantiation to trigger code generation
|
||||
template class TriDerived<int>;
|
||||
|
||||
// Test 3b: Three vbptrs with data members (calls memset)
|
||||
class TriDiamondWithData : public Left, public Middle, public Right {
|
||||
public:
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class TriDerivedWithData : public TriDiamondWithData {
|
||||
public:
|
||||
TriDerivedWithData();
|
||||
};
|
||||
|
||||
// CHECK-LABEL: define {{.*}} @"??0?$TriDerivedWithData@H@test@@QAE@XZ"
|
||||
//
|
||||
// Layout of TriDerivedWithData<int> (32-bit):
|
||||
// offset 0: vbptr for Left (4 bytes)
|
||||
// offset 4: vbptr for Middle (4 bytes)
|
||||
// offset 8: vbptr for Right (4 bytes)
|
||||
// offset 12: a (4 bytes)
|
||||
// offset 16: b (4 bytes)
|
||||
// offset 20+: virtual base Base
|
||||
|
||||
// memset zeros 8 bytes [12, 20)
|
||||
// CHECK: call void @llvm.memset.p0.i32(ptr {{.*}}, i8 0, i32 8, i1 false)
|
||||
// CHECK: ret
|
||||
|
||||
template<typename T>
|
||||
TriDerivedWithData<T>::TriDerivedWithData() : TriDiamondWithData() {
|
||||
}
|
||||
|
||||
template struct TriDerivedWithData<int>;
|
||||
|
||||
// Test 4: Another case which triggers the bug (similar to Test 1, non-template)
|
||||
class Interface {
|
||||
public:
|
||||
virtual ~Interface() {}
|
||||
};
|
||||
|
||||
class Base1If : public virtual Interface {
|
||||
};
|
||||
|
||||
class Base2If : public virtual Interface {
|
||||
};
|
||||
|
||||
class BaseIf : public Base1If, public Base2If {
|
||||
};
|
||||
|
||||
class DerivedClass : public BaseIf {
|
||||
public:
|
||||
// CHECK-LABEL: define {{.*}} @"??0DerivedClass@test@@QAE@XZ"
|
||||
|
||||
// Layout of DerivedClass (32-bit):
|
||||
// offset 0: vbptr for Base1If (4 bytes)
|
||||
// offset 4: vbptr for Base2If (4 bytes)
|
||||
// offset 8+: virtual base Interface
|
||||
|
||||
// CHECK: call {{.*}} @"??0BaseIf@test@@QAE@XZ"
|
||||
// EmitNullBaseClassInitialization now correctly calculates memory regions
|
||||
// around the vbptrs without hitting negative size assertion
|
||||
|
||||
// No memset is generated since there are no gaps to zero
|
||||
// CHECK-NOT: call void @llvm.memset
|
||||
// CHECK: ret
|
||||
|
||||
DerivedClass()
|
||||
: BaseIf()
|
||||
{ }
|
||||
};
|
||||
|
||||
// Instantiate to trigger code generation
|
||||
DerivedClass d;
|
||||
|
||||
// Test 4c: Non-template version with three vbptrs
|
||||
class TriConcreteClass : public TriDiamond {
|
||||
public:
|
||||
// CHECK-LABEL: define {{.*}} @"??0TriConcreteClass@test@@QAE@XZ"
|
||||
|
||||
// Layout of TriConcreteClass (32-bit):
|
||||
// offset 0: vbptr for Left (4 bytes)
|
||||
// offset 4: vbptr for Middle (4 bytes)
|
||||
// offset 8: vbptr for Right (4 bytes)
|
||||
// offset 12+: virtual base Base
|
||||
|
||||
// CHECK: call {{.*}} @"??0TriDiamond@test@@QAE@XZ"
|
||||
// No memset is generated since there are no gaps to zero
|
||||
// CHECK-NOT: call void @llvm.memset
|
||||
// CHECK: ret
|
||||
|
||||
TriConcreteClass() : TriDiamond() {}
|
||||
};
|
||||
|
||||
// Instantiate to trigger code generation
|
||||
TriConcreteClass tc;
|
||||
|
||||
|
||||
} // namespace test
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
//
|
||||
// memset zeros 8 bytes for x and y at offset 16
|
||||
// CHECK: call void @llvm.memset.p0.i64(ptr {{.*}}, i8 0, i64 8, i1 false)
|
||||
// CHECK: ret
|
||||
|
||||
template<typename T>
|
||||
DerivedWithData<T>::DerivedWithData() : DiamondWithData() {
|
||||
@@ -78,7 +79,73 @@ DerivedWithData<T>::DerivedWithData() : DiamondWithData() {
|
||||
|
||||
template struct DerivedWithData<int>;
|
||||
|
||||
// Test 3: Another case which triggers the bug (similar to Test 1, non-template)
|
||||
// Test 3: Three vbptrs test case
|
||||
|
||||
// Three separate classes that virtually inherit from Base
|
||||
class Middle : public virtual Base {
|
||||
};
|
||||
|
||||
// TriDiamond has three vbptrs - one from each base class
|
||||
class TriDiamond : public Left, public Middle, public Right {
|
||||
};
|
||||
|
||||
// Test 3a: Template instantiation with three vbptrs (no data members)
|
||||
template<typename T>
|
||||
class TriDerived : public TriDiamond {
|
||||
public:
|
||||
// CHECK-LABEL: define {{.*}} @"??0?$TriDerived@H@test@@QEAA@XZ"
|
||||
|
||||
// Layout of TriDerived<int>:
|
||||
// offset 0: vbptr for Left (8 bytes)
|
||||
// offset 8: vbptr for Middle (8 bytes)
|
||||
// offset 16: vbptr for Right (8 bytes)
|
||||
// offset 24+: virtual base Base
|
||||
|
||||
// CHECK: call {{.*}} @"??0TriDiamond@test@@QEAA@XZ"
|
||||
// No memset is generated since there are no gaps to zero
|
||||
// CHECK-NOT: call void @llvm.memset
|
||||
// CHECK: ret
|
||||
|
||||
TriDerived() : TriDiamond() {}
|
||||
};
|
||||
|
||||
// Explicit instantiation to trigger code generation
|
||||
template class TriDerived<int>;
|
||||
|
||||
// Test 3b: Three vbptrs with data members (calls memset)
|
||||
class TriDiamondWithData : public Left, public Middle, public Right {
|
||||
public:
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class TriDerivedWithData : public TriDiamondWithData {
|
||||
public:
|
||||
TriDerivedWithData();
|
||||
};
|
||||
|
||||
// CHECK-LABEL: define {{.*}} @"??0?$TriDerivedWithData@H@test@@QEAA@XZ"
|
||||
//
|
||||
// Layout of TriDerivedWithData<int>:
|
||||
// offset 0: vbptr for Left (8 bytes)
|
||||
// offset 8: vbptr for Middle (8 bytes)
|
||||
// offset 16: vbptr for Right (8 bytes)
|
||||
// offset 24: a (4 bytes)
|
||||
// offset 28: b (4 bytes)
|
||||
// offset 32+: virtual base Base
|
||||
|
||||
// memset zeros 8 bytes [24, 32)
|
||||
// CHECK: call void @llvm.memset.p0.i64(ptr {{.*}}, i8 0, i64 8, i1 false)
|
||||
// CHECK: ret
|
||||
|
||||
template<typename T>
|
||||
TriDerivedWithData<T>::TriDerivedWithData() : TriDiamondWithData() {
|
||||
}
|
||||
|
||||
template struct TriDerivedWithData<int>;
|
||||
|
||||
// Test 4: Another case which triggers the bug (similar to Test 1, non-template)
|
||||
class Interface {
|
||||
public:
|
||||
virtual ~Interface() {}
|
||||
@@ -118,5 +185,27 @@ public:
|
||||
// Instantiate to trigger code generation
|
||||
DerivedClass d;
|
||||
|
||||
// Test 4c: Non-template version with three vbptrs
|
||||
class TriConcreteClass : public TriDiamond {
|
||||
public:
|
||||
// CHECK-LABEL: define {{.*}} @"??0TriConcreteClass@test@@QEAA@XZ"
|
||||
|
||||
// Layout of TriConcreteClass:
|
||||
// offset 0: vbptr for Left (8 bytes)
|
||||
// offset 8: vbptr for Middle (8 bytes)
|
||||
// offset 16: vbptr for Right (8 bytes)
|
||||
// offset 24+: virtual base Base
|
||||
|
||||
// CHECK: call {{.*}} @"??0TriDiamond@test@@QEAA@XZ"
|
||||
// No memset is generated since there are no gaps to zero
|
||||
// CHECK-NOT: call void @llvm.memset
|
||||
// CHECK: ret
|
||||
|
||||
TriConcreteClass() : TriDiamond() {}
|
||||
};
|
||||
|
||||
// Instantiate to trigger code generation
|
||||
TriConcreteClass tc;
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
Reference in New Issue
Block a user