diff options
Diffstat (limited to 'llvm/lib/Target/AArch64/AArch64FastISel.cpp')
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64FastISel.cpp | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp index 179fe4dd7ff..7ee8c47930a 100644 --- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp +++ b/llvm/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; } |