Skip to content

Conversation

@davemgreen
Copy link
Collaborator

We already have a transform for (anyext (trunc x)) -> x, this adds an extended version for (anyext (freeze (trunc x))) -> (freeze x). As we treat freeze i8 and i16 as legal this can help reduce the number of extends in the code.

We already have a transform for (anyext (trunc x)) -> x, this adds an extended
version for (anyext (freeze (trunc x))) -> (freeze x). As we treat freeze i8
and i16 as legal this can help reduce the number of extends in the code.
@llvmbot
Copy link
Member

llvmbot commented Oct 30, 2025

@llvm/pr-subscribers-llvm-globalisel

Author: David Green (davemgreen)

Changes

We already have a transform for (anyext (trunc x)) -> x, this adds an extended version for (anyext (freeze (trunc x))) -> (freeze x). As we treat freeze i8 and i16 as legal this can help reduce the number of extends in the code.


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

2 Files Affected:

  • (modified) llvm/include/llvm/Target/GlobalISel/Combine.td (+20-8)
  • (modified) llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir (+21-4)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 119695e53c3cb..a102e3f0c6a47 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -805,16 +805,28 @@ def redundant_sext_inreg: GICombineRule <
   (defs root:$root),
   (match (wip_match_opcode G_SEXT_INREG):$root,
          [{ return Helper.matchRedundantSExtInReg(*${root}); }]),
-     (apply [{ Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
+  (apply [{ Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
 >;
 
-// Fold (anyext (trunc x)) -> x if the source type is same as
-// the destination type.
+// Fold (anyext (trunc x)) -> x if the source type is same as the destination
+// type.
 def anyext_trunc_fold: GICombineRule <
-  (defs root:$root, register_matchinfo:$matchinfo),
-  (match (wip_match_opcode G_ANYEXT):$root,
-         [{ return Helper.matchCombineAnyExtTrunc(*${root}, ${matchinfo}); }]),
-  (apply [{ Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }])
+  (defs root:$root),
+  (match (G_TRUNC $x, $src),
+         (G_ANYEXT $dst, $x):$root,
+         [{ return MRI.getType(${dst}.getReg()) == MRI.getType(${src}.getReg()); }]),
+  (apply (GIReplaceReg $dst, $src))
+>;
+
+// Fold (anyext (freeze (trunc x))) -> (freeze x) if the source type is same as
+// the destination type.
+def anyext_freeze_trunc_fold: GICombineRule <
+  (defs root:$root),
+  (match (G_TRUNC $x, $src),
+         (G_FREEZE $y, $x),
+         (G_ANYEXT $dst, $y):$root,
+         [{ return MRI.getType(${dst}.getReg()) == MRI.getType(${src}.getReg()); }]),
+  (apply (G_FREEZE $dst, $src))
 >;
 
 // Fold (zext (trunc x)) -> x if the source type is same as the destination type
@@ -2084,7 +2096,7 @@ def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero,
 def identity_combines : GICombineGroup<[select_same_val, right_identity_zero,
                                         binop_same_val, binop_left_to_zero,
                                         binop_right_to_zero, p2i_to_i2p,
-                                        i2p_to_p2i, anyext_trunc_fold,
+                                        i2p_to_p2i, anyext_trunc_fold, anyext_freeze_trunc_fold,
                                         fneg_fneg_fold, right_identity_one,
                                         add_sub_reg, buildvector_identity_fold,
                                         trunc_buildvector_fold,
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir
index 629238126380c..2b24a8920e0e0 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir
@@ -385,8 +385,8 @@ body:             |
     ; CHECK: liveins: $h0
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s16) = COPY $h0
-    ; CHECK-NEXT: %2:_(s64) = nneg G_ZEXT [[COPY]](s16)
-    ; CHECK-NEXT: $x0 = COPY %2(s64)
+    ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = nneg G_ZEXT [[COPY]](s16)
+    ; CHECK-NEXT: $x0 = COPY [[ZEXT]](s64)
     %0:_(s16) = COPY $h0
     %1:_(s32) = G_ANYEXT %0(s16)
     %2:_(s64) = nneg G_ZEXT %1(s32)
@@ -401,10 +401,27 @@ body:             |
     ; CHECK: liveins: $h0
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s16) = COPY $h0
-    ; CHECK-NEXT: %2:_(s64) = nneg G_ZEXT [[COPY]](s16)
-    ; CHECK-NEXT: $x0 = COPY %2(s64)
+    ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = nneg G_ZEXT [[COPY]](s16)
+    ; CHECK-NEXT: $x0 = COPY [[ZEXT]](s64)
     %0:_(s16) = COPY $h0
     %1:_(s32) = nneg G_ZEXT %0(s16)
     %2:_(s64) = G_ANYEXT %1(s32)
     $x0 = COPY %2(s64)
 ...
+---
+name:            test_combine_anyext_freeze_trunc
+body:             |
+  bb.1:
+  liveins: $x0
+    ; CHECK-LABEL: name: test_combine_anyext_freeze_trunc
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+    ; CHECK-NEXT: [[FREEZE:%[0-9]+]]:_(s64) = G_FREEZE [[COPY]]
+    ; CHECK-NEXT: $x1 = COPY [[FREEZE]](s64)
+    %0:_(s64) = COPY $x0
+    %1:_(s32) = G_TRUNC %0(s64)
+    %2:_(s32) = G_FREEZE %1(s32)
+    %3:_(s64) = G_ANYEXT %2(s32)
+    $x1 = COPY %3(s64)
+...

@llvmbot
Copy link
Member

llvmbot commented Oct 30, 2025

@llvm/pr-subscribers-backend-aarch64

Author: David Green (davemgreen)

Changes

We already have a transform for (anyext (trunc x)) -> x, this adds an extended version for (anyext (freeze (trunc x))) -> (freeze x). As we treat freeze i8 and i16 as legal this can help reduce the number of extends in the code.


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

2 Files Affected:

  • (modified) llvm/include/llvm/Target/GlobalISel/Combine.td (+20-8)
  • (modified) llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir (+21-4)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 119695e53c3cb..a102e3f0c6a47 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -805,16 +805,28 @@ def redundant_sext_inreg: GICombineRule <
   (defs root:$root),
   (match (wip_match_opcode G_SEXT_INREG):$root,
          [{ return Helper.matchRedundantSExtInReg(*${root}); }]),
-     (apply [{ Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
+  (apply [{ Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
 >;
 
-// Fold (anyext (trunc x)) -> x if the source type is same as
-// the destination type.
+// Fold (anyext (trunc x)) -> x if the source type is same as the destination
+// type.
 def anyext_trunc_fold: GICombineRule <
-  (defs root:$root, register_matchinfo:$matchinfo),
-  (match (wip_match_opcode G_ANYEXT):$root,
-         [{ return Helper.matchCombineAnyExtTrunc(*${root}, ${matchinfo}); }]),
-  (apply [{ Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }])
+  (defs root:$root),
+  (match (G_TRUNC $x, $src),
+         (G_ANYEXT $dst, $x):$root,
+         [{ return MRI.getType(${dst}.getReg()) == MRI.getType(${src}.getReg()); }]),
+  (apply (GIReplaceReg $dst, $src))
+>;
+
+// Fold (anyext (freeze (trunc x))) -> (freeze x) if the source type is same as
+// the destination type.
+def anyext_freeze_trunc_fold: GICombineRule <
+  (defs root:$root),
+  (match (G_TRUNC $x, $src),
+         (G_FREEZE $y, $x),
+         (G_ANYEXT $dst, $y):$root,
+         [{ return MRI.getType(${dst}.getReg()) == MRI.getType(${src}.getReg()); }]),
+  (apply (G_FREEZE $dst, $src))
 >;
 
 // Fold (zext (trunc x)) -> x if the source type is same as the destination type
@@ -2084,7 +2096,7 @@ def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero,
 def identity_combines : GICombineGroup<[select_same_val, right_identity_zero,
                                         binop_same_val, binop_left_to_zero,
                                         binop_right_to_zero, p2i_to_i2p,
-                                        i2p_to_p2i, anyext_trunc_fold,
+                                        i2p_to_p2i, anyext_trunc_fold, anyext_freeze_trunc_fold,
                                         fneg_fneg_fold, right_identity_one,
                                         add_sub_reg, buildvector_identity_fold,
                                         trunc_buildvector_fold,
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir
index 629238126380c..2b24a8920e0e0 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-ext.mir
@@ -385,8 +385,8 @@ body:             |
     ; CHECK: liveins: $h0
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s16) = COPY $h0
-    ; CHECK-NEXT: %2:_(s64) = nneg G_ZEXT [[COPY]](s16)
-    ; CHECK-NEXT: $x0 = COPY %2(s64)
+    ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = nneg G_ZEXT [[COPY]](s16)
+    ; CHECK-NEXT: $x0 = COPY [[ZEXT]](s64)
     %0:_(s16) = COPY $h0
     %1:_(s32) = G_ANYEXT %0(s16)
     %2:_(s64) = nneg G_ZEXT %1(s32)
@@ -401,10 +401,27 @@ body:             |
     ; CHECK: liveins: $h0
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s16) = COPY $h0
-    ; CHECK-NEXT: %2:_(s64) = nneg G_ZEXT [[COPY]](s16)
-    ; CHECK-NEXT: $x0 = COPY %2(s64)
+    ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = nneg G_ZEXT [[COPY]](s16)
+    ; CHECK-NEXT: $x0 = COPY [[ZEXT]](s64)
     %0:_(s16) = COPY $h0
     %1:_(s32) = nneg G_ZEXT %0(s16)
     %2:_(s64) = G_ANYEXT %1(s32)
     $x0 = COPY %2(s64)
 ...
+---
+name:            test_combine_anyext_freeze_trunc
+body:             |
+  bb.1:
+  liveins: $x0
+    ; CHECK-LABEL: name: test_combine_anyext_freeze_trunc
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+    ; CHECK-NEXT: [[FREEZE:%[0-9]+]]:_(s64) = G_FREEZE [[COPY]]
+    ; CHECK-NEXT: $x1 = COPY [[FREEZE]](s64)
+    %0:_(s64) = COPY $x0
+    %1:_(s32) = G_TRUNC %0(s64)
+    %2:_(s32) = G_FREEZE %1(s32)
+    %3:_(s64) = G_ANYEXT %2(s32)
+    $x1 = COPY %3(s64)
+...

Copy link
Contributor

@arsenm arsenm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is OK but DAGCombiner seems to not have this one

%2:_(s32) = G_FREEZE %1(s32)
%3:_(s64) = G_ANYEXT %2(s32)
$x1 = COPY %3(s64)
...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the negative test where the types mismatch? Also test multiple uses of the inner op

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.

3 participants