-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[SPIRV] Start adding support for int128
#170798
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
Conversation
|
@llvm/pr-subscribers-backend-spir-v Author: Alex Voicu (AlexVlx) ChangesLLVM has pretty thorough support for Full diff: https://github.com/llvm/llvm-project/pull/170798.diff 8 Files Affected:
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index 62f5e47c5ea3b..42de884840dc9 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -50,6 +50,14 @@ void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI,
unsigned IsBitwidth16 = MI->getFlags() & SPIRV::INST_PRINTER_WIDTH16;
const unsigned NumVarOps = MI->getNumOperands() - StartIndex;
+ if (MI->getOpcode() == SPIRV::OpConstantI && NumVarOps > 2) {
+ // SPV_ALTERA_arbitrary_precision_integers allows for integer widths greater
+ // than 64, which will be encoded via multiple operands.
+ for (unsigned I = StartIndex; I != MI->getNumOperands(); ++I)
+ O << ' ' << MI->getOperand(I).getImm();
+ return;
+ }
+
assert((NumVarOps == 1 || NumVarOps == 2) &&
"Unsupported number of bits for literal variable");
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 0fb44052527f0..693795d09dacd 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -151,22 +151,17 @@ SPIRVType *SPIRVGlobalRegistry::getOpTypeBool(MachineIRBuilder &MIRBuilder) {
}
unsigned SPIRVGlobalRegistry::adjustOpTypeIntWidth(unsigned Width) const {
- if (Width > 64)
- report_fatal_error("Unsupported integer width!");
- const SPIRVSubtarget &ST = cast<SPIRVSubtarget>(CurMF->getSubtarget());
- if (ST.canUseExtension(
- SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
- ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4))
- return Width;
if (Width <= 8)
- Width = 8;
+ return 8;
else if (Width <= 16)
- Width = 16;
+ return 16;
else if (Width <= 32)
- Width = 32;
- else
- Width = 64;
- return Width;
+ return 32;
+ else if (Width <= 64)
+ return 64;
+ else if (Width <= 128)
+ return 128;
+ reportFatalUsageError("Unsupported Integer width!");
}
SPIRVType *SPIRVGlobalRegistry::getOpTypeInt(unsigned Width,
@@ -413,7 +408,7 @@ Register SPIRVGlobalRegistry::createConstInt(const ConstantInt *CI,
MIB = MIRBuilder.buildInstr(SPIRV::OpConstantI)
.addDef(Res)
.addUse(getSPIRVTypeID(SpvType));
- addNumImm(APInt(BitWidth, CI->getZExtValue()), MIB);
+ addNumImm(CI->getValue(), MIB);
} else {
MIB = MIRBuilder.buildInstr(SPIRV::OpConstantNull)
.addDef(Res)
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index b5912c27316c9..38d4f7d706083 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -48,6 +48,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
const LLT s16 = LLT::scalar(16);
const LLT s32 = LLT::scalar(32);
const LLT s64 = LLT::scalar(64);
+ const LLT s128 = LLT::scalar(128);
const LLT v16s64 = LLT::fixed_vector(16, 64);
const LLT v16s32 = LLT::fixed_vector(16, 32);
@@ -307,7 +308,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
typeInSet(1, allPtrsScalarsAndVectors)));
getActionDefinitionsBuilder({G_IMPLICIT_DEF, G_FREEZE})
- .legalFor({s1})
+ .legalFor({s1, s128})
.legalFor(allFloatAndIntScalarsAndPtrs)
.legalFor(allowedVectorTypes)
.moreElementsToNextPow2(0)
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 2feb73d8dedfa..832139f7d7354 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -1395,6 +1395,17 @@ void addInstrRequirements(const MachineInstr &MI,
Reqs.addCapability(SPIRV::Capability::Int16);
else if (BitWidth == 8)
Reqs.addCapability(SPIRV::Capability::Int8);
+ else {
+ if (!ST.canUseExtension(
+ SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers))
+ reportFatalUsageError(
+ "OpTypeInt type with a width other than 8, 16, 32 or 64 bits "
+ "requires the following SPIR-V extension: "
+ "SPV_ALTERA_arbitrary_precision_integers");
+ Reqs.addExtension(
+ SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
+ Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionIntegersALTERA);
+ }
break;
}
case SPIRV::OpDot: {
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 7fdb0fafa3719..6feae31c8370f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -108,6 +108,13 @@ void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB) {
// Asm Printer needs this info to print 64-bit operands correctly
MIB.getInstr()->setAsmPrinterFlag(SPIRV::ASM_PRINTER_WIDTH64);
return;
+ } else if (Bitwidth <= 128) {
+ uint32_t LowBits = Imm.getRawData()[0] & 0xffffffff;
+ uint32_t MidBits0 = (Imm.getRawData()[0] >> 32) & 0xffffffff;
+ uint32_t MidBits1 = Imm.getRawData()[1] & 0xffffffff;
+ uint32_t HighBits = (Imm.getRawData()[1] >> 32) & 0xffffffff;
+ MIB.addImm(LowBits).addImm(MidBits0).addImm(MidBits1).addImm(HighBits);
+ return;
}
report_fatal_error("Unsupported constant bitwidth");
}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-addsub.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-addsub.ll
new file mode 100644
index 0000000000000..c90ffdd17996c
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-addsub.ll
@@ -0,0 +1,67 @@
+; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-ERROR: LLVM ERROR: OpTypeInt type with a width other than 8, 16, 32 or 64 bits requires the following SPIR-V extension: SPV_ALTERA_arbitrary_precision_integers
+
+; CHECK: OpCapability ArbitraryPrecisionIntegersALTERA
+; CHECK: OpExtension "SPV_ALTERA_arbitrary_precision_integers"
+; CHECK: OpName %[[#TestAdd:]] "test_add"
+; CHECK: OpName %[[#TestSub:]] "test_sub"
+; CHECK: %[[#Int128Ty:]] = OpTypeInt 128 0
+; CHECK: %[[#Const64Int128:]] = OpConstant %[[#Int128Ty]] 64 0 0 0
+
+; CHECK: %[[#TestAdd]] = OpFunction
+define spir_func void @test_add(i64 %AL, i64 %AH, i64 %BL, i64 %BH, ptr %RL, ptr %RH) {
+entry:
+; CHECK: {{.*}} = OpUConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpUConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpShiftLeftLogical %[[#Int128Ty]] {{%[0-9]+}} %[[#Const64Int128]]
+; CHECK: {{.*}} = OpBitwiseOr %[[#Int128Ty]]
+; CHECK: {{.*}} = OpUConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpIAdd %[[#Int128Ty]]
+ %tmp1 = zext i64 %AL to i128
+ %tmp23 = zext i64 %AH to i128
+ %tmp4 = shl i128 %tmp23, 64
+ %tmp5 = or i128 %tmp4, %tmp1
+ %tmp67 = zext i64 %BL to i128
+ %tmp89 = zext i64 %BH to i128
+ %tmp11 = shl i128 %tmp89, 64
+ %tmp12 = or i128 %tmp11, %tmp67
+ %tmp15 = add i128 %tmp12, %tmp5
+ %tmp1617 = trunc i128 %tmp15 to i64
+ store i64 %tmp1617, ptr %RL
+ %tmp21 = lshr i128 %tmp15, 64
+ %tmp2122 = trunc i128 %tmp21 to i64
+ store i64 %tmp2122, ptr %RH
+ ret void
+; CHECK: OpFunctionEnd
+}
+
+; CHECK: %[[#TestSub]] = OpFunction
+define spir_func void @test_sub(i64 %AL, i64 %AH, i64 %BL, i64 %BH, ptr %RL, ptr %RH) {
+entry:
+; CHECK: {{.*}} = OpUConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpUConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpShiftLeftLogical %[[#Int128Ty]] {{%[0-9]+}} %[[#Const64Int128]]
+; CHECK: {{.*}} = OpBitwiseOr %[[#Int128Ty]]
+; CHECK: {{.*}} = OpUConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpISub %[[#Int128Ty]]
+ %tmp1 = zext i64 %AL to i128
+ %tmp23 = zext i64 %AH to i128
+ %tmp4 = shl i128 %tmp23, 64
+ %tmp5 = or i128 %tmp4, %tmp1
+ %tmp67 = zext i64 %BL to i128
+ %tmp89 = zext i64 %BH to i128
+ %tmp11 = shl i128 %tmp89, 64
+ %tmp12 = or i128 %tmp11, %tmp67
+ %tmp15 = sub i128 %tmp5, %tmp12
+ %tmp1617 = trunc i128 %tmp15 to i64
+ store i64 %tmp1617, ptr %RL
+ %tmp21 = lshr i128 %tmp15, 64
+ %tmp2122 = trunc i128 %tmp21 to i64
+ store i64 %tmp2122, ptr %RH
+ ret void
+; CHECK: OpFunctionEnd
+}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-arith.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-arith.ll
new file mode 100644
index 0000000000000..d1de5df499566
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-arith.ll
@@ -0,0 +1,27 @@
+; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-ERROR: LLVM ERROR: OpTypeInt type with a width other than 8, 16, 32 or 64 bits requires the following SPIR-V extension: SPV_ALTERA_arbitrary_precision_integers
+
+; CHECK: OpCapability ArbitraryPrecisionIntegersALTERA
+; CHECK: OpExtension "SPV_ALTERA_arbitrary_precision_integers"
+; CHECK: OpName %[[#Foo:]] "foo"
+; CHECK: %[[#Int128Ty:]] = OpTypeInt 128 0
+
+; CHECK: %[[#Foo]] = OpFunction
+define i64 @foo(i64 %x, i64 %y, i32 %amt) {
+; CHECK: {{.*}} = OpUConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpSConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpBitwiseOr %[[#Int128Ty]]
+; CHECK: {{.*}} = OpUConvert %[[#Int128Ty]]
+; CHECK: {{.*}} = OpShiftRightLogical %[[#Int128Ty]]
+ %tmp0 = zext i64 %x to i128
+ %tmp1 = sext i64 %y to i128
+ %tmp2 = or i128 %tmp0, %tmp1
+ %tmp7 = zext i32 13 to i128
+ %tmp3 = lshr i128 %tmp2, %tmp7
+ %tmp4 = trunc i128 %tmp3 to i64
+ ret i64 %tmp4
+}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-switch-lower.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-switch-lower.ll
new file mode 100644
index 0000000000000..669e9362605a5
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_ALTERA_arbitrary_precision_integers/i128-switch-lower.ll
@@ -0,0 +1,27 @@
+; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-ERROR: LLVM ERROR: OpTypeInt type with a width other than 8, 16, 32 or 64 bits requires the following SPIR-V extension: SPV_ALTERA_arbitrary_precision_integers
+
+; CHECK: OpCapability ArbitraryPrecisionIntegersALTERA
+; CHECK: OpExtension "SPV_ALTERA_arbitrary_precision_integers"
+; CHECK: OpName %[[#Test:]] "test"
+; CHECK: OpName %[[#Exit:]] "exit"
+; CHECK: %[[#Int128Ty:]] = OpTypeInt 128 0
+; CHECK: %[[#UndefInt128:]] = OpUndef %[[#Int128Ty]]
+
+; CHECK: %[[#Test]] = OpFunction
+define void @test() {
+entry:
+; CHECK: OpSwitch %[[#UndefInt128]] %[[#Exit]] 0 0 3 0 %[[#Exit]] 0 0 5 0 %[[#Exit]] 0 0 4 0 %[[#Exit]] 0 0 8 0 %[[#Exit]]
+ switch i128 poison, label %exit [
+ i128 55340232221128654848, label %exit
+ i128 92233720368547758080, label %exit
+ i128 73786976294838206464, label %exit
+ i128 147573952589676412928, label %exit
+ ]
+exit:
+ unreachable
+}
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
|
@AlexVlx The PR fixes this failing test case I had. Would it be worth adding it? It does test a different int width. |
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.
LGTM
BTW, Slava no longer works on SPIR-V backend. Don't think he'd object tagging him, but just FYI.
| ; CHECK: OpName %[[#TestAdd:]] "test_add" | ||
| ; CHECK: OpName %[[#TestSub:]] "test_sub" | ||
| ; CHECK: %[[#Int128Ty:]] = OpTypeInt 128 0 | ||
| ; CHECK: %[[#Const64Int128:]] = OpConstant %[[#Int128Ty]] 64 0 0 0 |
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.
Just curious (potentially thinking about, what we might be missing): what happens with i126 scalars?
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.
Good question! Today it fails opaquely, with Unsupported integer width. With this patch it'd either pass if the required extension is present, or fail at module analysis with a slightly more informative message around needing to add the extension.
We should probably add the test under the extension itself, in a separate PR, that actually sweeps sizes (we have some of these elsewhere, they're needed for |
|
Hi @AlexVlx , https://lab.llvm.org/buildbot/#/builders/187/builds/14435 would yo take care of it? |
Yes, apologies for the inconvenience, I'll have a PR up in a few minutes, it was a bit sneaky. |
#171513 fixes it, will merge once checks complete. |
Adding support for i128 missed a few quirks of legalisation, which were masked previously by early erroring out on bitwidth > 64. i128 uses should be legal, we decide whether or not the resulting module is viable (i.e. if the required extensions are present) in the ModuleAnalysis pass.
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/129/builds/34692 Here is the relevant piece of the build log for the reference |
|
Hi @AlexVlx I noticed that if I build with gcc and -DLLVM_ENABLE_EXPENSIVE_CHECKS=ON many SPIRV lit tests fail with this patch. E.g. I guess it's this change that cause this |
@AlexVlx and then https://en.cppreference.com/w/cpp/named_req/Compare.html has the following requirement And with this patch we instead do so |
Thank you for the analysis. #171826 addresses this. |
LLVM has pretty thorough support for
int128, and it has started seeing some use. Even thouth we already have support for theSPV_ALTERA_arbitrary_precision_integersextension, the BE was oddly capping integer width to 64-bits. This patch adds partial support for lowering 128-bit integers toOpTypeInt 128. Some work remains to be done around legalisation support and validating constant uses (e.g. cases that get lowered toOpSpecConstantOp).