-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[TargetLowering] Use Correct VT for Multi-out Asm #116024
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TargetLowering] Use Correct VT for Multi-out Asm #116024
Conversation
This was overlooked in 7d94043 - when inline assembly has multiple outputs, they are returned as members of a struct, and the `getAsmOperandType` needs to be called for each member of struct. I noticed this when trying to use the same mechanism in the RISC-V backend. Committing two tests: - One that shows a crash before this change, which is fixed by this change. - One (commented out) that shows a different crash with tied inputs/outputs. This is commented as it is not fixed by this change and needs more work in target-independent inline asm handling code.
@llvm/pr-subscribers-backend-aarch64 Author: Sam Elliott (lenary) ChangesThis was overlooked in 7d94043 - when inline assembly has multiple outputs, they are returned as members of a struct, and the I noticed this when trying to use the same mechanism in the RISC-V backend. Committing two tests:
Full diff: https://github.com/llvm/llvm-project/pull/116024.diff 2 Files Affected:
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 8287565336b54d..1940ed25ecfd0d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -5753,7 +5753,7 @@ TargetLowering::ParseConstraints(const DataLayout &DL,
assert(!Call.getType()->isVoidTy() && "Bad inline asm!");
if (auto *STy = dyn_cast<StructType>(Call.getType())) {
OpInfo.ConstraintVT =
- getSimpleValueType(DL, STy->getElementType(ResNo));
+ getAsmOperandValueType(DL, STy->getElementType(ResNo)).getSimpleVT();
} else {
assert(ResNo == 0 && "Asm only has one result!");
OpInfo.ConstraintVT =
diff --git a/llvm/test/CodeGen/AArch64/ls64-inline-asm.ll b/llvm/test/CodeGen/AArch64/ls64-inline-asm.ll
index ed91f4adb8d3fb..d3d8ecb99f45ec 100644
--- a/llvm/test/CodeGen/AArch64/ls64-inline-asm.ll
+++ b/llvm/test/CodeGen/AArch64/ls64-inline-asm.ll
@@ -103,3 +103,37 @@ entry:
call void asm sideeffect "st64b $0,[$1]", "r,r,~{memory}"(i512 %s.sroa.0.0.insert.insert, ptr %addr)
ret void
}
+
+define void @multi_output(ptr %addr) {
+; CHECK-LABEL: multi_output:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: //APP
+; CHECK-NEXT: ld64b x0, [x0]
+; CHECK-NEXT: mov x8, x0
+; CHECK-NEXT: //NO_APP
+; CHECK-NEXT: stp x6, x7, [x8, #48]
+; CHECK-NEXT: stp x4, x5, [x8, #32]
+; CHECK-NEXT: stp x2, x3, [x8, #16]
+; CHECK-NEXT: stp x0, x1, [x8]
+; CHECK-NEXT: ret
+entry:
+ %val = call { i512, ptr } asm sideeffect "ld64b $0, [$2]; mov $1, $2", "=r,=r,r,~{memory}"(ptr %addr)
+ %val0 = extractvalue { i512, ptr } %val, 0
+ %val1 = extractvalue { i512, ptr } %val, 1
+ store i512 %val0, ptr %val1, align 8
+ ret void
+}
+
+; FIXME: This case still crashes in RegsForValue::AddInlineAsmOperands without
+; additional changes. I believe this is a bug in target-independent code, that
+; is worked around in the RISC-V and SystemZ backends, but should almost
+; certainly be fixed instead.
+; define void @tied_constraints(ptr %addr) {
+; entry:
+; %in = load i512, ptr %addr, align 8
+; %val = call { i512, ptr } asm sideeffect "nop", "=r,=r,0,1,~{memory}"(i512 %in, ptr %addr)
+; %val0 = extractvalue { i512, ptr } %val, 0
+; %val1 = extractvalue { i512, ptr } %val, 1
+; store i512 %val0, ptr %val1, align 8
+; ret void
+; }
|
@llvm/pr-subscribers-llvm-selectiondag Author: Sam Elliott (lenary) ChangesThis was overlooked in 7d94043 - when inline assembly has multiple outputs, they are returned as members of a struct, and the I noticed this when trying to use the same mechanism in the RISC-V backend. Committing two tests:
Full diff: https://github.com/llvm/llvm-project/pull/116024.diff 2 Files Affected:
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 8287565336b54d..1940ed25ecfd0d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -5753,7 +5753,7 @@ TargetLowering::ParseConstraints(const DataLayout &DL,
assert(!Call.getType()->isVoidTy() && "Bad inline asm!");
if (auto *STy = dyn_cast<StructType>(Call.getType())) {
OpInfo.ConstraintVT =
- getSimpleValueType(DL, STy->getElementType(ResNo));
+ getAsmOperandValueType(DL, STy->getElementType(ResNo)).getSimpleVT();
} else {
assert(ResNo == 0 && "Asm only has one result!");
OpInfo.ConstraintVT =
diff --git a/llvm/test/CodeGen/AArch64/ls64-inline-asm.ll b/llvm/test/CodeGen/AArch64/ls64-inline-asm.ll
index ed91f4adb8d3fb..d3d8ecb99f45ec 100644
--- a/llvm/test/CodeGen/AArch64/ls64-inline-asm.ll
+++ b/llvm/test/CodeGen/AArch64/ls64-inline-asm.ll
@@ -103,3 +103,37 @@ entry:
call void asm sideeffect "st64b $0,[$1]", "r,r,~{memory}"(i512 %s.sroa.0.0.insert.insert, ptr %addr)
ret void
}
+
+define void @multi_output(ptr %addr) {
+; CHECK-LABEL: multi_output:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: //APP
+; CHECK-NEXT: ld64b x0, [x0]
+; CHECK-NEXT: mov x8, x0
+; CHECK-NEXT: //NO_APP
+; CHECK-NEXT: stp x6, x7, [x8, #48]
+; CHECK-NEXT: stp x4, x5, [x8, #32]
+; CHECK-NEXT: stp x2, x3, [x8, #16]
+; CHECK-NEXT: stp x0, x1, [x8]
+; CHECK-NEXT: ret
+entry:
+ %val = call { i512, ptr } asm sideeffect "ld64b $0, [$2]; mov $1, $2", "=r,=r,r,~{memory}"(ptr %addr)
+ %val0 = extractvalue { i512, ptr } %val, 0
+ %val1 = extractvalue { i512, ptr } %val, 1
+ store i512 %val0, ptr %val1, align 8
+ ret void
+}
+
+; FIXME: This case still crashes in RegsForValue::AddInlineAsmOperands without
+; additional changes. I believe this is a bug in target-independent code, that
+; is worked around in the RISC-V and SystemZ backends, but should almost
+; certainly be fixed instead.
+; define void @tied_constraints(ptr %addr) {
+; entry:
+; %in = load i512, ptr %addr, align 8
+; %val = call { i512, ptr } asm sideeffect "nop", "=r,=r,0,1,~{memory}"(i512 %in, ptr %addr)
+; %val0 = extractvalue { i512, ptr } %val, 0
+; %val1 = extractvalue { i512, ptr } %val, 1
+; store i512 %val0, ptr %val1, align 8
+; ret void
+; }
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
getAsmOperandValueType(DL, STy->getElementType(ResNo)) | ||
.getSimpleVT(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens for nested structs? Are those supported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe the lowering from an inline assembly statement to a call ... asm
will create a nested struct. It either returns the single type corresponding to the output (if there's one output), or a struct with a member per output (if there's multiple outputs). I think that inline asm inputs/outputs cannot themselves be structs, but I'm not 100% certain of that. This code would suggest not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tried it and it seems to hit unreachable "Unknown type!"; we should do better here and report a proper error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better errors for IR that frontends don't produce seems like a different issue to fixing an actual crash in the AArch64 backend that frontends can hit, so should be in a different PR IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, separate fix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't touched this code in ages, but looks sensible.
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/92/builds/9715 Here is the relevant piece of the build log for the reference
|
This was overlooked in 7d94043 - when inline assembly has multiple outputs, they are returned as members of a struct, and the
getAsmOperandType
needs to be called for each member of struct. The difference between this and the single-output case is that in the latter, there isn't a struct wrapping the outputs.I noticed this when trying to use the same mechanism in the RISC-V backend.
Committing two tests: