Remove GlobalObject::getAlign/setAlignment (#143188)

Currently, GlobalObject has an "alignment" property... but it's
basically nonsense: alignment doesn't mean the same thing for variables
and functions, and it's completely meaningless for ifuncs.

This "removes" (actually marking protected) the methods from
GlobalObject, adds the relevant methods to Function and GlobalVariable,
and adjusts the code appropriately.

This should make future alignment-related cleanups easier.
This commit is contained in:
Eli Friedman
2025-06-09 13:51:03 -07:00
committed by GitHub
parent f9b98e386e
commit 9f82ac5738
18 changed files with 162 additions and 121 deletions

View File

@@ -1038,6 +1038,21 @@ public:
/// Return value: true => null pointer dereference is not undefined.
bool nullPointerIsDefined() const;
/// Returns the alignment of the given function.
///
/// Note that this is the alignment of the code, not the alignment of a
/// function pointer.
MaybeAlign getAlign() const { return GlobalObject::getAlign(); }
/// Sets the alignment attribute of the Function.
void setAlignment(Align Align) { GlobalObject::setAlignment(Align); }
/// Sets the alignment attribute of the Function.
///
/// This method will be deprecated as the alignment property should always be
/// defined.
void setAlignment(MaybeAlign Align) { GlobalObject::setAlignment(Align); }
private:
void allocHungoffUselist();
template<int Idx> void setHungoffOperand(Constant *C);

View File

@@ -67,12 +67,7 @@ private:
public:
GlobalObject(const GlobalObject &) = delete;
/// FIXME: Remove this function once transition to Align is over.
uint64_t getAlignment() const {
MaybeAlign Align = getAlign();
return Align ? Align->value() : 0;
}
protected:
/// Returns the alignment of the given variable or function.
///
/// Note that for functions this is the alignment of the code, not the
@@ -103,6 +98,7 @@ public:
assert(getGlobalObjectSubClassData() == Val && "representation error");
}
public:
/// Check if this global has a custom object file section.
///
/// This is more efficient than calling getSection() and checking for an empty

View File

@@ -298,6 +298,23 @@ public:
///
LLVM_ABI void clearCodeModel();
/// FIXME: Remove this function once transition to Align is over.
uint64_t getAlignment() const {
MaybeAlign Align = getAlign();
return Align ? Align->value() : 0;
}
/// Returns the alignment of the given variable.
MaybeAlign getAlign() const { return GlobalObject::getAlign(); }
/// Sets the alignment attribute of the GlobalVariable.
void setAlignment(Align Align) { GlobalObject::setAlignment(Align); }
/// Sets the alignment attribute of the GlobalVariable.
/// This method will be deprecated as the alignment property should always be
/// defined.
void setAlignment(MaybeAlign Align) { GlobalObject::setAlignment(Align); }
// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Value *V) {
return V->getValueID() == Value::GlobalVariableVal;

View File

@@ -976,32 +976,6 @@ public:
}
}
/// FIXME: Remove this function once transition to Align is over.
uint64_t getAlignment() const {
return cast<llvm::GlobalObject>(Val)->getAlignment();
}
/// Returns the alignment of the given variable or function.
///
/// Note that for functions this is the alignment of the code, not the
/// alignment of a function pointer.
MaybeAlign getAlign() const {
return cast<llvm::GlobalObject>(Val)->getAlign();
}
// TODO: Add missing: setAlignment(Align)
/// Sets the alignment attribute of the GlobalObject.
/// This method will be deprecated as the alignment property should always be
/// defined.
void setAlignment(MaybeAlign Align);
unsigned getGlobalObjectSubClassData() const {
return cast<llvm::GlobalObject>(Val)->getGlobalObjectSubClassData();
}
void setGlobalObjectSubClassData(unsigned V);
/// Check if this global has a custom object file section.
///
/// This is more efficient than calling getSection() and checking for an empty
@@ -1294,6 +1268,18 @@ public:
return cast<llvm::GlobalVariable>(Val)->getCodeModel();
}
/// Returns the alignment of the given variable.
MaybeAlign getAlign() const {
return cast<llvm::GlobalVariable>(Val)->getAlign();
}
// TODO: Add missing: setAligment(Align)
/// Sets the alignment attribute of the GlobalVariable.
/// This method will be deprecated as the alignment property should always be
/// defined.
void setAlignment(MaybeAlign Align);
// TODO: Missing setCodeModel(). Requires custom tracker.
#ifndef NDEBUG

View File

@@ -58,6 +58,16 @@ public:
}
FunctionType *getFunctionType() const;
/// Returns the alignment of the given function.
MaybeAlign getAlign() const { return cast<llvm::Function>(Val)->getAlign(); }
// TODO: Add missing: setAligment(Align)
/// Sets the alignment attribute of the Function.
/// This method will be deprecated as the alignment property should always be
/// defined.
void setAlignment(MaybeAlign Align);
#ifndef NDEBUG
void verify() const final {
assert(isa<llvm::Function>(Val) && "Expected Function!");

View File

@@ -369,7 +369,11 @@ Align AsmPrinter::getGVAlignment(const GlobalObject *GV, const DataLayout &DL,
Alignment = InAlign;
// If the GV has a specified alignment, take it into account.
const MaybeAlign GVAlign(GV->getAlign());
MaybeAlign GVAlign;
if (auto *GVar = dyn_cast<GlobalVariable>(GV))
GVAlign = GVar->getAlign();
else if (auto *F = dyn_cast<Function>(GV))
GVAlign = F->getAlign();
if (!GVAlign)
return Alignment;

View File

@@ -2108,8 +2108,10 @@ LLVMTypeRef LLVMGlobalGetValueType(LLVMValueRef Global) {
unsigned LLVMGetAlignment(LLVMValueRef V) {
Value *P = unwrap(V);
if (GlobalObject *GV = dyn_cast<GlobalObject>(P))
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(P))
return GV->getAlign() ? GV->getAlign()->value() : 0;
if (Function *F = dyn_cast<Function>(P))
return F->getAlign() ? F->getAlign()->value() : 0;
if (AllocaInst *AI = dyn_cast<AllocaInst>(P))
return AI->getAlign().value();
if (LoadInst *LI = dyn_cast<LoadInst>(P))
@@ -2128,8 +2130,10 @@ unsigned LLVMGetAlignment(LLVMValueRef V) {
void LLVMSetAlignment(LLVMValueRef V, unsigned Bytes) {
Value *P = unwrap(V);
if (GlobalObject *GV = dyn_cast<GlobalObject>(P))
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(P))
GV->setAlignment(MaybeAlign(Bytes));
else if (Function *F = dyn_cast<Function>(P))
F->setAlignment(MaybeAlign(Bytes));
else if (AllocaInst *AI = dyn_cast<AllocaInst>(P))
AI->setAlignment(Align(Bytes));
else if (LoadInst *LI = dyn_cast<LoadInst>(P))

View File

@@ -457,10 +457,10 @@ CallInst *IRBuilderBase::CreateInvariantStart(Value *Ptr, ConstantInt *Size) {
}
static MaybeAlign getAlign(Value *Ptr) {
if (auto *O = dyn_cast<GlobalObject>(Ptr))
return O->getAlign();
if (auto *V = dyn_cast<GlobalVariable>(Ptr))
return V->getAlign();
if (auto *A = dyn_cast<GlobalAlias>(Ptr))
return A->getAliaseeObject()->getAlign();
return getAlign(A->getAliaseeObject());
return {};
}

View File

@@ -957,30 +957,27 @@ uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL,
Align Value::getPointerAlignment(const DataLayout &DL) const {
assert(getType()->isPointerTy() && "must be pointer");
if (auto *GO = dyn_cast<GlobalObject>(this)) {
if (isa<Function>(GO)) {
Align FunctionPtrAlign = DL.getFunctionPtrAlign().valueOrOne();
switch (DL.getFunctionPtrAlignType()) {
case DataLayout::FunctionPtrAlignType::Independent:
return FunctionPtrAlign;
case DataLayout::FunctionPtrAlignType::MultipleOfFunctionAlign:
return std::max(FunctionPtrAlign, GO->getAlign().valueOrOne());
}
llvm_unreachable("Unhandled FunctionPtrAlignType");
if (const Function *F = dyn_cast<Function>(this)) {
Align FunctionPtrAlign = DL.getFunctionPtrAlign().valueOrOne();
switch (DL.getFunctionPtrAlignType()) {
case DataLayout::FunctionPtrAlignType::Independent:
return FunctionPtrAlign;
case DataLayout::FunctionPtrAlignType::MultipleOfFunctionAlign:
return std::max(FunctionPtrAlign, F->getAlign().valueOrOne());
}
const MaybeAlign Alignment(GO->getAlign());
llvm_unreachable("Unhandled FunctionPtrAlignType");
} else if (auto *GVar = dyn_cast<GlobalVariable>(this)) {
const MaybeAlign Alignment(GVar->getAlign());
if (!Alignment) {
if (auto *GVar = dyn_cast<GlobalVariable>(GO)) {
Type *ObjectType = GVar->getValueType();
if (ObjectType->isSized()) {
// If the object is defined in the current Module, we'll be giving
// it the preferred alignment. Otherwise, we have to assume that it
// may only have the minimum ABI alignment.
if (GVar->isStrongDefinitionForLinker())
return DL.getPreferredAlign(GVar);
else
return DL.getABITypeAlign(ObjectType);
}
Type *ObjectType = GVar->getValueType();
if (ObjectType->isSized()) {
// If the object is defined in the current Module, we'll be giving
// it the preferred alignment. Otherwise, we have to assume that it
// may only have the minimum ABI alignment.
if (GVar->isStrongDefinitionForLinker())
return DL.getPreferredAlign(GVar);
else
return DL.getABITypeAlign(ObjectType);
}
}
return Alignment.valueOrOne();

View File

@@ -735,12 +735,6 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
"Global is external, but doesn't have external or weak linkage!", &GV);
if (const GlobalObject *GO = dyn_cast<GlobalObject>(&GV)) {
if (MaybeAlign A = GO->getAlign()) {
Check(A->value() <= Value::MaximumAlignment,
"huge alignment values are unsupported", GO);
}
if (const MDNode *Associated =
GO->getMetadata(LLVMContext::MD_associated)) {
Check(Associated->getNumOperands() == 1,
@@ -830,6 +824,11 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
void Verifier::visitGlobalVariable(const GlobalVariable &GV) {
Type *GVType = GV.getValueType();
if (MaybeAlign A = GV.getAlign()) {
Check(A->value() <= Value::MaximumAlignment,
"huge alignment values are unsupported", &GV);
}
if (GV.hasInitializer()) {
Check(GV.getInitializer()->getType() == GVType,
"Global variable initializer type does not match global "
@@ -2869,6 +2868,11 @@ void Verifier::visitFunction(const Function &F) {
Check(!F.hasStructRetAttr() || F.getReturnType()->isVoidTy(),
"Invalid struct return type!", &F);
if (MaybeAlign A = F.getAlign()) {
Check(A->value() <= Value::MaximumAlignment,
"huge alignment values are unsupported", &F);
}
AttributeList Attrs = F.getAttributes();
Check(verifyAttributeCount(Attrs, FT->getNumParams()),

View File

@@ -414,8 +414,11 @@ void LTOModule::addDefinedFunctionSymbol(StringRef Name, const GlobalValue *F) {
void LTOModule::addDefinedSymbol(StringRef Name, const GlobalValue *def,
bool isFunction) {
const GlobalObject *go = dyn_cast<GlobalObject>(def);
uint32_t attr = go ? Log2(go->getAlign().valueOrOne()) : 0;
uint32_t attr = 0;
if (auto *gv = dyn_cast<GlobalVariable>(def))
attr = Log2(gv->getAlign().valueOrOne());
else if (auto *f = dyn_cast<Function>(def))
attr = Log2(f->getAlign().valueOrOne());
// set permissions part
if (isFunction) {

View File

@@ -282,20 +282,11 @@ PoisonValue *PoisonValue::getElementValue(unsigned Idx) const {
cast<llvm::PoisonValue>(Val)->getElementValue(Idx)));
}
void GlobalObject::setAlignment(MaybeAlign Align) {
void GlobalVariable::setAlignment(MaybeAlign Align) {
Ctx.getTracker()
.emplaceIfTracking<
GenericSetter<&GlobalObject::getAlign, &GlobalObject::setAlignment>>(
this);
cast<llvm::GlobalObject>(Val)->setAlignment(Align);
}
void GlobalObject::setGlobalObjectSubClassData(unsigned V) {
Ctx.getTracker()
.emplaceIfTracking<
GenericSetter<&GlobalObject::getGlobalObjectSubClassData,
&GlobalObject::setGlobalObjectSubClassData>>(this);
cast<llvm::GlobalObject>(Val)->setGlobalObjectSubClassData(V);
.emplaceIfTracking<GenericSetter<&GlobalVariable::getAlign,
&GlobalVariable::setAlignment>>(this);
cast<llvm::GlobalVariable>(Val)->setAlignment(Align);
}
void GlobalObject::setSection(StringRef S) {

View File

@@ -17,6 +17,13 @@ FunctionType *Function::getFunctionType() const {
Ctx.getType(cast<llvm::Function>(Val)->getFunctionType()));
}
void Function::setAlignment(MaybeAlign Align) {
Ctx.getTracker()
.emplaceIfTracking<
GenericSetter<&Function::getAlign, &Function::setAlignment>>(this);
cast<llvm::Function>(Val)->setAlignment(Align);
}
#ifndef NDEBUG
void Function::dumpNameAndArgs(raw_ostream &OS) const {
auto *F = cast<llvm::Function>(Val);

View File

@@ -42,6 +42,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachinePostDominators.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DebugCounter.h"
@@ -997,9 +998,9 @@ bool PPCMIPeephole::simplifyCode() {
// the transformation.
bool IsWordAligned = false;
if (SrcMI->getOperand(1).isGlobal()) {
const GlobalObject *GO =
dyn_cast<GlobalObject>(SrcMI->getOperand(1).getGlobal());
if (GO && GO->getAlign() && *GO->getAlign() >= 4 &&
const GlobalVariable *GV =
dyn_cast<GlobalVariable>(SrcMI->getOperand(1).getGlobal());
if (GV && GV->getAlign() && *GV->getAlign() >= 4 &&
(SrcMI->getOperand(1).getOffset() % 4 == 0))
IsWordAligned = true;
} else if (SrcMI->getOperand(1).isImm()) {

View File

@@ -8,7 +8,7 @@
#include "SystemZSubtarget.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
@@ -83,9 +83,9 @@ bool SystemZSubtarget::isAddressedViaADA(const GlobalValue *GV) const {
// least two byte alignment, then generated code can use relative
// instructions to address the variable. Otherwise, use the ADA to address
// the variable.
if (GO->getAlignment() & 0x1) {
return true;
}
if (auto *GV = dyn_cast<GlobalVariable>(GO))
if (GV->getAlign() && (*GV->getAlign()).value() & 0x1)
return true;
// getKindForGlobal only works with definitions
if (GO->isDeclaration()) {

View File

@@ -1546,9 +1546,9 @@ Align llvm::tryEnforceAlignment(Value *V, Align PrefAlign,
return PrefAlign;
}
if (auto *GO = dyn_cast<GlobalObject>(V)) {
if (auto *GV = dyn_cast<GlobalVariable>(V)) {
// TODO: as above, this shouldn't be necessary.
Align CurrentAlign = GO->getPointerAlignment(DL);
Align CurrentAlign = GV->getPointerAlignment(DL);
if (PrefAlign <= CurrentAlign)
return CurrentAlign;
@@ -1556,16 +1556,16 @@ Align llvm::tryEnforceAlignment(Value *V, Align PrefAlign,
// of the global. If the memory we set aside for the global may not be the
// memory used by the final program then it is impossible for us to reliably
// enforce the preferred alignment.
if (!GO->canIncreaseAlignment())
if (!GV->canIncreaseAlignment())
return CurrentAlign;
if (GO->isThreadLocal()) {
unsigned MaxTLSAlign = GO->getParent()->getMaxTLSAlignment() / CHAR_BIT;
if (GV->isThreadLocal()) {
unsigned MaxTLSAlign = GV->getParent()->getMaxTLSAlignment() / CHAR_BIT;
if (MaxTLSAlign && PrefAlign > Align(MaxTLSAlign))
PrefAlign = Align(MaxTLSAlign);
}
GO->setAlignment(PrefAlign);
GV->setAlignment(PrefAlign);
return PrefAlign;
}

View File

@@ -13,18 +13,26 @@ using namespace llvm;
static bool shouldReduceSection(GlobalObject &GO) { return GO.hasSection(); }
static bool shouldReduceAlign(GlobalObject &GO) {
return GO.getAlign().has_value();
static bool shouldReduceAlign(GlobalVariable *GV) {
return GV->getAlign().has_value();
}
static bool shouldReduceAlign(Function *F) { return F->getAlign().has_value(); }
static bool shouldReduceComdat(GlobalObject &GO) { return GO.hasComdat(); }
void llvm::reduceGlobalObjectsDeltaPass(Oracle &O, ReducerWorkItem &Program) {
for (auto &GO : Program.getModule().global_objects()) {
if (shouldReduceSection(GO) && !O.shouldKeep())
GO.setSection("");
if (shouldReduceAlign(GO) && !O.shouldKeep())
GO.setAlignment(MaybeAlign());
if (auto *GV = dyn_cast<GlobalVariable>(&GO)) {
if (shouldReduceAlign(GV) && !O.shouldKeep())
GV->setAlignment(MaybeAlign());
}
if (auto *F = dyn_cast<Function>(&GO)) {
if (shouldReduceAlign(F) && !O.shouldKeep())
F->setAlignment(MaybeAlign());
}
if (shouldReduceComdat(GO) && !O.shouldKeep())
GO.setComdat(nullptr);
}

View File

@@ -1051,29 +1051,6 @@ define void @foo() {
auto *Call = cast<sandboxir::CallInst>(&*It++);
// Check classof(), creation.
auto *GO = cast<sandboxir::GlobalObject>(Call->getCalledOperand());
// Check getAlignment().
EXPECT_EQ(GO->getAlignment(), LLVMGO->getAlignment());
// Check getAlign().
EXPECT_EQ(GO->getAlign(), LLVMGO->getAlign());
// Check setAlignment().
auto OrigMaybeAlign = GO->getAlign();
auto NewMaybeAlign = MaybeAlign(128);
EXPECT_NE(NewMaybeAlign, OrigMaybeAlign);
GO->setAlignment(NewMaybeAlign);
EXPECT_EQ(GO->getAlign(), NewMaybeAlign);
GO->setAlignment(OrigMaybeAlign);
EXPECT_EQ(GO->getAlign(), OrigMaybeAlign);
// Check getGlobalObjectSubClassData().
EXPECT_EQ(GO->getGlobalObjectSubClassData(),
LLVMGO->getGlobalObjectSubClassData());
// Check setGlobalObjectSubClassData().
auto OrigGOSCD = GO->getGlobalObjectSubClassData();
auto NewGOSCD = 1u;
EXPECT_NE(NewGOSCD, OrigGOSCD);
GO->setGlobalObjectSubClassData(NewGOSCD);
EXPECT_EQ(GO->getGlobalObjectSubClassData(), NewGOSCD);
GO->setGlobalObjectSubClassData(OrigGOSCD);
EXPECT_EQ(GO->getGlobalObjectSubClassData(), OrigGOSCD);
// Check hasSection().
EXPECT_EQ(GO->hasSection(), LLVMGO->hasSection());
// Check getSection().
@@ -1284,6 +1261,16 @@ define void @foo() {
EXPECT_EQ(GV0->getCodeModelRaw(), LLVMGV0->getCodeModelRaw());
// Check getCodeModel().
EXPECT_EQ(GV0->getCodeModel(), LLVMGV0->getCodeModel());
// Check getAlign().
EXPECT_EQ(GV0->getAlign(), LLVMGV0->getAlign());
// Check setAlignment().
auto OrigMaybeAlign = GV0->getAlign();
auto NewMaybeAlign = MaybeAlign(128);
EXPECT_NE(NewMaybeAlign, OrigMaybeAlign);
GV0->setAlignment(NewMaybeAlign);
EXPECT_EQ(GV0->getAlign(), NewMaybeAlign);
GV0->setAlignment(OrigMaybeAlign);
EXPECT_EQ(GV0->getAlign(), OrigMaybeAlign);
}
TEST_F(SandboxIRTest, GlobalAlias) {
@@ -1855,6 +1842,17 @@ bb1:
)IR");
}
#endif // NDEBUG
// Check getAlign().
EXPECT_EQ(F0->getAlign(), F0->getAlign());
// Check setAlignment().
auto OrigMaybeAlign = F0->getAlign();
auto NewMaybeAlign = MaybeAlign(128);
EXPECT_NE(NewMaybeAlign, OrigMaybeAlign);
F0->setAlignment(NewMaybeAlign);
EXPECT_EQ(F0->getAlign(), NewMaybeAlign);
F0->setAlignment(OrigMaybeAlign);
EXPECT_EQ(F0->getAlign(), OrigMaybeAlign);
}
TEST_F(SandboxIRTest, Module) {