diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index 415164fc9e2cb..710662dc107c5 100644 --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -2337,6 +2337,11 @@ class BitPermutationSelector { ANDIVal, ANDISVal), 0); } + // Caller assumes ResNo == 0, but we might have ResNo != 0 after + // optimizing away a permutation. Kludge with an extra node. + if (Res.getResNo() != 0) + return CurDAG->getMachineNode(PPC::OR, dl, MVT::i32, Res, Res); + return Res.getNode(); } diff --git a/llvm/test/CodeGen/PowerPC/lwzu-i48.ll b/llvm/test/CodeGen/PowerPC/lwzu-i48.ll new file mode 100644 index 0000000000000..8205f5976e876 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/lwzu-i48.ll @@ -0,0 +1,19 @@ +; RUN: llc -mtriple=powerpc-unknown-openbsd < %s | FileCheck %s + +; BitPermutationSelector in PPCISelDAGToDAG.cpp was taking the wrong +; result of a load after optimizing away a permutation. +; Here, the big end of i48 %3 was %1 but should be %0. + +define i32 @hop(ptr %out, ptr %in) { +entry: + %0 = getelementptr i8, ptr %in, i32 28 + %1 = load i32, ptr %0, align 4 + %2 = ptrtoint ptr %0 to i48 + %3 = shl i48 %2, 16 + store i48 %3, ptr %out, align 4 + ret i32 %1 +} +; The stw should store POINTER, not VALUE. +; CHECK: lwzu [[VALUE:[0-9]+]], 28([[POINTER:[0-9]+]]) +; CHECK: mr [[MOVED:[0-9]+]], [[POINTER]] +; CHECK: stw [[MOVED]], 0({{[0-9]+}})