Skip to content

[SimplifyCFG] Make i1 legal to build lookup tables #87431

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

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

Conversation

krtab
Copy link

@krtab krtab commented Apr 2, 2024

This is my attempt to fix the LLVM issue leading to rust-lang/rust#123305 and my first contribution to LLVM.

i1 types are not considered to simplify switches because they are !isTypeLegalForLookupTable. This hardcode an exception but other ways may make more sense.

I guess I should add a test? Could you point to me where?

Copy link

github-actions bot commented Apr 2, 2024

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@nikic
Copy link
Contributor

nikic commented Apr 10, 2024

Can you please add a test in llvm/test/Transforms/SimplifyCFG (something that doesn't fold without your change and folds with)? It's a bit hard to tell what exactly it is you are trying to fix here.

@llvmbot
Copy link
Member

llvmbot commented Apr 10, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Arthur Carcano (krtab)

Changes

This is my attempt to fix the LLVM issue leading to rust-lang/rust#123305 and my first contribution to LLVM.

i1 types are not considered to simplify switches because they are !isTypeLegalForLookupTable. This hardcode an exception but other ways may make more sense.

I guess I should add a test? Could you point to me where?


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

2 Files Affected:

  • (modified) llvm/lib/Transforms/Utils/SimplifyCFG.cpp (+2)
  • (added) llvm/test/Transforms/SimplifyCFG/fold-i1.ll (+64)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 55bbffb18879fb..af6ace5675bf52 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6448,6 +6448,8 @@ static bool isTypeLegalForLookupTable(Type *Ty, const TargetTransformInfo &TTI,
   // on ABI alignment and padding in the table to allow the load to be widened.
   // Or we could widen the constants and truncate the load.
   unsigned BitWidth = IT->getBitWidth();
+  if (BitWidth == 1)
+    return true;
   return BitWidth >= 8 && isPowerOf2_32(BitWidth) &&
          DL.fitsInLegalInteger(IT->getBitWidth());
 }
diff --git a/llvm/test/Transforms/SimplifyCFG/fold-i1.ll b/llvm/test/Transforms/SimplifyCFG/fold-i1.ll
new file mode 100644
index 00000000000000..444f51fb2438bc
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/fold-i1.ll
@@ -0,0 +1,64 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -S -passes='simplifycfg<switch-to-lookup>' | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+define { i1, i8 } @f(i8 noundef %character) unnamed_addr {
+; CHECK-LABEL: define { i1, i8 } @f(
+; CHECK-SAME: i8 noundef [[CHARACTER:%.*]]) unnamed_addr {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    [[SWITCH_TABLEIDX:%.*]] = sub i8 [[CHARACTER]], 48
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[SWITCH_TABLEIDX]], 9
+; CHECK-NEXT:    [[_0_SROA_11_0:%.*]] = select i1 [[TMP2]], i8 [[SWITCH_TABLEIDX]], i8 undef
+; CHECK-NEXT:    [[_0_SROA_0_0:%.*]] = select i1 [[TMP2]], i1 true, i1 false
+; CHECK-NEXT:    [[TMP0:%.*]] = insertvalue { i1, i8 } poison, i1 [[_0_SROA_0_0]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i1, i8 } [[TMP0]], i8 [[_0_SROA_11_0]], 1
+; CHECK-NEXT:    ret { i1, i8 } [[TMP1]]
+;
+start:
+  switch i8 %character, label %bb11 [
+  i8 48, label %bb2
+  i8 49, label %bb3
+  i8 50, label %bb4
+  i8 51, label %bb5
+  i8 52, label %bb6
+  i8 53, label %bb7
+  i8 54, label %bb8
+  i8 55, label %bb9
+  i8 56, label %bb10
+  ]
+
+bb2:
+  br label %bb11
+
+bb3:
+  br label %bb11
+
+bb4:
+  br label %bb11
+
+bb5:
+  br label %bb11
+
+bb6:
+  br label %bb11
+
+bb7:
+  br label %bb11
+
+bb8:
+  br label %bb11
+
+bb9:
+  br label %bb11
+
+bb10:
+  br label %bb11
+
+bb11:
+  %_0.sroa.11.0 = phi i8 [ 8, %bb10 ], [ 7, %bb9 ], [ 6, %bb8 ], [ 5, %bb7 ], [ 4, %bb6 ], [ 3, %bb5 ], [ 2, %bb4 ], [ 1, %bb3 ], [ 0, %bb2 ], [ undef, %start ]
+  %_0.sroa.0.0 = phi i1 [ true, %bb10 ], [ true, %bb9 ], [ true, %bb8 ], [ true, %bb7 ], [ true, %bb6 ], [ true, %bb5 ], [ true, %bb4 ], [ true, %bb3 ], [ true, %bb2 ], [ false, %start ]
+  %0 = insertvalue { i1, i8 } poison, i1 %_0.sroa.0.0, 0
+  %1 = insertvalue { i1, i8 } %0, i8 %_0.sroa.11.0, 1
+  ret { i1, i8 } %1
+}

@krtab
Copy link
Author

krtab commented Apr 10, 2024

I've added a test @nikic , let me know it this should be improved.

; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i8 [[CHARACTER]], 48
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[SWITCH_TABLEIDX]], 9
; CHECK-NEXT: [[_0_SROA_11_0:%.*]] = select i1 [[TMP2]], i8 [[SWITCH_TABLEIDX]], i8 undef
; CHECK-NEXT: [[_0_SROA_0_0:%.*]] = select i1 [[TMP2]], i1 true, i1 false
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be good to also test the case where we actually build a lookup table for the booleans. Need some pattern for that which doesn't reduce down to a simple select.

If I'm reading the code right, then what we'd end up doing is generate an array of i1 constants and then generate i1 loads -- the former is okay-ish, but the latter is a big no-no. We'd instead want to generate a table of i8s, generate i8 loads and truncate them to i1.

An alternative would be to not allow table generation, but instead relax the "AllTablesFitInRegister" condition so that we always have either a legal integer width or the lookup mask fitting in a register, without requiring that all of them fit in a register.

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