diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -4550,9 +4550,9 @@ ConstantInt *RHS = dyn_cast(AddrInst->getOperand(1)); if (!RHS || RHS->getBitWidth() > 64) return false; - int64_t Scale = RHS->getSExtValue(); - if (Opcode == Instruction::Shl) - Scale = 1LL << Scale; + int64_t Scale = Opcode == Instruction::Shl + ? 1LL << RHS->getLimitedValue(RHS->getBitWidth() - 1) + : RHS->getSExtValue(); return matchScaledValue(AddrInst->getOperand(0), Scale, Depth); } diff --git a/llvm/test/CodeGen/X86/codegen-prepare-oob-shl.ll b/llvm/test/CodeGen/X86/codegen-prepare-oob-shl.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/codegen-prepare-oob-shl.ll @@ -0,0 +1,22 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -mtriple i686-unknown-unknown -codegenprepare -S | FileCheck %s + +target datalayout = "e-p:8:8" + +; The shl has UB (shift count oob). This used to result in undefined behavior +; in codegenprepare when AddressingModeMatcher::matchOperationAddr tried to +; shift a variable by that amount during compilation. Intent with the test +; case is to verify that this compiles without complaints even if opt is built +; with ubsan enabled. +define dso_local void @main(i32 %a, [3 x { i8, i8 }*]* %p) { +; CHECK-LABEL: @main( +; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], -1229216766 +; CHECK-NEXT: [[ARRAYIDX926:%.*]] = getelementptr inbounds [3 x { i8, i8 }*], [3 x { i8, i8 }*]* [[P:%.*]], i32 0, i32 [[SHL]] +; CHECK-NEXT: [[L0:%.*]] = load { i8, i8 }*, { i8, i8 }** [[ARRAYIDX926]], align 1 +; CHECK-NEXT: ret void +; + %shl = shl i32 %a, -1229216766 + %arrayidx926 = getelementptr inbounds [3 x { i8, i8 }*], [3 x { i8, i8 }*]* %p, i32 0, i32 %shl + %l0 = load { i8, i8 }*, { i8, i8 }** %arrayidx926, align 1 + ret void +}