Skip to content

🍒[cxx-interop] Workaround a template instantiation issue, part 2 #10113

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 1 commit into from
Feb 27, 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
138 changes: 138 additions & 0 deletions llvm/include/llvm/Transforms/Scalar/GVN.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Allocator.h"
Expand Down Expand Up @@ -432,4 +433,141 @@ struct llvm::GVNPass::Expression {
}
};


/// Represents a particular available value that we know how to materialize.
/// Materialization of an AvailableValue never fails. An AvailableValue is
/// implicitly associated with a rematerialization point which is the
/// location of the instruction from which it was formed.
struct llvm::gvn::AvailableValue {
enum class ValType {
SimpleVal, // A simple offsetted value that is accessed.
LoadVal, // A value produced by a load.
MemIntrin, // A memory intrinsic which is loaded from.
UndefVal, // A UndefValue representing a value from dead block (which
// is not yet physically removed from the CFG).
SelectVal, // A pointer select which is loaded from and for which the load
// can be replace by a value select.
};

/// Val - The value that is live out of the block.
Value *Val;
/// Kind of the live-out value.
ValType Kind;

/// Offset - The byte offset in Val that is interesting for the load query.
unsigned Offset = 0;
/// V1, V2 - The dominating non-clobbered values of SelectVal.
Value *V1 = nullptr, *V2 = nullptr;

static AvailableValue get(Value *V, unsigned Offset = 0) {
AvailableValue Res;
Res.Val = V;
Res.Kind = ValType::SimpleVal;
Res.Offset = Offset;
return Res;
}

static AvailableValue getMI(MemIntrinsic *MI, unsigned Offset = 0) {
AvailableValue Res;
Res.Val = MI;
Res.Kind = ValType::MemIntrin;
Res.Offset = Offset;
return Res;
}

static AvailableValue getLoad(LoadInst *Load, unsigned Offset = 0) {
AvailableValue Res;
Res.Val = Load;
Res.Kind = ValType::LoadVal;
Res.Offset = Offset;
return Res;
}

static AvailableValue getUndef() {
AvailableValue Res;
Res.Val = nullptr;
Res.Kind = ValType::UndefVal;
Res.Offset = 0;
return Res;
}

static AvailableValue getSelect(SelectInst *Sel, Value *V1, Value *V2) {
AvailableValue Res;
Res.Val = Sel;
Res.Kind = ValType::SelectVal;
Res.Offset = 0;
Res.V1 = V1;
Res.V2 = V2;
return Res;
}

bool isSimpleValue() const { return Kind == ValType::SimpleVal; }
bool isCoercedLoadValue() const { return Kind == ValType::LoadVal; }
bool isMemIntrinValue() const { return Kind == ValType::MemIntrin; }
bool isUndefValue() const { return Kind == ValType::UndefVal; }
bool isSelectValue() const { return Kind == ValType::SelectVal; }

Value *getSimpleValue() const {
assert(isSimpleValue() && "Wrong accessor");
return Val;
}

LoadInst *getCoercedLoadValue() const {
assert(isCoercedLoadValue() && "Wrong accessor");
return cast<LoadInst>(Val);
}

MemIntrinsic *getMemIntrinValue() const {
assert(isMemIntrinValue() && "Wrong accessor");
return cast<MemIntrinsic>(Val);
}

SelectInst *getSelectValue() const {
assert(isSelectValue() && "Wrong accessor");
return cast<SelectInst>(Val);
}

/// Emit code at the specified insertion point to adjust the value defined
/// here to the specified type. This handles various coercion cases.
Value *MaterializeAdjustedValue(LoadInst *Load, Instruction *InsertPt,
GVNPass &gvn) const;
};

/// Represents an AvailableValue which can be rematerialized at the end of
/// the associated BasicBlock.
struct llvm::gvn::AvailableValueInBlock {
/// BB - The basic block in question.
BasicBlock *BB = nullptr;

/// AV - The actual available value
AvailableValue AV;

static AvailableValueInBlock get(BasicBlock *BB, AvailableValue &&AV) {
AvailableValueInBlock Res;
Res.BB = BB;
Res.AV = std::move(AV);
return Res;
}

static AvailableValueInBlock get(BasicBlock *BB, Value *V,
unsigned Offset = 0) {
return get(BB, AvailableValue::get(V, Offset));
}

static AvailableValueInBlock getUndef(BasicBlock *BB) {
return get(BB, AvailableValue::getUndef());
}

static AvailableValueInBlock getSelect(BasicBlock *BB, SelectInst *Sel,
Value *V1, Value *V2) {
return get(BB, AvailableValue::getSelect(Sel, V1, V2));
}

/// Emit code at the end of this block to adjust the value defined here to
/// the specified type. This handles various coercion cases.
Value *MaterializeAdjustedValue(LoadInst *Load, GVNPass &gvn) const {
return AV.MaterializeAdjustedValue(Load, BB->getTerminator(), gvn);
}
};

#endif // LLVM_TRANSFORMS_SCALAR_GVN_H
136 changes: 0 additions & 136 deletions llvm/lib/Transforms/Scalar/GVN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,142 +155,6 @@ template <> struct DenseMapInfo<GVNPass::Expression> {

} // end namespace llvm

/// Represents a particular available value that we know how to materialize.
/// Materialization of an AvailableValue never fails. An AvailableValue is
/// implicitly associated with a rematerialization point which is the
/// location of the instruction from which it was formed.
struct llvm::gvn::AvailableValue {
enum class ValType {
SimpleVal, // A simple offsetted value that is accessed.
LoadVal, // A value produced by a load.
MemIntrin, // A memory intrinsic which is loaded from.
UndefVal, // A UndefValue representing a value from dead block (which
// is not yet physically removed from the CFG).
SelectVal, // A pointer select which is loaded from and for which the load
// can be replace by a value select.
};

/// Val - The value that is live out of the block.
Value *Val;
/// Kind of the live-out value.
ValType Kind;

/// Offset - The byte offset in Val that is interesting for the load query.
unsigned Offset = 0;
/// V1, V2 - The dominating non-clobbered values of SelectVal.
Value *V1 = nullptr, *V2 = nullptr;

static AvailableValue get(Value *V, unsigned Offset = 0) {
AvailableValue Res;
Res.Val = V;
Res.Kind = ValType::SimpleVal;
Res.Offset = Offset;
return Res;
}

static AvailableValue getMI(MemIntrinsic *MI, unsigned Offset = 0) {
AvailableValue Res;
Res.Val = MI;
Res.Kind = ValType::MemIntrin;
Res.Offset = Offset;
return Res;
}

static AvailableValue getLoad(LoadInst *Load, unsigned Offset = 0) {
AvailableValue Res;
Res.Val = Load;
Res.Kind = ValType::LoadVal;
Res.Offset = Offset;
return Res;
}

static AvailableValue getUndef() {
AvailableValue Res;
Res.Val = nullptr;
Res.Kind = ValType::UndefVal;
Res.Offset = 0;
return Res;
}

static AvailableValue getSelect(SelectInst *Sel, Value *V1, Value *V2) {
AvailableValue Res;
Res.Val = Sel;
Res.Kind = ValType::SelectVal;
Res.Offset = 0;
Res.V1 = V1;
Res.V2 = V2;
return Res;
}

bool isSimpleValue() const { return Kind == ValType::SimpleVal; }
bool isCoercedLoadValue() const { return Kind == ValType::LoadVal; }
bool isMemIntrinValue() const { return Kind == ValType::MemIntrin; }
bool isUndefValue() const { return Kind == ValType::UndefVal; }
bool isSelectValue() const { return Kind == ValType::SelectVal; }

Value *getSimpleValue() const {
assert(isSimpleValue() && "Wrong accessor");
return Val;
}

LoadInst *getCoercedLoadValue() const {
assert(isCoercedLoadValue() && "Wrong accessor");
return cast<LoadInst>(Val);
}

MemIntrinsic *getMemIntrinValue() const {
assert(isMemIntrinValue() && "Wrong accessor");
return cast<MemIntrinsic>(Val);
}

SelectInst *getSelectValue() const {
assert(isSelectValue() && "Wrong accessor");
return cast<SelectInst>(Val);
}

/// Emit code at the specified insertion point to adjust the value defined
/// here to the specified type. This handles various coercion cases.
Value *MaterializeAdjustedValue(LoadInst *Load, Instruction *InsertPt,
GVNPass &gvn) const;
};

/// Represents an AvailableValue which can be rematerialized at the end of
/// the associated BasicBlock.
struct llvm::gvn::AvailableValueInBlock {
/// BB - The basic block in question.
BasicBlock *BB = nullptr;

/// AV - The actual available value
AvailableValue AV;

static AvailableValueInBlock get(BasicBlock *BB, AvailableValue &&AV) {
AvailableValueInBlock Res;
Res.BB = BB;
Res.AV = std::move(AV);
return Res;
}

static AvailableValueInBlock get(BasicBlock *BB, Value *V,
unsigned Offset = 0) {
return get(BB, AvailableValue::get(V, Offset));
}

static AvailableValueInBlock getUndef(BasicBlock *BB) {
return get(BB, AvailableValue::getUndef());
}

static AvailableValueInBlock getSelect(BasicBlock *BB, SelectInst *Sel,
Value *V1, Value *V2) {
return get(BB, AvailableValue::getSelect(Sel, V1, V2));
}

/// Emit code at the end of this block to adjust the value defined here to
/// the specified type. This handles various coercion cases.
Value *MaterializeAdjustedValue(LoadInst *Load, GVNPass &gvn) const {
return AV.MaterializeAdjustedValue(Load, BB->getTerminator(), gvn);
}
};

//===----------------------------------------------------------------------===//
// ValueTable Internal Functions
//===----------------------------------------------------------------------===//
Expand Down