Provably Correct Peephole Optimizations with Alive.

Slides:



Advertisements
Similar presentations
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Advertisements

Challenges in increasing tool support for programming K. Rustan M. Leino Microsoft Research, Redmond, WA, USA 23 Sep 2004 ICTAC Guiyang, Guizhou, PRC joint.
Undefined Behavior What happened to my code?
An Abstract Interpretation Framework for Refactoring P. Cousot, NYU, ENS, CNRS, INRIA R. Cousot, ENS, CNRS, INRIA F. Logozzo, M. Barnett, Microsoft Research.
Semantics Static semantics Dynamic semantics attribute grammars
ICE1341 Programming Languages Spring 2005 Lecture #6 Lecture #6 In-Young Ko iko.AT. icu.ac.kr iko.AT. icu.ac.kr Information and Communications University.
8. Code Generation. Generate executable code for a target machine that is a faithful representation of the semantics of the source code Depends not only.
Abstraction and Modular Reasoning for the Verification of Software Corina Pasareanu NASA Ames Research Center.
The Substitution Principle SWE 332 – Fall Liskov Substitution Principle In any client code, if subtype object is substituted for supertype object,
The Interface Definition Language for Fail-Safe C Kohei Suenaga, Yutaka Oiwa, Eijiro Sumii, Akinori Yonezawa University of Tokyko.
Chapter 5: Elementary Data Types Properties of types and objects –Data objects, variables and constants –Data types –Declarations –Type checking –Assignment.
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 1 Symbolic Execution and Proof of Properties.
Technology from seed Weakest Precondition Synthesis for Compiler Optimizations Nuno Lopes and José Monteiro.
ISBN Chapter 3 Describing Syntax and Semantics.
Technology from seed Automatic Synthesis of Weakest Preconditions for Compiler Optimizations Nuno Lopes Advisor: José Monteiro.
CS 355 – Programming Languages
Using Programmer-Written Compiler Extensions to Catch Security Holes Authors: Ken Ashcraft and Dawson Engler Presented by : Hong Chen CS590F 2/7/2007.
Ross Tate, Juan Chen, Chris Hawblitzel. Typed Assembly Languages Compilers are great but they make mistakes and can introduce vulnerabilities Typed assembly.
CS 536 Spring Intermediate Code. Local Optimizations. Lecture 22.
Houdini: An Annotation Assistant for ESC/Java Cormac Flanagan and K. Rustan M. Leino Compaq Systems Research Center.
Validating High-Level Synthesis Sudipta Kundu, Sorin Lerner, Rajesh Gupta Department of Computer Science and Engineering, University of California, San.
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
Intermediate Code. Local Optimizations
CS 330 Programming Languages 09 / 16 / 2008 Instructor: Michael Eckmann.
1 Type Type system for a programming language = –set of types AND – rules that specify how a typed program is allowed to behave Why? –to generate better.
Describing Syntax and Semantics
Cormac Flanagan University of California, Santa Cruz Hybrid Type Checking.
Specifications Liskov Chapter 9 SWE 619 Last Updated Fall 2008.
Have Your Verified Compiler And Extend It Too Zachary Tatlock Sorin Lerner UC San Diego.
Carnegie Mellon 1 This Week: Integers Integers  Representation: unsigned and signed  Conversion, casting  Expanding, truncating  Addition, negation,
Compositional correctness of IP-based system design: Translating C/C++ Models into SIGNAL Processes Rennes, November 04, 2005 Hamoudi Kalla and Jean-Pierre.
Software Engineering Prof. Dr. Bertrand Meyer March 2007 – June 2007 Chair of Software Engineering Static program checking and verification Slides: Based.
1 Debugging and Testing Overview Defensive Programming The goal is to prevent failures Debugging The goal is to find cause of failures and fix it Testing.
Chapter 25 Formal Methods Formal methods Specify program using math Develop program using math Prove program matches specification using.
ISBN Chapter 3 Describing Semantics -Attribute Grammars -Dynamic Semantics.
CS 363 Comparative Programming Languages Semantics.
Reasoning about programs March CSE 403, Winter 2011, Brun.
Towards Beautiful Test Cases for Compiler Bugs John Regehr University of Utah.
ISBN Chapter 3 Describing Semantics.
Chapter 3 Part II Describing Syntax and Semantics.
CSV 889: Concurrent Software Verification Subodh Sharma Indian Institute of Technology Delhi Scalable Symbolic Execution: KLEE.
13 Aug 2013 Program Verification. Proofs about Programs Why make you study logic? Why make you do proofs? Because we want to prove properties of programs.
ANU COMP2110 Software Design in 2003 Lecture 10Slide 1 COMP2110 Software Design in 2004 Lecture 12 Documenting Detailed Design How to write down detailed.
1 Contractual Consistency Between BON Static and Dynamic Diagrams Ali Taleghani July 30, 2004.
C HAPTER 3 Describing Syntax and Semantics. D YNAMIC S EMANTICS Describing syntax is relatively simple There is no single widely acceptable notation or.
Digital Computer Concept and Practice Copyright ©2012 by Jaejin Lee Control Unit.
Finding and Understanding Bugs in C Compilers Xuejun Yang Yang Chen Eric Eide John Regehr University of Utah.
Conditionally Correct Superoptimization Rahul Sharma, Eric Schkufza, Berkeley Churchill, Alex Aiken (Stanford University)
LLVM Simone Campanoni
ARM Shifts, Multiplies & Divide??. MVN Pseudo Instructions Pseudo Intruction: Supported by assembler, not be hardware.
Test-Case Reduction for C Compiler Bugs
Types for Programs and Proofs
This Week: Integers Integers Summary
Instructor: David Ferry
CSE 374 Programming Concepts & Tools
Undefined Behavior: Long Live Poison!
Accessible Formal Methods A Study of the Java Modeling Language
LLVM IR, code emission, assignment 4
Threads and Memory Models Hal Perkins Autumn 2011
Programming Languages (CS 550) Mini Language Compiler
Programming Languages 2nd edition Tucker and Noonan
Improving Reliability of Compilers
All You Ever Wanted to Know About Dynamic Taint Analysis & Forward Symbolic Execution (but might have been afraid to ask) Edward J. Schwartz, Thanassis.
Threads and Memory Models Hal Perkins Autumn 2009
Tutorial for LLVM Intermediate Representation
Semantics for Compiler IRs: Undefined Behavior is not Evil!
The Zoo of Software Security Techniques
Programming Languages and Compilers (CS 421)
Programming Languages 2nd edition Tucker and Noonan
Programming Languages (CS 360) Mini Language Compiler
Presentation transcript:

Provably Correct Peephole Optimizations with Alive

Compilers are Buggy Csmith [PLDI’11]: 79 bugs in GCC (25 P1) 202 bugs in LLVM 2 wrong-code bugs in CompCert Orion [PLDI’14]: 40 wrong-code bugs in GCC 42 wrong-code bugs in LLVM Last Week: 439 open wrong-code bug reports in GCC (out of 9,691) 24 open wrong-code bug reports in LLVM (out of 6,761)

Buggy Compilers = Security Bugs CVE GCC 4.1/4.2 (fold-const.c) had a bug that could remove valid pointer comparisons Result: Removed some bounds checks from programs

Peephole Optimizers are Particularly Buggy LLVM’s InstCombine (a peephole optimizer) had the most bugs reported by fuzzing tools InstCombine has 20,000 lines of C++ Semantics of LLVM IR are tricky; InstCombine exploits the corner cases to improve performance: Undefined behavior, poison values, undefined values, overflows, …

Optimizations are Easy to Get Wrong int a = x << c; int b = a / d; x * 2 c / d x / (d / 2 c )= x / d * 2 c = x * 2 c / d

Optimizations are Easy to Get Wrong ERROR: Domain of definedness of Target is smaller than Source's for i4 %b Example: %X i4 = 0x0 (0) c i4 = 0x3 (3) d i4 = 0x7 (7) %a i4 = 0x0 (0) (1 << c) i4 = 0x8 (8, -8) %t i4 = 0x0 (0) Source value: 0x0 (0) Target value: undef int a = x << c; int b = a / d;

Implementing Peephole Optimizers { Value *Op1C = Op1; BinaryOperator *BO = dyn_cast (Op0); if (!BO || (BO->getOpcode() != Instruction::UDiv && BO->getOpcode() != Instruction::SDiv)) { Op1C = Op0; BO = dyn_cast (Op1); } Value *Neg = dyn_castNegVal(Op1C); if (BO && BO->hasOneUse() && (BO->getOperand(1) == Op1C || BO->getOperand(1) == Neg) && (BO->getOpcode() == Instruction::UDiv || BO->getOpcode() == Instruction::SDiv)) { Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1); // If the division is exact, X % Y is zero, so we end up with X or -X. if (PossiblyExactOperator *SDiv = dyn_cast (BO)) if (SDiv->isExact()) { if (Op1BO == Op1C) return ReplaceInstUsesWith(I, Op0BO); return BinaryOperator::CreateNeg(Op0BO); } Value *Rem; if (BO->getOpcode() == Instruction::UDiv) Rem = Builder->CreateURem(Op0BO, Op1BO); else Rem = Builder->CreateSRem(Op0BO, Op1BO); Rem->takeName(BO); if (Op1BO == Op1C) return BinaryOperator::CreateSub(Op0BO, Rem); return BinaryOperator::CreateSub(Rem, Op0BO); }

Alive New language and tool for: Specifying peephole optimizations Proving them correct (or generate a counterexample) Generating C++ code for a compiler Design point: both practical and formal

A Simple Peephole Optimization int f(int x, int y) { return (x / y) * y; } { Value *Op1C = Op1; BinaryOperator *BO = dyn_cast (Op0); if (!BO || (BO->getOpcode() != Instruction::UDiv && BO->getOpcode() != Instruction::SDiv)) { Op1C = Op0; BO = dyn_cast (Op1); } Value *Neg = dyn_castNegVal(Op1C); if (BO && BO->hasOneUse() && (BO->getOperand(1) == Op1C || BO->getOperand(1) == Neg) && (BO->getOpcode() == Instruction::UDiv || BO->getOpcode() == Instruction::SDiv)) { Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1); // If the division is exact, X % Y is zero, so we end up with X or -X. if (PossiblyExactOperator *SDiv = dyn_cast (BO)) if (SDiv->isExact()) { if (Op1BO == Op1C) return ReplaceInstUsesWith(I, Op0BO); return BinaryOperator::CreateNeg(Op0BO); } Value *Rem; if (BO->getOpcode() == Instruction::UDiv) Rem = Builder->CreateURem(Op0BO, Op1BO); else Rem = Builder->CreateSRem(Op0BO, Op1BO); Rem->takeName(BO); if (Op1BO == Op1C) return BinaryOperator::CreateSub(Op0BO, Rem); return BinaryOperator::CreateSub(Rem, Op0BO); } define %x, i32 %y) { %1 = sdiv i32 %x, %y %2 = mul i32 %1, %y ret i32 %2 } define %x, i32 %y) { %1 = srem i32 %x, %y %2 = sub i32 %x, %1 ret i32 %2 } Compile to LLVM IR Optimize

A Simple Peephole Optimization { Value *Op1C = Op1; BinaryOperator *BO = dyn_cast (Op0); if (!BO || (BO->getOpcode() != Instruction::UDiv && BO->getOpcode() != Instruction::SDiv)) { Op1C = Op0; BO = dyn_cast (Op1); } Value *Neg = dyn_castNegVal(Op1C); if (BO && BO->hasOneUse() && (BO->getOperand(1) == Op1C || BO->getOperand(1) == Neg) && (BO->getOpcode() == Instruction::UDiv || BO->getOpcode() == Instruction::SDiv)) { Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1); // If the division is exact, X % Y is zero, so we end up with X or -X. if (PossiblyExactOperator *SDiv = dyn_cast (BO)) if (SDiv->isExact()) { if (Op1BO == Op1C) return ReplaceInstUsesWith(I, Op0BO); return BinaryOperator::CreateNeg(Op0BO); } Value *Rem; if (BO->getOpcode() == Instruction::UDiv) Rem = Builder->CreateURem(Op0BO, Op1BO); else Rem = Builder->CreateSRem(Op0BO, Op1BO); Rem->takeName(BO); if (Op1BO == Op1C) return BinaryOperator::CreateSub(Op0BO, Rem); return BinaryOperator::CreateSub(Rem, Op0BO); } define %x, i32 %y) { %1 = sdiv i32 %x, %y %2 = mul i32 %1, %y ret i32 %2 } define %x, i32 %y) { %1 = srem i32 %x, %y %2 = sub i32 %x, %1 ret i32 %2 } Optimize define %x, i32 %y) { %1 = sdiv i32 %x, %y %2 = mul i32 %1, %y ret i32 %2 } => define %x, i32 %y) { %1 = srem i32 %x, %y %2 = sub i32 %x, %1 ret i32 %2 }

%1 = sdiv i32 %x, %y %2 = mul i32 %1, %y => %t = srem i32 %x, %y %2 = sub i32 %x, %t A Simple Peephole Optimization { Value *Op1C = Op1; BinaryOperator *BO = dyn_cast (Op0); if (!BO || (BO->getOpcode() != Instruction::UDiv && BO->getOpcode() != Instruction::SDiv)) { Op1C = Op0; BO = dyn_cast (Op1); } Value *Neg = dyn_castNegVal(Op1C); if (BO && BO->hasOneUse() && (BO->getOperand(1) == Op1C || BO->getOperand(1) == Neg) && (BO->getOpcode() == Instruction::UDiv || BO->getOpcode() == Instruction::SDiv)) { Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1); // If the division is exact, X % Y is zero, so we end up with X or -X. if (PossiblyExactOperator *SDiv = dyn_cast (BO)) if (SDiv->isExact()) { if (Op1BO == Op1C) return ReplaceInstUsesWith(I, Op0BO); return BinaryOperator::CreateNeg(Op0BO); } Value *Rem; if (BO->getOpcode() == Instruction::UDiv) Rem = Builder->CreateURem(Op0BO, Op1BO); else Rem = Builder->CreateSRem(Op0BO, Op1BO); Rem->takeName(BO); if (Op1BO == Op1C) return BinaryOperator::CreateSub(Op0BO, Rem); return BinaryOperator::CreateSub(Rem, Op0BO); }

%1 = sdiv i32 %x, %y %2 = mul i32 %1, %y => %t = srem i32 %x, %y %2 = sub i32 %x, %t A Simple Peephole Optimization { Value *Op1C = Op1; BinaryOperator *BO = dyn_cast (Op0); if (!BO || (BO->getOpcode() != Instruction::UDiv && BO->getOpcode() != Instruction::SDiv)) { Op1C = Op0; BO = dyn_cast (Op1); } Value *Neg = dyn_castNegVal(Op1C); if (BO && BO->hasOneUse() && (BO->getOperand(1) == Op1C || BO->getOperand(1) == Neg) && (BO->getOpcode() == Instruction::UDiv || BO->getOpcode() == Instruction::SDiv)) { Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1); // If the division is exact, X % Y is zero, so we end up with X or -X. if (PossiblyExactOperator *SDiv = dyn_cast (BO)) if (SDiv->isExact()) { if (Op1BO == Op1C) return ReplaceInstUsesWith(I, Op0BO); return BinaryOperator::CreateNeg(Op0BO); } Value *Rem; if (BO->getOpcode() == Instruction::UDiv) Rem = Builder->CreateURem(Op0BO, Op1BO); else Rem = Builder->CreateSRem(Op0BO, Op1BO); Rem->takeName(BO); if (Op1BO == Op1C) return BinaryOperator::CreateSub(Op0BO, Rem); return BinaryOperator::CreateSub(Rem, Op0BO); }

%1 = sdiv %x, %y %2 = mul %1, %y => %t = srem %x, %y %2 = sub %x, %t A Simple Peephole Optimization { Value *Op1C = Op1; BinaryOperator *BO = dyn_cast (Op0); if (!BO || (BO->getOpcode() != Instruction::UDiv && BO->getOpcode() != Instruction::SDiv)) { Op1C = Op0; BO = dyn_cast (Op1); } Value *Neg = dyn_castNegVal(Op1C); if (BO && BO->hasOneUse() && (BO->getOperand(1) == Op1C || BO->getOperand(1) == Neg) && (BO->getOpcode() == Instruction::UDiv || BO->getOpcode() == Instruction::SDiv)) { Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1); // If the division is exact, X % Y is zero, so we end up with X or -X. if (PossiblyExactOperator *SDiv = dyn_cast (BO)) if (SDiv->isExact()) { if (Op1BO == Op1C) return ReplaceInstUsesWith(I, Op0BO); return BinaryOperator::CreateNeg(Op0BO); } Value *Rem; if (BO->getOpcode() == Instruction::UDiv) Rem = Builder->CreateURem(Op0BO, Op1BO); else Rem = Builder->CreateSRem(Op0BO, Op1BO); Rem->takeName(BO); if (Op1BO == Op1C) return BinaryOperator::CreateSub(Op0BO, Rem); return BinaryOperator::CreateSub(Rem, Op0BO); }

Name: sdiv general %1 = sdiv %x, %y %2 = mul %1, %y => %t = srem %x, %y %2 = sub %x, %t Name: sdiv exact %1 = sdiv exact %x, %y %2 = mul %1, %y => %2 = %x A Simple Peephole Optimization { Value *Op1C = Op1; BinaryOperator *BO = dyn_cast (Op0); if (!BO || (BO->getOpcode() != Instruction::UDiv && BO->getOpcode() != Instruction::SDiv)) { Op1C = Op0; BO = dyn_cast (Op1); } Value *Neg = dyn_castNegVal(Op1C); if (BO && BO->hasOneUse() && (BO->getOperand(1) == Op1C || BO->getOperand(1) == Neg) && (BO->getOpcode() == Instruction::UDiv || BO->getOpcode() == Instruction::SDiv)) { Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1); // If the division is exact, X % Y is zero, so we end up with X or -X. if (PossiblyExactOperator *SDiv = dyn_cast (BO)) if (SDiv->isExact()) { if (Op1BO == Op1C) return ReplaceInstUsesWith(I, Op0BO); return BinaryOperator::CreateNeg(Op0BO); } Value *Rem; if (BO->getOpcode() == Instruction::UDiv) Rem = Builder->CreateURem(Op0BO, Op1BO); else Rem = Builder->CreateSRem(Op0BO, Op1BO); Rem->takeName(BO); if (Op1BO == Op1C) return BinaryOperator::CreateSub(Op0BO, Rem); return BinaryOperator::CreateSub(Rem, Op0BO); }

Alive Language Pre: C2 % (1<<C1) == 0 %s = shl nsw %X, C1 %r = sdiv %s, C2 => %r = sdiv %X, C2/(1<<C1) Predicates in preconditions may be the result of a dataflow analysis. Precondition Source template Target template

Alive Language Pre: C2 % (1<<C1) == 0 %s = shl nsw %X, C1 %r = sdiv %s, C2 => %r = sdiv %X, C2/(1<<C1) Generalized from LLVM IR: Symbolic constants Implicit types Constants

Alive Refinemen t Constraint s Alive C++ Transformatio n Typing Constraint s

Correctness Criteria 1.Target invokes undefined behavior only when the source does 2.Result of target = result of source when source does not invoke undefined behavior 3.Final memory states are equivalent LLVM has 3 types of UB: Poison values Undef values True UB See paper for more details

The story of a new optimization A developer wrote a new optimization that improves benchmarks: 3.8% perlbmk (SPEC CPU 2000) 1% perlbench (SPEC CPU 2006) 1.2% perlbench (SPEC CPU 2006) w/ LTO+PGO 40 lines of code August 2014

The story of a new optimization The first patch was wrong Pre: isPowerOf2(C1 ^ C2) %x = add %A, C1 %i = icmp ult %x, C3 %y = add %A, C2 %j = icmp ult %y, C3 %r = or %i, %j => %and = and %A, ~(C1 ^ C2) %lhs = add %and, umax(C1, C2) %r = icmp ult %lhs, C3 ERROR: Mismatch in values of %r Example: %A i4 = 0x0 (0) C1 i4 = 0xA (10, -6) C3 i4 = 0x5 (5) C2 i4 = 0x2 (2) %x i4 = 0xA (10, -6) %i i1 = 0x0 (0) %y i4 = 0x2 (2) %j i1 = 0x1 (1, -1) %and i4 = 0x0 (0) %lhs i4 = 0xA (10, -6) Source value: 0x1 (1, -1) Target value: 0x0 (0)

The story of a new optimization The second patch was wrong The third patch was correct! Still fires on the benchmarks! Pre: C1 u> C3 && C2 u> C3 && isPowerOf2(C1 ^ C2) && isPowerOf2(-C1 ^ -C2) && (-C1 ^ -C2) == ((C3-C1) ^ (C3-C2)) && abs(C1-C2) u> C3 %x = add %A, C1 %i = icmp ult %x, C3 %y = add %A, C2 %j = icmp ult %y, C3 %r = or %i, %j => %and = and %A, ~(C1^C2) %lhs = add %and, umax(C1,C2) %r = icmp ult %lhs, C3

Experiments 1.Translated > 300 optimizations from LLVM’s InstCombine to Alive. Found 8 bugs; remaining proved correct. 2.Automatic optimal post-condition strengthening Significantly better than developers 3.Replaced InstCombine with automatically generated code

InstCombine: Stats per File 14% wrong! File# opts. # translated# bugs AddSub67492 AndOrXor Calls80-- Casts77-- Combining63-- Compares245-- LoadStoreAlloca28170 MulDivRem65446 PHI12-- Select74520 Shifts43410 SimplifyDemande d 75-- VectorOps34-- Total1,

Optimal Attribute Inference Pre: C1 % C2 == 0 %m = mul nsw %X, C1 %r = sdiv %m, C2 => %r = mul nsw %X, C1/C2 States that the operation will not result in a signed overflow

Optimal Attribute Inference Weakened 1 precondition Strengthened the postcondition for 70 (21%) optimizations 40% for AddSub, MulDivRem, Shifts Postconditions state, e.g., when an operation will not overflow

Alive is Useful! Released as open-source in Fall 2014 In use by developers across 6 companies Already caught dozens of bugs in new patches Talks about replacing InstCombine

Conclusion (Peephole) optimizers are huge and buggy Presented Alive, a DSL+tool to specify peephole optimizations Usable by compiler developers (easy to learn; friendly interface) Automatic verification Generates C++ implementation automatically Available from

Instruction Attributes Instructions may become poison: NSW: no signed wrap NUW: no unsigned wrap Exact: lossless operation Essential for optimization, but extremely hard to reason by hand

Valid Associativity %t = add %A, %B %r = add %t, %C %t = add %B, %C %r = add %A, %t (A + B) + C = A + (B + C)

Associativity w/ NSW %t = add nsw i8 %A, %B %r = add nsw i8 %t, %C %t = add nsw i8 %B, %C %r = add nsw i8 %A, %t %A = 50 %B = -50 %C = -100 %t = 0 %r = -100 %t = poison (- 150) %r = poison

Long Tail of Optimizations

Definedness Constraints

Poison-free Constraints

PR20186: wrong value %div = sdiv %x, C %r = sub 0, %div => %r = sdiv %x, -C

PR20189: introduce poison value %B = sub 0, %A %C = sub nsw %X, %B => %C = add nsw %X, %A

PR21242: introduce poison value Pre: isPowerOf2(C1) %r = mul nsw %x, C1 => %r = shl nsw %x, log2(C1)

PR21243: wrong value Pre: !WillNotOverflowSignedMul(C1, C2) %Op0 = sdiv %X, C1 %r = sdiv %Op0, C2 => %r = 0

PR21245: wrong value Pre: C2 % (1<<C1) == 0 %s = shl nsw %X, C1 %r = sdiv %s, C2 => %r = sdiv %X, (C2 / (1 << C1))

PR21255: introduce undef behavior %Op0 = lshr %X, C1 %r = udiv %Op0, C2 => %r = udiv %X, (C2 << C1)

PR21256: introduce undef behavior %Op1 = sub 0, %X %r = srem %Op0, %Op1 => %r = srem %Op0, %X

PR21274: introduce undef behavior Pre: isPowerOf2(%Power) %shl = shl %Power, %A %Y = lshr %shl, %B %r = udiv %X, %Y => %sub = sub %A, %B %Y = shl %Power, %sub %r = udiv %X, %Y

Precondition Predicates equivalentAddressValues isPowerOf2 isPowerOf2OrZero isShiftedMask isSignBit MaskedValueIsZero WillNotOverflowSignedAdd WillNotOverflowUnsignedAdd WillNotOverflowSignedSub WillNotOverflowUnsignedSub WillNotOverflowSignedMul WillNotOverflowUnsignedMul WillNotOverflowUnsignedShl