RISC-V vector instruction has register overlapping constraint for certain
instructions, and will cause illegal instruction trap if violated, we use
early clobber to model this constraint, but it can't prevent register allocator
allocated same or overlapped if the input register is undef value, so convert
IMPLICIT_DEF to temporary pseudo could prevent that happen, it's not best way
to resolve this. Ideally we should model the constraint right, but before we
model the constraint right, it's the approach to prevent that happen.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Is this MIR wrong here? Does %10 should be marked as vrm2?
Compiler treat %11 and %10 as M1, %0 as M2, so i think RA doesn't violated the early clobber constraint.
192B early-clobber %11:vr = PseudoVRGATHEREI16_VV_M1_M2 %10:vr, %0:vrm2, 4, 3, implicit $vl, implicit $vtype vrgatherei16.vv v15, v14, v8 // %11 -> v15 // %10 -> v14 // %0 -> v8
Compiler Register allocation result:
********** REWRITE VIRTUAL REGISTERS ********** ********** Function: foo ********** REGISTER MAP ********** [%0 -> $v8m2] VRM2 [%1 -> $v10m2] VRM2 [%2 -> $v12m2] VRM2 [%10 -> $v14] VR [%11 -> $v15] VR [%12 -> $v16] VR [%13 -> $v15] VR [%14 -> $v16] VR [%15 -> $v14] VR [%16 -> $x10] GPR [%17 -> $x10] GPR [%18 -> $x10] GPR
You're right. I mixed up the operand order. I need to go look at this test again. It used to fail. Maybe we fixed it some other way.
I remember now. It only miscompiles with -riscv-enable-subreg-liveness
That produces
foo: # @foo .cfi_startproc # %bb.0: # %loopIR.preheader.i.i vsetvli a0, zero, e16, mf4, ta, ma vid.v v8 vadd.vi v10, v8, 1 vadd.vi v12, v8, 3 .LBB0_1: # %loopIR3.i.i # =>This Inner Loop Header: Depth=1 vl1r.v v9, (zero) vsetivli zero, 4, e8, m1, ta, ma vrgatherei16.vv v11, v9, v8 vrgatherei16.vv v13, v9, v10 vsetvli a0, zero, e8, m1, ta, ma vand.vv v11, v11, v13 vsetivli zero, 4, e8, m1, ta, ma vrgatherei16.vv v13, v9, v12 <- this instruction violates the early clobber constraint vsetvli a0, zero, e8, m1, ta, ma vand.vv v9, v11, v13 vs1r.v v9, (zero) j .LBB0_1 .Lfunc_end0: .size foo, .Lfunc_end0-foo .cfi_endproc # -- End function .section ".note.GNU-stack","",@progbits
Add one more condtion for subreg-liveness.
The assembly show as below:
.p2align 2 # -- Begin function foo .type foo,@function foo: # @foo .cfi_startproc # %bb.0: # %loopIR.preheader.i.i vsetvli a0, zero, e16, mf4, ta, ma vid.v v14 vadd.vi v15, v14, 1 vadd.vi v16, v14, 3 vmv1r.v v8, v14 vmv1r.v v10, v15 vmv1r.v v12, v16 .LBB0_1: # %loopIR3.i.i # =>This Inner Loop Header: Depth=1 vl1r.v v14, (zero) vsetivli zero, 4, e8, m1, ta, ma vrgatherei16.vv v15, v14, v8 vrgatherei16.vv v16, v14, v10 vsetvli a0, zero, e8, m1, ta, ma vand.vv v15, v15, v16 vsetivli zero, 4, e8, m1, ta, ma vrgatherei16.vv v16, v14, v12 vsetvli a0, zero, e8, m1, ta, ma vand.vv v14, v15, v16 vs1r.v v14, (zero) j .LBB0_1 .Lfunc_end0: .size foo, .Lfunc_end0-foo .cfi_endproc # -- End function .section ".note.GNU-stack","",@progbits
llvm/test/CodeGen/RISCV/rvv/undef-earlyclobber-chain.ll | ||
---|---|---|
1 | Could you add a pre-commit patch for this testcase so that could easier demonstrate what's get fixed? |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
50 | SmallPtrSet for Seen |
llvm/test/CodeGen/RISCV/rvv/undef-earlyclobber-chain.ll | ||
---|---|---|
1 | New patch https://reviews.llvm.org/D137763 for test only and set up the dependency. Should I remove the testcase in this patch? |
- Record PHI node subregister change
- New INSERT_SUBREG insert before early-clobber instruciton
- Subreg index computation include PHI node
Handle Sub-register undef+early-clobber
For sub-registers, there is the same issue. The register allocator will also generate the program that breaks the early-clobber constraint. The reason for this situation is that the partial register used in instruction (with early-clobber flag) is undef. For example:
early-clobber %12:vr = PseudoVRGATHEREI16_VV_M1_M2 %10:vr, %1:vrm2, 4, 3, implicit $vl, implicit $vtype
->
vrgatherei16.vv v13, v9, v12
v12 is selected as VRM2, it will occupy the v12~v13. The register allocator still allocates the v13 for %12:vrm2 due to the v13 is undef for %1:vr in the register allocation stage. This is an example of how an undef subregister breaks the early-clobber constraint in the register allocation stage.
Here we propose an approach to fix this problem. The concept is the same as a normal undef register situation. We define the sub-register with pseudo instruction and remove it in the later pass (after RA).
There are three steps for this approach:
- Select the def-use chain from implicit_def to the first user with early-clobber constraint
- Compute the undef sub-register index from collecting information from INSERT_SUBREG and PHI node
- Insert the PseudoInit and INSERT_SUBREG for undefined sub-register after the last INSERT_SUGREG that updates the sub-register
Here we show the example with the pattern that will trigger undef+early-clobber issue.
Step 1
There are three def-use chains we need to care about in this program.
The pattern will look like
v0 = Implicit_def … INSERT_SUBREG | COPY | PHI … early-clobber rd = Op vN
Step 2
The INSERT_SUBREG node third operand is subregister index. It shows that this node defines which sub-register in the whole register. We can use the information to construct the sub-register that is undefined.
We use the LaneBitMask for this purpose.
LaneBitmask == 0xC for whole VRM2 register LaneBitmask == 0x4 for %subreg.sub_vrm1_0 LaneBitmask == 0x8 for %subreg.sub_vrm1_1
If we get the following def-use chain in step1
%4:vrm2 = Implicit_def %0:vrm2 = INSERT_SUBREG %4, %subreg.sub_vrm1_0 early-clobber %11:vr = Op %0
0xC is VRM2’s LaneBitMask and 0x4 is already defined by INSERT_SUBREG in the program.
0xC & ~0x4 = 0x8 -> subreg.sub_vrm1_1
In this case, subreg.sub_vrm1_1 is the undefined sub-register before being used by early-clobber instruction.
Step 3
We can define a sub-register by INSERT_SUBREG between the last INSERT_SUBREG and the user with early-clobber. Our goal is to make sure the sub-registers are all defined before being used by early-clobber instruction.
%4:vrm2 = Implicit_def %0:vrm2 = INSERT_SUBREG %4, %subreg.sub_vrm1_0 early-clobber %11:vr = Op %0
->
%4:vrm2 = Implicit_def %0:vrm2 = INSERT_SUBREG %4, %subreg.sub_vrm1_0 %21:vr = PseudoRVVInitUndefM1 %22:vrm2 = INSERT_SUBREG %1:vrm2, %21:vr, %subreg.sub_vrm1_1 early-clobber %11:vr = Op %22
PHI in def-use chain
In Step 2, PHI will be seen as another instruction that will change the subregister defined region. The PHINodeLaneBitRecord will record the LaneBitMask from both predecessors, and insert the INSERT_SUBREG with this information.
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
2 | pesudo -> pseudo | |
11 | "pesudo" -> "pseudo" in two places | |
19 | pesudo -> pseudo | |
19 | latter -> later | |
246 | Pesudo -> Pseudo | |
247 | regitser -> register | |
289 | Candidata -> Candidate? | |
llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll | ||
28 | Are we treating insert_subreg for segment load tuples the same as inserting a small LMUL into a wider LMUL? |
llvm/test/CodeGen/RISCV/rvv/subregister-undef-early-clobber-vrm4.mir | ||
---|---|---|
118 ↗ | (On Diff #478437) | Why is there an PseudoRVVInitUnde pseudo in the IR before the pass runs? |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
74 | You can pass Register by value | |
106 | origin -> original | |
111 | Can't we do something like VRRegClass.hasSubClassEq(MRI->getRegClass(R)) || VRM2RegClass.hasSubClassEq(MRI->getRegClass(R)) || VRM4RegClass.hasSubClassEq(MRI->getRegClass(R)) || VRM8RegClass.hasSubClassEq(MRI->getRegClass(R)) why do we need to use getVRLargestSuperClass? |
llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll | ||
---|---|---|
28 | This pass doesn't consider segment load as instruction that assign sub-register. The following Insert_subreg work like put %5:vrm2 into %6:vrm4 %1:vrm4 = IMPLICIT_DEF %5:vrm2 = PseudoVLE32_V_M2 killed %4, 0, 5 /* e32 */ %6:vrm4 = INSERT_SUBREG %1, %5, %subreg.sub_vrm2_0 Do we should treat vloxseg2ei32 as INSERT_SUBREG in this patch? |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
172 | Why passing Insts by value? That will make a copy but it doesn't look like we need a copy. | |
182 | Why passing Insts by value? That will make a copy but it doesn't look like we need a copy. | |
183 | unsigned -> Register | |
197 | unsigned -> Register | |
197 | Why passing Insts by value? That will make a copy but it doesn't look like we need a copy. | |
200 | unsigned -> Register | |
299 | unsigned -> Register | |
300 | unsigned -> Register | |
313 | createVirtualRegister returns Register not unsigned | |
317 | createVirtualRegister returns Register not unsigned | |
llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll | ||
28 | Nevermind, I didn't realize this test had so many undef and poison operands. I suspect llvm-reduce or bugpoint. I dislike tests with undef/poison operands. It makes things very fragile. It would be legal for DAG combine to delete a large portion of this test. |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
279 | "the " is unnecessary in this sentence |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
28 | "is be occupied" -> "is occupied" |
Is it possible to insert the PseudoRVVInitUndef instructions after we've left SSA and the LiveIntervals have been built. Would that make it easier to find the undef lanes?
- unsigned -> Register
- use const std::vector<MachineInstr *> & instead of call by value
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
202 | Isn't this calculating for the entire function? But handleSubReg is called for individual instructions. So we'll be recomputing information right? |
This could certainly use some new MIR tests. I didn't look super closely but I'm not sure you're correctly handling undef vs. not-undef subreg defs
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
54 | DenseMap | |
91–101 | I don't understand the point of this function, getSuperClasses is already sorted by largest. You can just take the first? | |
106 | Could this use the new getPhysRegBaseClass? | |
108 | Don't call getRegClass for each use | |
142 | Reg.isVirtual() | |
201 | unique_ptr |
- Use unique_ptr for VRegInfo
- Only run once DetectDeadLanes for each function
- Remove Seen and PHINodeLaneBitRecord
- Only call getRegClass once
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
91–101 | When this function take VRNoV0RegClassID as input. the getSuperClasses will return as following order. AnyRegRegClassID 1 This patch only want those four RegClass as result. | |
106 | Could this hook use for virtual register? It seem only for physical register but this pass run before register allocation. | |
202 | Yes, you're right. we don't need recompute this info for each instruction. It call only once now. |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
40 | Are there any maps in the code anymore? | |
llvm/test/CodeGen/RISCV/O3-pipeline.ll | ||
107 | If I understand correctly, we're effectively running DetectDeadLanes inside of RISCV init undef pass and then running the real DetectDeadLanes pass which won't do anything because we already did it? |
llvm/test/CodeGen/RISCV/O3-pipeline.ll | ||
---|---|---|
107 | Can we run DetectDeadLanes, then run our pass and just use the portion of the DetectDeadLanes that computes the Lane Masks in our pass? |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
282 | Should this be std::unique_ptr<VRegInfo[]> since it points to an array? |
llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp | ||
---|---|---|
149 | I kind of think we should keep these instructions all the way to RISCVAsmPrinter::emitInstruction. Setting the operands to "undef" says it is ok to change the operands after this pass runs, but its not. RISCVExpandPseudo runs late enough there is probably no pass that will change them. Keeping the pseudo all the way to RISCVAsmPrinter::emitInstruction removes any possibility. | |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
88 | Can this be if (RISCV::VRM8RegClass.hasSubClassEq(RC)) return &RISCV::VRM8RegClass; if (RISCV::VRM4RegClass.hasSubClassEq(RC)) return &RISCV::VRM4RegClass; if (RISCV::VRM2RegClass.hasSubClassEq(RC)) return &RISCV::VRM2RegClass; if (RISCV::VRRegClass.hasSubClassEq(RC)) return &RISCV::VRRegClass; return RC; | |
117 | return RISCV::PseudoRVVInitUndefM1; | |
152 | Do we need to scan all operands? Can we check if MO is a tied use and find the operand it is tied to check the early clobber? | |
188 | Use defs()? | |
188 | Replace the place with llvm::any_of? | |
201 | Can we scan uses() instead of operands()? | |
206 | I think we wouldn't need this if we only checked uses? | |
229 | Can we put Info.UsedLanes & ~Info.DefinedLanes into a variable? We use that expression twice | |
232 | Lastest isn't a word |
- Skip undef-init pseudo in ASMEmitter instead of removing it in PseudoExpend pass
- Update operands with defs() or uses()
- Fix some typo
- Use variable to represent Info.UsedLanes & ~Info.DefinedLanes
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
152 | 0B bb.0.entry: 16B LIFETIME_START %stack.0.dst 32B %1:vr = IMPLICIT_DEF 48B early-clobber %0:vr = PseudoVRGATHER_VI_M1 killed %1:vr, 0, 0, 5 64B %2:gpr = ADDI %stack.0.dst, 0 80B PseudoVSE32_V_M1 killed %0:vr, killed %2:gpr, 0, 5 96B LIFETIME_END %stack.0.dst 112B %3:gpr = COPY $x0 128B $x10 = COPY %3:gpr 144B PseudoRET implicit $x10 Here we maybe need scan both defs and uses operand, because the early-clobber operand not always exist tied-to operand. |
llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp | ||
---|---|---|
149 | Skip PseudoRVVInitUndefM1|2|4|8 in RISCVAsmPrinter::emitInstruction and remove undef-init relate function in RISCVExpandPseudo. |
LGTM
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
152 | Right. I wasn't thinking about that right. |
It seems like this breaks under ASan: https://lab.llvm.org/buildbot/#/builders/5/builds/31529/steps/13/logs/stdio
FAIL: LLVM :: CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll (35389 of 72944) ******************** TEST 'LLVM :: CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll' FAILED ******************** Script: -- : 'RUN: at line 2'; /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llc -mtriple=riscv64 -mattr=+f,+m,+zfh,+experimental-zvfh -riscv-enable-subreg-liveness=false < /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll : 'RUN: at line 4'; /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llc -mtriple=riscv64 -mattr=+f,+m,+zfh,+experimental-zvfh < /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll -riscv-enable-subreg-liveness=true| /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll --check-prefix=SUBREGLIVENESS -- Exit Code: 2 Command Output (stderr): -- ================================================================= ==924420==ERROR: AddressSanitizer: use-after-poison on address 0x62100002da58 at pc 0x564ad06d209e bp 0x7ffe116375f0 sp 0x7ffe116375e8 READ of size 8 at 0x62100002da58 thread T0 #0 0x564ad06d209d in operands_begin /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/CodeGen/MachineInstr.h:635:42 #1 0x564ad06d209d in defs /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/CodeGen/MachineInstr.h:679:23 #2 0x564ad06d209d in isEarlyClobberMI /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp:175:26 #3 0x564ad06d209d in processBasicBlock /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp:250:39 #4 0x564ad06d209d in (anonymous namespace)::RISCVInitUndef::runOnMachineFunction(llvm::MachineFunction&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp:270:16 #5 0x564ad2aa92d2 in llvm::MachineFunctionPass::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/CodeGen/MachineFunctionPass.cpp:91:13 #6 0x564ad39ba4a3 in llvm::FPPassManager::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1430:27 #7 0x564ad39d4140 in llvm::FPPassManager::runOnModule(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1476:16 #8 0x564ad39bc312 in runOnModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1545:27 #9 0x564ad39bc312 in llvm::legacy::PassManagerImpl::run(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:535:44 #10 0x564acd741a10 in compileModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/llc/llc.cpp:733:8 #11 0x564acd741a10 in main /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/llc/llc.cpp:420:22 #12 0x7f2985940d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d) #13 0x7f2985940e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d) #14 0x564acd66dba4 in _start (/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llc+0x7670ba4) 0x62100002da58 is located 2392 bytes inside of 4096-byte region [0x62100002d100,0x62100002e100) allocated by thread T0 here: #0 0x564acd72db32 in operator new(unsigned long, std::align_val_t) /b/sanitizer-x86_64-linux-fast/build/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:107:3 #1 0x564acdc2908d in Allocate /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/AllocatorBase.h:86:12 #2 0x564acdc2908d in StartNewSlab /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/Allocator.h:339:42 #3 0x564acdc2908d in llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>::Allocate(unsigned long, llvm::Align) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/Allocator.h:195:5 #4 0x564ad2a81869 in Allocate /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/Allocator.h:209:12 #5 0x564ad2a81869 in operator new<llvm::MallocAllocator, 4096UL, 4096UL, 128UL> /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/Allocator.h:443:20 #6 0x564ad2a81869 in llvm::MachineFunction::init() /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/CodeGen/MachineFunction.cpp:185:15 #7 0x564ad2b43c17 in llvm::MachineModuleInfo::getOrCreateMachineFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/CodeGen/MachineModuleInfo.cpp:108:14 #8 0x564ad2aa8def in llvm::MachineFunctionPass::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/CodeGen/MachineFunctionPass.cpp:46:29 #9 0x564ad39ba4a3 in llvm::FPPassManager::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1430:27 #10 0x564ad39d4140 in llvm::FPPassManager::runOnModule(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1476:16 #11 0x564ad39bc312 in runOnModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1545:27 #12 0x564ad39bc312 in llvm::legacy::PassManagerImpl::run(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:535:44 #13 0x564acd741a10 in compileModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/llc/llc.cpp:733:8 #14 0x564acd741a10 in main /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/llc/llc.cpp:420:22 #15 0x7f2985940d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d) SUMMARY: AddressSanitizer: use-after-poison /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/CodeGen/MachineInstr.h:635:42 in operands_begin Shadow bytes around the buggy address: 0x0c427fffdaf0: 00 f7 00 00 00 00 00 00 00 00 00 f7 00 00 00 00 0x0c427fffdb00: 00 00 00 00 00 00 00 00 00 00 00 00 f7 00 00 00 0x0c427fffdb10: 00 00 00 00 00 00 f7 00 00 00 00 00 00 00 00 00 0x0c427fffdb20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffdb30: 00 00 00 00 00 00 00 f7 00 00 00 00 00 00 00 00 =>0x0c427fffdb40: 00 f7 00 00 00 00 f7 f7 f7 f7 f7[f7]f7 f7 f7 f7 0x0c427fffdb50: f7 00 00 00 00 f7 00 00 00 00 00 00 00 00 00 f7 0x0c427fffdb60: 00 00 00 00 00 00 00 00 f7 00 00 00 00 00 00 00 0x0c427fffdb70: 00 00 f7 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffdb80: 00 00 00 f7 00 00 00 00 00 00 00 00 00 f7 00 00 0x0c427fffdb90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f7 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==924420==ABORTING FileCheck error: '<stdin>' is empty. FileCheck command line: /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll --check-prefix=SUBREGLIVENESS -- ******************** Testing: 0.. 10.. 20.. 30.. 40.. FAIL: LLVM :: CodeGen/RISCV/rvv/undef-earlyclobber-chain.ll (35659 of 72944) ******************** TEST 'LLVM :: CodeGen/RISCV/rvv/undef-earlyclobber-chain.ll' FAILED ******************** Script: -- : 'RUN: at line 2'; /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llc -mtriple riscv64 -mattr=+v -riscv-enable-subreg-liveness < /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/CodeGen/RISCV/rvv/undef-earlyclobber-chain.ll | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/CodeGen/RISCV/rvv/undef-earlyclobber-chain.ll -- Exit Code: 2 Command Output (stderr): -- ================================================================= ==928893==ERROR: AddressSanitizer: use-after-poison on address 0x62100005a980 at pc 0x55a20925a09e bp 0x7ffebd9ed930 sp 0x7ffebd9ed928 READ of size 8 at 0x62100005a980 thread T0 #0 0x55a20925a09d in operands_begin /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/CodeGen/MachineInstr.h:635:42 #1 0x55a20925a09d in defs /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/CodeGen/MachineInstr.h:679:23 #2 0x55a20925a09d in isEarlyClobberMI /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp:175:26 #3 0x55a20925a09d in processBasicBlock /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp:250:39 #4 0x55a20925a09d in (anonymous namespace)::RISCVInitUndef::runOnMachineFunction(llvm::MachineFunction&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp:270:16 #5 0x55a20b6312d2 in llvm::MachineFunctionPass::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/CodeGen/MachineFunctionPass.cpp:91:13 #6 0x55a20c5424a3 in llvm::FPPassManager::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1430:27 #7 0x55a20c55c140 in llvm::FPPassManager::runOnModule(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1476:16 #8 0x55a20c544312 in runOnModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1545:27 #9 0x55a20c544312 in llvm::legacy::PassManagerImpl::run(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:535:44 #10 0x55a2062c9a10 in compileModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/llc/llc.cpp:733:8 #11 0x55a2062c9a10 in main /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/llc/llc.cpp:420:22 #12 0x7f2447396d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d) #13 0x7f2447396e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d) #14 0x55a2061f5ba4 in _start (/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llc+0x7670ba4) 0x62100005a980 is located 2176 bytes inside of 4096-byte region [0x62100005a100,0x62100005b100) allocated by thread T0 here: #0 0x55a2062b5b32 in operator new(unsigned long, std::align_val_t) /b/sanitizer-x86_64-linux-fast/build/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:107:3 #1 0x55a2067b108d in Allocate /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/AllocatorBase.h:86:12 #2 0x55a2067b108d in StartNewSlab /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/Allocator.h:339:42 #3 0x55a2067b108d in llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>::Allocate(unsigned long, llvm::Align) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/Allocator.h:195:5 #4 0x55a20b609869 in Allocate /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/Allocator.h:209:12 #5 0x55a20b609869 in operator new<llvm::MallocAllocator, 4096UL, 4096UL, 128UL> /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/Support/Allocator.h:443:20 #6 0x55a20b609869 in llvm::MachineFunction::init() /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/CodeGen/MachineFunction.cpp:185:15 #7 0x55a20b6cbc17 in llvm::MachineModuleInfo::getOrCreateMachineFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/CodeGen/MachineModuleInfo.cpp:108:14 #8 0x55a20b630def in llvm::MachineFunctionPass::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/CodeGen/MachineFunctionPass.cpp:46:29 #9 0x55a20c5424a3 in llvm::FPPassManager::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1430:27 #10 0x55a20c55c140 in llvm::FPPassManager::runOnModule(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1476:16 #11 0x55a20c544312 in runOnModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1545:27 #12 0x55a20c544312 in llvm::legacy::PassManagerImpl::run(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:535:44 #13 0x55a2062c9a10 in compileModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/llc/llc.cpp:733:8 #14 0x55a2062c9a10 in main /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/llc/llc.cpp:420:22 #15 0x7f2447396d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d) SUMMARY: AddressSanitizer: use-after-poison /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/include/llvm/CodeGen/MachineInstr.h:635:42 in operands_begin Shadow bytes around the buggy address: 0x0c42800034e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c42800034f0: 00 f7 00 00 00 00 00 00 00 00 00 f7 00 00 00 00 0x0c4280003500: f7 00 00 00 00 00 00 00 00 00 f7 00 00 00 00 00 0x0c4280003510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4280003520: 00 00 00 00 00 00 00 00 00 00 00 f7 f7 f7 f7 f7 =>0x0c4280003530:[f7]f7 f7 f7 f7 f7 00 00 00 00 f7 00 00 00 00 00 0x0c4280003540: 00 00 00 00 f7 00 00 00 00 00 00 00 00 00 00 00 0x0c4280003550: 00 00 00 00 00 f7 00 00 00 00 00 00 00 00 00 f7 0x0c4280003560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4280003570: f7 00 00 00 00 00 00 00 00 00 f7 00 00 00 00 f7 0x0c4280003580: 00 00 00 00 00 00 00 00 00 f7 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==928893==ABORTING FileCheck error: '<stdin>' is empty. FileCheck command line: /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/CodeGen/RISCV/rvv/undef-earlyclobber-chain.ll
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
176 | Any idea why the llvm::any_of didn't work? |
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
176 | Because the thing that calls this is erasing from the MBB whilst it iterates over it... so this is the wrong fix and probably doesn't even work either |
- Restore any_of version isEarlyClobberMI
- handleImplicitDef will remove ImplicitDef MI, and be use in following for loop body. I think this is the reason it trigger ASan fail.
llvm/lib/Target/RISCV/RISCVRVVInitUndef.cpp | ||
---|---|---|
176 | Do we need [&] here or would [] work? |
- Rename some variables name (UserMOs -> UseMOs, UseMO -> UserMO)
- Reorder if statement in processBasicBlock
- Use [] instead of [&] because the body of the function doesn't use any variables other than DefMO.
Illegal instructions "vslideup.vi v8, v8, 5" and "vslideup.vi v8, v8, 2" are generated.
Looks like the undef operand is not the passthru operand in this case. It's the value to slide. This pass only fixed the case where the passthru was undef. Can you file a new issue?
I kind of think we should keep these instructions all the way to RISCVAsmPrinter::emitInstruction. Setting the operands to "undef" says it is ok to change the operands after this pass runs, but its not. RISCVExpandPseudo runs late enough there is probably no pass that will change them. Keeping the pseudo all the way to RISCVAsmPrinter::emitInstruction removes any possibility.