For Mips64 N32/N64 ABI, unsigned 32-bit integers should be sign extended. This patch also fixes cases where operand for truncate instruction is in another basic block.
Diff Detail
- Repository
- rL LLVM
Event Timeline
TruncNoExt node is used for values smaller than 32bit, where we don't need to do sign extension.
Could you point me at the original problem you're trying to solve? The new node appears to be doing the same job as AssertZExt and I'm fairly certain this is headed into a bigger problem we encountered back in spring.
The summary of the larger bug is that MIPS64 lacks a 32-bit comparison instruction (the same opcode performs a 64-bit comparison) but the code generator isn't properly aware of this. As a result, the code generator expects the hardware to ignore bits 32-63 but they actually affect the result. This bug gets exposed as we increase our reliance on the code generator getting it right by removing the redundant extends.
@vkalintiris has been working on a fix to the larger problem (D10970 and a second part to handle the operands). Once both are committed we should be able to safely remove any redundant sign extends that remain.
lib/Target/Mips/MipsISelLowering.cpp | ||
---|---|---|
2909–2910 | Our calling convention doesn't really matter at this point since clang is responsible for emitting appropriate signext/zeroext for the given ABI. We just need to follow what the IR says. | |
2927–2933 | AssertZext already eliminates any extends the the TRUNCATE would otherwise introduce. I suspect something else in the DAG is causing the sign extends you're trying to remove. | |
test/CodeGen/Mips/divrem.ll | ||
76–186 | Please leave these as zeroext. They use zeroext to avoid noise around the interesting generated code and there's no need to match the standard ABI in this kind of test. | |
test/CodeGen/Mips/mips64-sign-extend.ll | ||
6 | This will match any i32->i64 sign extend in the output file, even in different functions. You need some CHECK-LABEL's to restrict the scope of the matching. | |
31 | As above, this could match in any function. | |
38–45 | These CHECK-NOT's don't do what you expect if the earlier CHECK's match in an unexpected function. | |
test/CodeGen/Mips/octeon_popcnt.ll | ||
24 | Please leave these as zeroext. They use zeroext to avoid noise around the interesting generated code and there's no need to match the standard ABI in this kind of test. |
Original problem is where operand for truncate instruction is in another basic block (foo1 function in mips64-sign-extend.ll). SelectionDAG for this case (AssertZext node was created in SelectionDAGBuilder.cpp (RegsForValue::getCopyFromRegs)):
Optimized legalized selection DAG: BB#1 'foo:if.then' SelectionDAG has 13 nodes: t0: ch = EntryToken t2: i64,ch = CopyFromReg t0, Register:i64 %vreg0 t4: i64 = AssertZext t2, ValueType:ch:i32 t5: i32 = truncate t4 t20: i32 = setcc t5, Constant:i32<-1>, setgt:ch t12: ch = brcond t0, t20, BasicBlock:ch<if.else 0x14ad3e0> t14: ch = br t12, BasicBlock:ch<if.then4 0x14ad318>
In this case, we need to do sign extension for (trunc (assertzext GPR64:$src)), so I changed this pattern to do sign extension. After this change, for arguments zeroext i1, zeroext i8 and zeroext i16, we got redundant SLL instruction. TruncNoExt node is used to prevent generating SLL instruction in these cases.
This is the same problem Vasileios ran into when he removed some redundant sign extends. The root of the problem is that the legalized SelectionDAG isn't actually legal for MIPS64 since we don't have any 32-bit comparison operations (setlt and friends compare GPR-width values and produce a GPR-width 0 or 1). The legalizer should be promoting both the operands and result of the setcc to i64 which will result in the following DAG:
t0: ch = EntryToken t2: i64,ch = CopyFromReg t0, Register:i64 %vreg0 t4: i64 = AssertZext t2, ValueType:ch:i32 t5: i32 = truncate t4 t6: i64 = sext t5 t20: i64 = setcc t6, Constant:i64<-1>, setgt:ch t12: ch = brcond t0, t20, BasicBlock:ch<if.else 0x14ad3e0> t14: ch = br t12, BasicBlock:ch<if.then4 0x14ad318>
the t6: i64 = sext t5 will then lead to a sll instruction.
One other thing to mention is that the redundant SLL instructions you mention in:
After this change, for arguments zeroext i1, zeroext i8 and zeroext i16, we got redundant SLL instruction.
are needed to promote the i8 to an i32 (which as noted above, should be an i64) for use in the signed comparison.
I applied D10970, but i got compiler error:
llvm/lib/Target/Mips/Mips64r6InstrInfo.td:134:11: error: Couldn't find multiclass 'Cmp_Pats'
What should we do about the problem where operand for truncate instruction is in another basic block?
It depends on D14612 so you need to apply that first.
What should we do about the problem where operand for truncate instruction is in another basic block?
It's the same issue, the sign extend is missing because our legalized SelectionDAG is actually illegal for MIPS64. It will be fixed by promoting the setcc to i64.
It depends on D14612 so you need to apply that first.
Nearly forgot to say: This patch is only half the solution. We also need to promote the operands of setcc nodes.
Our calling convention doesn't really matter at this point since clang is responsible for emitting appropriate signext/zeroext for the given ABI. We just need to follow what the IR says.