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

Case gnu range need to be improved #632

Closed
wenpen opened this issue May 27, 2024 · 4 comments · Fixed by #650
Closed

Case gnu range need to be improved #632

wenpen opened this issue May 27, 2024 · 4 comments · Fixed by #650

Comments

@wenpen
Copy link
Contributor

wenpen commented May 27, 2024

Pr #599 added support for gnu range in case statement, but the implementation need to store every integer inside the range.

For example, the following code will produce tons of repeated

  switch(x) {
    case 50 ... 233:
      return 1;
  }
switch i32 %5, label %8 [
    i32 50, label %6
    i32 51, label %6
    i32 52, label %6
    ...
    ...
    i32 231, label %6
    i32 232, label %6
    i32 233, label %6
  ], !dbg !12

While the OG codegen is smart

  switch i32 %0, label %sw.caserange [
  ]

sw.caserange:                                     ; preds = %entry
  %1 = sub i32 %0, 50
  %inbounds = icmp ule i32 %1, 183
  br i1 %inbounds, label %sw.bb, label %sw.epilog
@wenpen
Copy link
Contributor Author

wenpen commented May 27, 2024

Hi @bcardosolopes, I'm working on this issue as we talked before, I felt it's not very trivial, so opened this issue to discuss it.

IIUC, the two different codegen pipelines are as below.
The original codegen workflow is:
SwitchStmt => SwitchInst+BranchInst
The cir workflow is:
SwitchStmt => cir::SwitchOp => cir::SwitchFlatOp => LLVM::SwitchOp => SwitchInst

So the problem is cir lack the BranchInst information, in my view there are two proposals to solve it

  1. Add attributes in SwitchOp to record the range information, and lower it to BranchInst. Then we need to modify all the three ops, i.e. cir::SwitchOp, cir::SwitchFlatOp and LLVM::SwitchOp.
  2. In CIRSwitchOpFlattening, replace SwitchOp with BrCondOp, just like what CIRLoopOpInterfaceFlattening did. I prefer this solution, as it would be helpful to Assertion failure on switch statement with case label in nested block #522

Do you have some suggestions? I'll start the work if you confirm the solution, thanks!

@Lancern
Copy link
Member

Lancern commented May 28, 2024

In CIRSwitchOpFlattening, replace SwitchOp with BrCondOp, just like what CIRLoopOpInterfaceFlattening did.

Consider this case:

int test(int x) {
  switch(x) {
  case 1000 ... 2000:
    return 1;

  case 3333:
    return 3;
  case 4444:
    return 4;
  case 5555:
    return 5;

  default:
    return 6;
  }
}

The original CodeGen generates:

  switch i32 %0, label %sw.caserange [
    i32 3333, label %sw.bb1
    i32 4444, label %sw.bb2
    i32 5555, label %sw.bb3
  ]

sw.caserange:
  %1 = sub i32 %0, 1000
  %inbounds = icmp ule i32 %1, 1000
  br i1 %inbounds, label %sw.bb, label %sw.default

So to keep the same output code you cannot just replace SwitchOp with BrCondOp. The above code is more or less likely to be transformed into:

int test(int x) {
  switch(x) {
  case 3333:
    return 3;
  case 4444:
    return 4;
  case 5555:
    return 5;

  default:
    if (x >= 1000 && x <= 2000)
      return 1;
    return 6;
  }
}

@wenpen
Copy link
Contributor Author

wenpen commented May 28, 2024

@Lancern Your suggestion is great!
I'll try this implementation, thank you.

@bcardosolopes
Copy link
Member

bcardosolopes commented May 30, 2024

  1. Add attributes in SwitchOp to record the range information

We need a new switch case that tracks ranges.

... and lower it to BranchInst. Then we need to modify all the three ops, i.e. cir::SwitchOp, cir::SwitchFlatOp and LLVM::SwitchOp.

Changing LLVM::SwitchOp is out of scope.

  1. In CIRSwitchOpFlattening, replace SwitchOp with BrCondOp, just like what CIRLoopOpInterfaceFlattening did. I prefer this solution, as it would be helpful to Assertion failure on switch statement with case label in nested block #522

Having the new range attribute is decoupled from the actual lowering strategy, as @Lancern pointed out - SwitchOp might needed to be lowered to a mix of flat switch and brcond's. I suggest you put a debugger in LLVM traditional codegen and learn how it applies the heuristics, we should do similar in CIR, but likely as part of CIRSwitchOpFlattening, as you noticed.

bcardosolopes pushed a commit that referenced this issue Jun 5, 2024
Make lowering result of case range smart.

Resolve #632
bruteforceboy pushed a commit to bruteforceboy/clangir that referenced this issue Oct 2, 2024
Make lowering result of case range smart.

Resolve llvm#632
Hugobros3 pushed a commit to shady-gang/clangir that referenced this issue Oct 2, 2024
Make lowering result of case range smart.

Resolve llvm#632
smeenai pushed a commit to smeenai/clangir that referenced this issue Oct 9, 2024
Make lowering result of case range smart.

Resolve llvm#632
keryell pushed a commit to keryell/clangir that referenced this issue Oct 19, 2024
Make lowering result of case range smart.

Resolve llvm#632
lanza pushed a commit that referenced this issue Nov 5, 2024
Make lowering result of case range smart.

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

Successfully merging a pull request may close this issue.

3 participants