Skip to content
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

[WebAssembly] Split separate component LiveIntervals for TEEs #131561

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

aheejin
Copy link
Member

@aheejin aheejin commented Mar 17, 2025

MachineVerifier requires that a virtual register's LiveInterval has only one connected component:

// Check the LI only has one connected component.
ConnectedVNInfoEqClasses ConEQ(*LiveInts);
unsigned NumComp = ConEQ.Classify(LI);
if (NumComp > 1) {
report("Multiple connected components in live interval", MF);
report_context(LI);
for (unsigned comp = 0; comp != NumComp; ++comp) {
OS << comp << ": valnos";
for (const VNInfo *I : LI.valnos)
if (comp == ConEQ.getEqClass(I))
OS << ' ' << I->id;
OS << '\n';
}
}
(This is different from SSA; there can be multiple defs for a register, but those live intervals should somehow be connected. I am not very sure why this rule exists, but this rule apparently has been there forever since 260fa28.)


And it turns out our TEE generation in RegStackify can create virtual registers with LiveInterval with multiple disconnected segments.

This is how TEE generation works:

/// A multiple-use def in the same block with no intervening memory or register
/// dependencies; move the def down, nest it with the current instruction, and
/// insert a tee to satisfy the rest of the uses. As an illustration, rewrite
/// this:
///
/// Reg = INST ... // Def
/// INST ..., Reg, ... // Insert
/// INST ..., Reg, ...
/// INST ..., Reg, ...
///
/// to this:
///
/// DefReg = INST ... // Def (to become the new Insert)
/// TeeReg, Reg = TEE_... DefReg
/// INST ..., TeeReg, ... // Insert
/// INST ..., Reg, ...
/// INST ..., Reg, ...
///
/// with DefReg and TeeReg stackified. This eliminates a local.get from the
/// resulting code.

But it is possible that Reg = INST can also use Reg:

0   Reg = ...
    ...
1   Reg = INST ..., Reg, ...   // It both defs and uses 'Reg'
2   INST ..., Reg, ...
3   INST ..., Reg, ...
4   INST ..., Reg, ...

In this pseudocode, Reg's live interval is [0r,1r),[1r:4r), which has two segments that are connected. But after the TEE transformation,

0   Reg = ...
    ...
1   DefReg = INST ..., Reg, ...
2   TeeReg, Reg = TEE_... DefReg
3   INST ..., TeeReg, ...
4   INST ..., Reg, ...
5   INST ..., Reg, ...

now %0's live interval is [0r,1r),[2r,4r), which are not connected anymore.

In many cases, these split segments are connected by another segment generated by a PHI (or a block start boundary that used to be a PHI). For example, if there is a loop,

bb.0:
  successors: %bb.1
0   Reg = INST ...
    ...

bb.1:
  ; predecessors: %bb.0, %bb.1
    successors: %bb.1, %bb.2
1   DefReg = INST ..., Reg, ...
2   TeeReg, Reg = TEE_... DefReg
3   INST ..., TeeReg, ...
4   INST ..., Reg, ...
5   INST ..., Reg, ...
6   BR_IF bb.1

bb.2:
  ; predecessors: %bb.1
7   INST ...

The live interval would be [0r,1B),[1B,1r),[2r,7B) and these three segments are classified as a single equivalence class because of the segment [1B,1r) starting at the merging point (which used to be a PHI) at the start of bb.1. But this kind of connection is not always guaranteed. The method that determines whether all components are connected, i.e., there is a single equivalence class in a LiveRange, is ConnectedVNInfoEqClasses::Classify.


In RegStackify, there is a routine that splits live intervals into multiple registers in some cases:

// Shrink LI to its uses, cleaning up LI.
static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) {
if (LIS.shrinkToUses(&LI)) {
SmallVector<LiveInterval *, 4> SplitLIs;
LIS.splitSeparateComponents(LI, SplitLIs);
}
}
It looks this was copied from
/// Wrapper method for \see LiveIntervals::shrinkToUses.
/// This method does the proper fixing of the live-ranges when the afore
/// mentioned method returns true.
void shrinkToUses(LiveInterval *LI,
SmallVectorImpl<MachineInstr *> *Dead = nullptr) {
NumShrinkToUses++;
if (LIS->shrinkToUses(LI, Dead)) {
/// Check whether or not \p LI is composed by multiple connected
/// components and if that is the case, fix that.
SmallVector<LiveInterval *, 8> SplitLIs;
LIS->splitSeparateComponents(*LI, SplitLIs);
}
}

But LiveIntervals::shrinkToUses does not return true for all unconnected live intervals. I don't understand all the details of that function or why RegisterCoalescer::shrinkToUses was written that way, but it looks it returns true when there are some dead components:

// Handle dead values.
bool CanSeparate = computeDeadValues(*li, dead);
LLVM_DEBUG(dbgs() << "Shrunk: " << *li << '\n');
return CanSeparate;
And the case in the attached test case does not return true here, but still has multiple unconnected components and does not pass MachineVerifier unless they are split.


So this PR runs LiveIntervals::splitSeparateComponents regardless of the return value of LiveIntervals::shrinkToUses. splitSeparateComponents won't do anything unless there are multiple unconnected components to split.


This is one of the bugs reported in #126916.

`MachineVerifier` requires that a virtual register's `LiveInterval` has
only one connected component:
https://github.com/llvm/llvm-project/blob/f4043f451d0e8c30c8a9826ce87a6e76f3ace468/llvm/lib/CodeGen/MachineVerifier.cpp#L3923-L3936
(This is different from SSA; there can be multiple defs for a register,
but those live intervals should somehow be _connected_. I am not very
sure why this rule exists, but this rule apparently has been there
forever since
llvm@260fa28.)

---

And it turns out our `TEE` generation in RegStackify can create virtual
registers with `LiveInterval` with multiple disconnected segments.

This is how `TEE` generation works:
https://github.com/llvm/llvm-project/blob/f4043f451d0e8c30c8a9826ce87a6e76f3ace468/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp#L613-L632

But it is possible that `Reg = INST` can also use `Reg`:
```
0   Reg = ...
    ...
1   Reg = INST ..., Reg, ...   // It both defs and uses 'Reg'
2   INST ..., Reg, ...
3   INST ..., Reg, ...
4   INST ..., Reg, ...
```
In this pseudocode, `Reg`'s live interval is `[0r,1r),[1r:4r)`, which
has two segments that are connected. But after the `TEE` transformation,
```
0   Reg = ...
    ...
1   DefReg = INST ..., Reg, ...
2   TeeReg, Reg = TEE_... DefReg
3   INST ..., TeeReg, ...
4   INST ..., Reg, ...
5   INST ..., Reg, ...
```
now `%0`'s live interval is `[0r,1r),[2r,4r)`, which are not connected
anymore.

In many cases, these split segments are connected by another segment
generated by a `PHI` (or a block start boundary that used to be a
`PHI`). For example, if there is a loop,
```
bb.0:
  successors: %bb.1
0   Reg = INST ...
    ...

bb.1:
  ; predecessors: %bb.1
    successors: %bb.1, %bb.2
1   DefReg = INST ..., Reg, ...
2   TeeReg, Reg = TEE_... DefReg
3   INST ..., TeeReg, ...
4   INST ..., Reg, ...
5   INST ..., Reg, ...
6   BR_IF bb.1

bb.2:
  ; predecessors: %bb.1
7   INST ...
```
The live interval would be `[0r,1B),[1B,1r),[2r,7B)` and these three
segments are classified as a single equivalence class because of the
segment `[1B,1r)` starting at the merging point (which used to be a
`PHI`) at the start of bb.1. But this kind of connection is not always
guaranteed. The method that determines whether all components are
connected, i.e., there is a single equivalence class in a `LiveRange`,
is `ConnectedVNInfoEqClasses::Classify`.

---

In RegStackify, there is a routine that splits live intervals into
multiple registers in some cases:
https://github.com/llvm/llvm-project/blob/f4043f451d0e8c30c8a9826ce87a6e76f3ace468/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp#L511-L517
It looks this was copied from
https://github.com/llvm/llvm-project/blob/dc9a183ac6aa2d087ceac56970255b06c4772ca3/llvm/lib/CodeGen/RegisterCoalescer.cpp#L341-L353.

But `LiveIntervals::shrinkToUses` does not return true for all
unconnected live intervals. I don't understand all the details of that
function or why `RegisterCoalescer::shrinkToUses` was written that way,
but it looks it returns true when there are some dead components:
https://github.com/llvm/llvm-project/blob/926d980017d82dedb9eb50147a82fdfb01659f16/llvm/lib/CodeGen/LiveIntervals.cpp#L537-L540
And the case in the attached test case does not return true here, but
still has multiple unconnected components and does not pass
`MachineVerifier` unless they are split.

---

So this PR runs `LiveIntervals::splitSeparateComponents` regardless of
the return value of `LiveIntervals::shrinkToUses`.
`splitSeparateComponents` won't do anything unless there are multiple
unconnected components to split.

---

This is one of the bugs reported in llvm#126916.
@llvmbot
Copy link
Member

llvmbot commented Mar 17, 2025

@llvm/pr-subscribers-backend-webassembly

Author: Heejin Ahn (aheejin)

Changes

MachineVerifier requires that a virtual register's LiveInterval has only one connected component:

// Check the LI only has one connected component.
ConnectedVNInfoEqClasses ConEQ(*LiveInts);
unsigned NumComp = ConEQ.Classify(LI);
if (NumComp > 1) {
report("Multiple connected components in live interval", MF);
report_context(LI);
for (unsigned comp = 0; comp != NumComp; ++comp) {
OS << comp << ": valnos";
for (const VNInfo *I : LI.valnos)
if (comp == ConEQ.getEqClass(I))
OS << ' ' << I->id;
OS << '\n';
}
}
(This is different from SSA; there can be multiple defs for a register, but those live intervals should somehow be connected. I am not very sure why this rule exists, but this rule apparently has been there forever since
260fa28.)


And it turns out our TEE generation in RegStackify can create virtual registers with LiveInterval with multiple disconnected segments.

This is how TEE generation works:

/// A multiple-use def in the same block with no intervening memory or register
/// dependencies; move the def down, nest it with the current instruction, and
/// insert a tee to satisfy the rest of the uses. As an illustration, rewrite
/// this:
///
/// Reg = INST ... // Def
/// INST ..., Reg, ... // Insert
/// INST ..., Reg, ...
/// INST ..., Reg, ...
///
/// to this:
///
/// DefReg = INST ... // Def (to become the new Insert)
/// TeeReg, Reg = TEE_... DefReg
/// INST ..., TeeReg, ... // Insert
/// INST ..., Reg, ...
/// INST ..., Reg, ...
///
/// with DefReg and TeeReg stackified. This eliminates a local.get from the
/// resulting code.

But it is possible that Reg = INST can also use Reg:

0   Reg = ...
    ...
1   Reg = INST ..., Reg, ...   // It both defs and uses 'Reg'
2   INST ..., Reg, ...
3   INST ..., Reg, ...
4   INST ..., Reg, ...

In this pseudocode, Reg's live interval is [0r,1r),[1r:4r), which has two segments that are connected. But after the TEE transformation,

0   Reg = ...
    ...
1   DefReg = INST ..., Reg, ...
2   TeeReg, Reg = TEE_... DefReg
3   INST ..., TeeReg, ...
4   INST ..., Reg, ...
5   INST ..., Reg, ...

now %0's live interval is [0r,1r),[2r,4r), which are not connected anymore.

In many cases, these split segments are connected by another segment generated by a PHI (or a block start boundary that used to be a PHI). For example, if there is a loop,

bb.0:
  successors: %bb.1
0   Reg = INST ...
    ...

bb.1:
  ; predecessors: %bb.1
    successors: %bb.1, %bb.2
1   DefReg = INST ..., Reg, ...
2   TeeReg, Reg = TEE_... DefReg
3   INST ..., TeeReg, ...
4   INST ..., Reg, ...
5   INST ..., Reg, ...
6   BR_IF bb.1

bb.2:
  ; predecessors: %bb.1
7   INST ...

The live interval would be [0r,1B),[1B,1r),[2r,7B) and these three segments are classified as a single equivalence class because of the segment [1B,1r) starting at the merging point (which used to be a PHI) at the start of bb.1. But this kind of connection is not always guaranteed. The method that determines whether all components are connected, i.e., there is a single equivalence class in a LiveRange, is [ConnectedVNInfoEqClasses::Classify](

unsigned ConnectedVNInfoEqClasses::Classify(const LiveRange &LR) {
// Create initial equivalence classes.
EqClass.clear();
EqClass.grow(LR.getNumValNums());
const VNInfo *used = nullptr, *unused = nullptr;
// Determine connections.
for (const VNInfo *VNI : LR.valnos) {
// Group all unused values into one class.
if (VNI->isUnused()) {
if (unused)
EqClass.join(unused->id, VNI->id);
unused = VNI;
continue;
}
used = VNI;
if (VNI->isPHIDef()) {
const MachineBasicBlock *MBB = LIS.getMBBFromIndex(VNI->def);
assert(MBB && "Phi-def has no defining MBB");
// Connect to values live out of predecessors.
for (MachineBasicBlock *Pred : MBB->predecessors())
if (const VNInfo *PVNI = LR.getVNInfoBefore(LIS.getMBBEndIdx(Pred)))
EqClass.join(VNI->id, PVNI->id);
} else {
// Normal value defined by an instruction. Check for two-addr redef.
// FIXME: This could be coincidental. Should we really check for a tied
// operand constraint?
// Note that VNI->def may be a use slot for an early clobber def.
if (const VNInfo *UVNI = LR.getVNInfoBefore(VNI->def))
EqClass.join(VNI->id, UVNI->id);
}
}
// Lump all the unused values in with the last used value.
if (used && unused)
EqClass.join(used->id, unused->id);
EqClass.compress();
return EqClass.getNumClasses();
}
).


In RegStackify, there is a routine that splits live intervals into multiple registers in some cases:

// Shrink LI to its uses, cleaning up LI.
static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) {
if (LIS.shrinkToUses(&LI)) {
SmallVector<LiveInterval *, 4> SplitLIs;
LIS.splitSeparateComponents(LI, SplitLIs);
}
}
It looks this was copied from
/// Wrapper method for \see LiveIntervals::shrinkToUses.
/// This method does the proper fixing of the live-ranges when the afore
/// mentioned method returns true.
void shrinkToUses(LiveInterval *LI,
SmallVectorImpl<MachineInstr *> *Dead = nullptr) {
NumShrinkToUses++;
if (LIS->shrinkToUses(LI, Dead)) {
/// Check whether or not \p LI is composed by multiple connected
/// components and if that is the case, fix that.
SmallVector<LiveInterval *, 8> SplitLIs;
LIS->splitSeparateComponents(*LI, SplitLIs);
}
}
.

But LiveIntervals::shrinkToUses does not return true for all unconnected live intervals. I don't understand all the details of that function or why RegisterCoalescer::shrinkToUses was written that way, but it looks it returns true when there are some dead components:

// Handle dead values.
bool CanSeparate = computeDeadValues(*li, dead);
LLVM_DEBUG(dbgs() << "Shrunk: " << *li << '\n');
return CanSeparate;
And the case in the attached test case does not return true here, but still has multiple unconnected components and does not pass MachineVerifier unless they are split.


So this PR runs LiveIntervals::splitSeparateComponents regardless of the return value of LiveIntervals::shrinkToUses. splitSeparateComponents won't do anything unless there are multiple unconnected components to split.


This is one of the bugs reported in #126916.


Full diff: https://github.com/llvm/llvm-project/pull/131561.diff

2 Files Affected:

  • (modified) llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp (+5-4)
  • (added) llvm/test/CodeGen/WebAssembly/tee-live-intervals.mir (+41)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
index 428d573668fb4..5ff3d5f760204 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
@@ -510,10 +510,11 @@ static unsigned getTeeOpcode(const TargetRegisterClass *RC) {
 
 // Shrink LI to its uses, cleaning up LI.
 static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) {
-  if (LIS.shrinkToUses(&LI)) {
-    SmallVector<LiveInterval *, 4> SplitLIs;
-    LIS.splitSeparateComponents(LI, SplitLIs);
-  }
+  LIS.shrinkToUses(&LI);
+  // In case the register's live interval now has multiple unconnected
+  // components, split them into multiple registers.
+  SmallVector<LiveInterval *, 4> SplitLIs;
+  LIS.splitSeparateComponents(LI, SplitLIs);
 }
 
 /// A single-use def in the same block with no intervening memory or register
diff --git a/llvm/test/CodeGen/WebAssembly/tee-live-intervals.mir b/llvm/test/CodeGen/WebAssembly/tee-live-intervals.mir
new file mode 100644
index 0000000000000..b137e990932b0
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/tee-live-intervals.mir
@@ -0,0 +1,41 @@
+# RUN: llc -mtriple=wasm32-unknown-unknown -run-pass wasm-reg-stackify -verify-machineinstrs %s -o -
+
+# TEE generation in RegStackify can create virtual registers with LiveIntervals
+# with multiple disconnected segments, which is invalid in MachineVerifier. In
+# this test, '%0 = CALL @foo' will become a CALL and a TEE, which creates
+# unconnected split segments. This should be later split into multiple
+# registers. This test should not crash with -verify-machineinstrs, which checks
+# whether all segments within a register is connected. See ??? for the detailed
+# explanation.
+
+--- |
+  target triple = "wasm32-unknown-unknown"
+
+  declare ptr @foo(ptr returned)
+  define void @tee_live_intervals_test() {
+    ret void
+  }
+...
+---
+name: tee_live_intervals_test
+liveins:
+  - { reg: '$arguments' }
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $arguments
+    successors: %bb.1, %bb.2
+    %0:i32 = ARGUMENT_i32 0, implicit $arguments
+    %1:i32 = CONST_I32 0, implicit-def dead $arguments
+    BR_IF %bb.2, %1:i32, implicit-def dead $arguments
+
+  bb.1:
+  ; predecessors: %bb.0
+    %0:i32 = CALL @foo, %0:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
+    STORE8_I32_A32 0, 0, %0:i32, %1:i32, implicit-def dead $arguments
+    RETURN %0:i32, implicit-def dead $arguments
+
+  bb.2:
+  ; predecessors: %bb.0
+    %2:i32 = CONST_I32 0, implicit-def dead $arguments
+    RETURN %2:i32, implicit-def dead $arguments

@aheejin
Copy link
Member Author

aheejin commented Mar 17, 2025

I have a question about the rule. Why is it required that a LiveIntervals all segments should be connected in 260fa28? cc @stoklund

@sunfishcode
Copy link
Member

Your analysis here sounds sensible to me, but I also don't understand all the details of why RegisterCoalescer::shrinkToUses was written that way.

@aheejin
Copy link
Member Author

aheejin commented Mar 20, 2025

Yeah I don't know why RegisterCoalescer::shrinkToUses was written that way or if that was even correct either, but given that this causes a real crash with -verify-machineinstrs in RegStackify, I think we can at least land this? This basically splits live intervals when it violates the verification of MachineVerifier and doesn't do anything otherwise.

@aheejin aheejin requested a review from qcolombet March 24, 2025 00:39
@aheejin
Copy link
Member Author

aheejin commented Mar 24, 2025

@qcolombet I think if (LIS->shrinkToUses(LI, Dead)) condition in

/// Wrapper method for \see LiveIntervals::shrinkToUses.
/// This method does the proper fixing of the live-ranges when the afore
/// mentioned method returns true.
void shrinkToUses(LiveInterval *LI,
SmallVectorImpl<MachineInstr *> *Dead = nullptr) {
NumShrinkToUses++;
if (LIS->shrinkToUses(LI, Dead)) {
/// Check whether or not \p LI is composed by multiple connected
/// components and if that is the case, fix that.
SmallVector<LiveInterval *, 8> SplitLIs;
LIS->splitSeparateComponents(*LI, SplitLIs);
}
}

was first written in 0ddd315 authored by you. It's a long time ago, but in case you remember the context, could you explain what this condition means, and why it does not return true in some cases when there are unconnected components (as described in the test case of this PR)?

@qcolombet
Copy link
Collaborator

@qcolombet I think if (LIS->shrinkToUses(LI, Dead)) condition in

/// Wrapper method for \see LiveIntervals::shrinkToUses.
/// This method does the proper fixing of the live-ranges when the afore
/// mentioned method returns true.
void shrinkToUses(LiveInterval *LI,
SmallVectorImpl<MachineInstr *> *Dead = nullptr) {
NumShrinkToUses++;
if (LIS->shrinkToUses(LI, Dead)) {
/// Check whether or not \p LI is composed by multiple connected
/// components and if that is the case, fix that.
SmallVector<LiveInterval *, 8> SplitLIs;
LIS->splitSeparateComponents(*LI, SplitLIs);
}
}

was first written in 0ddd315 authored by you. It's a long time ago, but in case you remember the context, could you explain what this condition means, and why it does not return true in some cases when there are unconnected components (as described in the test case of this PR)?

shrinkToUses is supposed to return true when there are unconnected components as described in the comments of this method (

/// are added to the dead vector. Returns true if the interval may have been
)

If this is not the case, then there may be a bug in computeDeadValues.
In any case, I don't believe your patch is the correct fix. Although this will fix the problem, this is a big hammer because this has a compile time cost that we shouldn't have to pay in most cases (hence why the code was only running when the method returns true.)

And it turns out our TEE generation in RegStackify can create virtual registers with LiveInterval with multiple disconnected segments.

I'm wondering if you're trying to apply the same recipe as the register coalescer on something that doesn't follow the same rules.

Could you check (e.g., by inserting calls to the verifier at different stages of the reg stackifier) whether your live intervals are "correct" when you enter into shrinkToUsers.

@aheejin
Copy link
Member Author

aheejin commented Mar 26, 2025

@qcolombet Thanks for the info; I'll take a look. Meanwhile, do you know why this verification rule, which requires a LiveIntervals should not contain unconnected components, exist?

// Check the LI only has one connected component.
ConnectedVNInfoEqClasses ConEQ(*LiveInts);
unsigned NumComp = ConEQ.Classify(LI);
if (NumComp > 1) {
report("Multiple connected components in live interval", MF);
report_context(LI);
for (unsigned comp = 0; comp != NumComp; ++comp) {
OS << comp << ": valnos";
for (const VNInfo *I : LI.valnos)
if (comp == ConEQ.getEqClass(I))
OS << ' ' << I->id;
OS << '\n';
}
}

I haven't read the implementation of https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/RegisterCoalescer.cpp, but in general what register coalescing does is to reuse registers if live ranges don't overlap, which I think naturally create multiple unconnected components. For example,

0  %a = ...
1  ... use %a ...  ;; %a is dead after here
2  %b = 
3  ... use %b ...

In this pseudocode, where %a and %b are registers, if the types of %a and %b are the same and their live ranges don't overlap, register coalescing can make the code only use %a:

0  %a = ...
1  ... use %a ...
2  %a = 
3  ... use %a ...

But this can create unconnected live intervals for %a, like [0r,1r), [2r,3r).

@qcolombet
Copy link
Collaborator

Meanwhile, do you know why this verification rule, which requires a LiveIntervals should not contain unconnected components, exist?

That's because you don't want to group variables that are otherwise completely unrelated. That creates additional constraints on your allocation for no reason.

@aheejin
Copy link
Member Author

aheejin commented Mar 28, 2025

Meanwhile, do you know why this verification rule, which requires a LiveIntervals should not contain unconnected components, exist?

That's because you don't want to group variables that are otherwise completely unrelated. That creates additional constraints on your allocation for no reason.

Sorry, not sure if I understand. Then doesn't this effectively ban register coalescing, as I asked in #131561 (comment)?

@qcolombet
Copy link
Collaborator

Meanwhile, do you know why this verification rule, which requires a LiveIntervals should not contain unconnected components, exist?

That's because you don't want to group variables that are otherwise completely unrelated. That creates additional constraints on your allocation for no reason.

Sorry, not sure if I understand. Then doesn't this effectively ban register coalescing, as I asked in #131561 (comment)?

In a way it does, because these two variables are unrelated, so there's no point in coalescing them.
The goal of coalescing is to eliminate copies. Your example has none, so no coalescing is needed.

@qcolombet
Copy link
Collaborator

Let me rephrase, it bans coalescing of unrelated variables.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants