Skip to content

[InlineAsm] break up Data Bitfield::Element into corresponding fields #66297

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
Sep 15, 2023
Merged
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
79 changes: 35 additions & 44 deletions llvm/include/llvm/IR/InlineAsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,48 +272,45 @@ class InlineAsm final : public Value {
Max = ZT,
};

// These are helper methods for dealing with flags in the INLINEASM SDNode
// in the backend.
// This class is intentionally packed into a 32b value as it is used as a
// MVT::i32 ConstantSDNode SDValue for SelectionDAG and as immediate operands
// on INLINEASM and INLINEASM_BR MachineInstr's.
//
// The encoding of Flag is currently:
// Bits 2-0 - A Kind::* value indicating the kind of the operand.
// Bits 15-3 - The number of SDNode operands associated with this inline
// assembly operand.
// Bits 2-0 - A Kind::* value indicating the kind of the operand. (KindField)
// Bits 15-3 - The number of SDNode operands associated with
// this inline assembly operand. (NumOperands)
// Bit 31 - determines if this is a matched operand. (IsMatched)
// If bit 31 is set:
// Bit 30-16 - The operand number that this operand must match.
// When bits 2-0 are Kind::Mem, the Constraint_* value must be
// obtained from the flags for this operand number.
// Bits 30-16 - The operand number that this operand must match. (MatchedOperandNo)
// Else if bits 2-0 are Kind::Mem:
// Bit 30-16 - A Constraint_* value indicating the original constraint
// code.
// Bits 30-16 - A ConstraintCode:: value indicating the original constraint code. (MemConstraintCode)
// Else:
// Bit 30-16 - The register class ID to use for the operand.
// Bits 30-16 - The register class ID to use for the operand. (RegClass)
//
// Bits 30-16 are called "Data" for lack of a better name. The getter is
// intentionally private; the public methods that rely on that private method
// should be used to check invariants first before accessing Data.
// As such, MatchedOperandNo, MemConstraintCode, and RegClass are views of
// the same slice of bits, but are mutually exclusive depending on the
// fields IsMatched then KindField.
class Flag {
uint32_t Storage;
using KindField = Bitfield::Element<Kind, 0, 3, Kind::Func>;
using NumOperands = Bitfield::Element<unsigned, 3, 13>;
using Data = Bitfield::Element<unsigned, 16, 15>;
using MatchedOperandNo = Bitfield::Element<unsigned, 16, 15>;
using MemConstraintCode = Bitfield::Element<ConstraintCode, 16, 15, ConstraintCode::Max>;
using RegClass = Bitfield::Element<unsigned, 16, 15>;
using IsMatched = Bitfield::Element<bool, 31, 1>;

unsigned getData() const { return Bitfield::get<Data>(Storage); }

unsigned getMatchedOperandNo() const { return Bitfield::get<MatchedOperandNo>(Storage); }
unsigned getRegClass() const { return Bitfield::get<RegClass>(Storage); }
bool isMatched() const { return Bitfield::get<IsMatched>(Storage); }
void setKind(Kind K) { Bitfield::set<KindField>(Storage, K); }
void setNumOperands(unsigned N) { Bitfield::set<NumOperands>(Storage, N); }
void setData(unsigned D) { Bitfield::set<Data>(Storage, D); }
void setIsMatched(bool B) { Bitfield::set<IsMatched>(Storage, B); }

public:
Flag() : Storage(0) {}
explicit Flag(uint32_t F) : Storage(F) {}
Flag(enum Kind K, unsigned NumOps) {
setKind(K);
setNumOperands(NumOps);
setData(0);
setIsMatched(false);
Flag(enum Kind K, unsigned NumOps) : Storage(0) {
Bitfield::set<KindField>(Storage, K);
Bitfield::set<NumOperands>(Storage, NumOps);
}
operator uint32_t() { return Storage; }
Kind getKind() const { return Bitfield::get<KindField>(Storage); }
Expand Down Expand Up @@ -356,7 +353,7 @@ class InlineAsm final : public Value {
bool isUseOperandTiedToDef(unsigned &Idx) const {
if (!isMatched())
return false;
Idx = getData();
Idx = getMatchedOperandNo();
return true;
}

Expand All @@ -367,28 +364,24 @@ class InlineAsm final : public Value {
return false;
// setRegClass() uses 0 to mean no register class, and otherwise stores
// RC + 1.
if (!getData())
if (!getRegClass())
return false;
RC = getData() - 1;
RC = getRegClass() - 1;
return true;
}

ConstraintCode getMemoryConstraintID() const {
assert((isMemKind() || isFuncKind()) &&
"Not expected mem or function flag!");
uint32_t D = getData();
assert(D <= static_cast<uint32_t>(ConstraintCode::Max) &&
D >= static_cast<uint32_t>(ConstraintCode::Unknown) &&
"unexpected value for memory constraint");
return static_cast<ConstraintCode>(D);
return Bitfield::get<MemConstraintCode>(Storage);
}

/// setMatchingOp - Augment an existing flag with information indicating
/// that this input operand is tied to a previous output operand.
void setMatchingOp(unsigned MatchedOperandNo) {
assert(getData() == 0 && "Matching operand already set");
setData(MatchedOperandNo);
setIsMatched(true);
void setMatchingOp(unsigned OperandNo) {
assert(getMatchedOperandNo() == 0 && "Matching operand already set");
Bitfield::set<MatchedOperandNo>(Storage, OperandNo);
Bitfield::set<IsMatched>(Storage, true);
}

/// setRegClass - Augment an existing flag with the required register class
Expand All @@ -397,25 +390,23 @@ class InlineAsm final : public Value {
void setRegClass(unsigned RC) {
assert(!isImmKind() && "Immediates cannot have a register class");
assert(!isMemKind() && "Memory operand cannot have a register class");
assert(getData() == 0 && "Register class already set");
assert(getRegClass() == 0 && "Register class already set");
// Store RC + 1, reserve the value 0 to mean 'no register class'.
setData(RC + 1);
Bitfield::set<RegClass>(Storage, RC + 1);
}

/// setMemConstraint - Augment an existing flag with the constraint code for
/// a memory constraint.
void setMemConstraint(ConstraintCode C) {
assert((isMemKind() || isFuncKind()) &&
"Flag is not a memory or function constraint!");
assert(getData() == 0 && "Mem constraint already set");
setData(static_cast<uint32_t>(C));
assert(getMemoryConstraintID() == ConstraintCode::Unknown && "Mem constraint already set");
Bitfield::set<MemConstraintCode>(Storage, C);
}
/// clearMemConstraint - Similar to setMemConstraint(0), but without the
/// assertion checking that the constraint has not been set previously.
void clearMemConstraint() {
assert((isMemKind() || isFuncKind()) &&
"Flag is not a memory or function constraint!");
setData(0);
Bitfield::set<MemConstraintCode>(Storage, ConstraintCode::Unknown);
}
};

Expand Down