Skip to content

Commit 06e1bca

Browse files
[InlineAsm] break up Data Bitfield::Element into corresponding fields (#66297)
Use multiple Bitfield::Element's to provide more meaningful access to the same slice of bits. "Data" used in different contexts is confusing. Try to be as clear as possible, and in that vein, update the comment block for this class, too. This was suggested by @bwendling in #65649 (comment) and @jyknight in #65649 (review)
1 parent d8626c3 commit 06e1bca

File tree

1 file changed

+35
-44
lines changed

1 file changed

+35
-44
lines changed

llvm/include/llvm/IR/InlineAsm.h

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -272,48 +272,45 @@ class InlineAsm final : public Value {
272272
Max = ZT,
273273
};
274274

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

302-
unsigned getData() const { return Bitfield::get<Data>(Storage); }
303+
304+
unsigned getMatchedOperandNo() const { return Bitfield::get<MatchedOperandNo>(Storage); }
305+
unsigned getRegClass() const { return Bitfield::get<RegClass>(Storage); }
303306
bool isMatched() const { return Bitfield::get<IsMatched>(Storage); }
304-
void setKind(Kind K) { Bitfield::set<KindField>(Storage, K); }
305-
void setNumOperands(unsigned N) { Bitfield::set<NumOperands>(Storage, N); }
306-
void setData(unsigned D) { Bitfield::set<Data>(Storage, D); }
307-
void setIsMatched(bool B) { Bitfield::set<IsMatched>(Storage, B); }
308307

309308
public:
310309
Flag() : Storage(0) {}
311310
explicit Flag(uint32_t F) : Storage(F) {}
312-
Flag(enum Kind K, unsigned NumOps) {
313-
setKind(K);
314-
setNumOperands(NumOps);
315-
setData(0);
316-
setIsMatched(false);
311+
Flag(enum Kind K, unsigned NumOps) : Storage(0) {
312+
Bitfield::set<KindField>(Storage, K);
313+
Bitfield::set<NumOperands>(Storage, NumOps);
317314
}
318315
operator uint32_t() { return Storage; }
319316
Kind getKind() const { return Bitfield::get<KindField>(Storage); }
@@ -356,7 +353,7 @@ class InlineAsm final : public Value {
356353
bool isUseOperandTiedToDef(unsigned &Idx) const {
357354
if (!isMatched())
358355
return false;
359-
Idx = getData();
356+
Idx = getMatchedOperandNo();
360357
return true;
361358
}
362359

@@ -367,28 +364,24 @@ class InlineAsm final : public Value {
367364
return false;
368365
// setRegClass() uses 0 to mean no register class, and otherwise stores
369366
// RC + 1.
370-
if (!getData())
367+
if (!getRegClass())
371368
return false;
372-
RC = getData() - 1;
369+
RC = getRegClass() - 1;
373370
return true;
374371
}
375372

376373
ConstraintCode getMemoryConstraintID() const {
377374
assert((isMemKind() || isFuncKind()) &&
378375
"Not expected mem or function flag!");
379-
uint32_t D = getData();
380-
assert(D <= static_cast<uint32_t>(ConstraintCode::Max) &&
381-
D >= static_cast<uint32_t>(ConstraintCode::Unknown) &&
382-
"unexpected value for memory constraint");
383-
return static_cast<ConstraintCode>(D);
376+
return Bitfield::get<MemConstraintCode>(Storage);
384377
}
385378

386379
/// setMatchingOp - Augment an existing flag with information indicating
387380
/// that this input operand is tied to a previous output operand.
388-
void setMatchingOp(unsigned MatchedOperandNo) {
389-
assert(getData() == 0 && "Matching operand already set");
390-
setData(MatchedOperandNo);
391-
setIsMatched(true);
381+
void setMatchingOp(unsigned OperandNo) {
382+
assert(getMatchedOperandNo() == 0 && "Matching operand already set");
383+
Bitfield::set<MatchedOperandNo>(Storage, OperandNo);
384+
Bitfield::set<IsMatched>(Storage, true);
392385
}
393386

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

405398
/// setMemConstraint - Augment an existing flag with the constraint code for
406399
/// a memory constraint.
407400
void setMemConstraint(ConstraintCode C) {
408-
assert((isMemKind() || isFuncKind()) &&
409-
"Flag is not a memory or function constraint!");
410-
assert(getData() == 0 && "Mem constraint already set");
411-
setData(static_cast<uint32_t>(C));
401+
assert(getMemoryConstraintID() == ConstraintCode::Unknown && "Mem constraint already set");
402+
Bitfield::set<MemConstraintCode>(Storage, C);
412403
}
413404
/// clearMemConstraint - Similar to setMemConstraint(0), but without the
414405
/// assertion checking that the constraint has not been set previously.
415406
void clearMemConstraint() {
416407
assert((isMemKind() || isFuncKind()) &&
417408
"Flag is not a memory or function constraint!");
418-
setData(0);
409+
Bitfield::set<MemConstraintCode>(Storage, ConstraintCode::Unknown);
419410
}
420411
};
421412

0 commit comments

Comments
 (0)