diff --git a/lib/Target/AArch64/AArch64FastISel.cpp b/lib/Target/AArch64/AArch64FastISel.cpp index 179fe4dd7ff..7ee8c47930a 100644 --- a/lib/Target/AArch64/AArch64FastISel.cpp +++ b/lib/Target/AArch64/AArch64FastISel.cpp @@ -2694,8 +2694,11 @@ bool AArch64FastISel::SelectTrunc(const Instruction *I) { bool SrcIsKill = hasTrivialKill(Op); // If we're truncating from i64 to a smaller non-legal type then generate an - // AND. Otherwise, we know the high bits are undefined and a truncate doesn't - // generate any code. + // AND. Otherwise, we know the high bits are undefined and a truncate only + // generate a COPY. We cannot mark the source register also as result + // register, because this can incorrectly transfer the kill flag onto the + // source register. + unsigned ResultReg; if (SrcVT == MVT::i64) { uint64_t Mask = 0; switch (DestVT.SimpleTy) { @@ -2716,12 +2719,16 @@ bool AArch64FastISel::SelectTrunc(const Instruction *I) { unsigned Reg32 = FastEmitInst_extractsubreg(MVT::i32, SrcReg, SrcIsKill, AArch64::sub_32); // Create the AND instruction which performs the actual truncation. - unsigned ANDReg = emitAND_ri(MVT::i32, Reg32, /*IsKill=*/true, Mask); - assert(ANDReg && "Unexpected AND instruction emission failure."); - SrcReg = ANDReg; + ResultReg = emitAND_ri(MVT::i32, Reg32, /*IsKill=*/true, Mask); + assert(ResultReg && "Unexpected AND instruction emission failure."); + } else { + ResultReg = createResultReg(&AArch64::GPR32RegClass); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), ResultReg) + .addReg(SrcReg, getKillRegState(SrcIsKill)); } - UpdateValueMap(I, SrcReg); + UpdateValueMap(I, ResultReg); return true; } diff --git a/test/CodeGen/AArch64/fast-isel-trunc.ll b/test/CodeGen/AArch64/fast-isel-trunc.ll new file mode 100644 index 00000000000..55937eb76fa --- /dev/null +++ b/test/CodeGen/AArch64/fast-isel-trunc.ll @@ -0,0 +1,12 @@ +; RUN: llc -mtriple=aarch64-apple-darwin -fast-isel -fast-isel-abort -verify-machineinstrs < %s + +; Test that %1 doesn't get the kill flag set before its last use. +define i32 @test_trunc(i32 %a) { + %1 = add i32 %a, 1 + %2 = trunc i32 %1 to i16 + %3 = icmp ult i16 1, %2 + %4 = add i32 %1, 1 + %5 = sext i1 %3 to i32 + %6 = and i32 %4, %5 + ret i32 %6 +}