[clang] [llvm] [HLSL] implement elementwise firstbithigh hlsl builtin (PR #111082)
Farzon Lotfi via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 22 10:43:18 PDT 2024
================
@@ -2626,6 +2671,148 @@ Register SPIRVInstructionSelector::buildPointerToResource(
MIRBuilder);
}
+bool SPIRVInstructionSelector::selectFirstBitHigh16(Register ResVReg,
+ const SPIRVType *ResType,
+ MachineInstr &I,
+ bool IsSigned) const {
+ unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
+ // zero or sign extend
+ Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
+ bool Result =
+ selectUnOpWithSrc(ExtReg, ResType, I, I.getOperand(2).getReg(), Opcode);
+ return Result & selectFirstBitHigh32(ResVReg, ResType, I, ExtReg, IsSigned);
+}
+
+bool SPIRVInstructionSelector::selectFirstBitHigh32(Register ResVReg,
+ const SPIRVType *ResType,
+ MachineInstr &I,
+ Register SrcReg,
+ bool IsSigned) const {
+ unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb;
+ return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
+ .addImm(Opcode)
+ .addUse(SrcReg)
+ .constrainAllUses(TII, TRI, RBI);
+}
+
+bool SPIRVInstructionSelector::selectFirstBitHigh64(Register ResVReg,
+ const SPIRVType *ResType,
+ MachineInstr &I,
+ bool IsSigned) const {
+ Register OpReg = I.getOperand(2).getReg();
+ // 1. split our int64 into 2 pieces using a bitcast
+ unsigned count = GR.getScalarOrVectorComponentCount(ResType);
+ SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType);
+ MachineIRBuilder MIRBuilder(I);
+ SPIRVType *postCastT =
+ GR.getOrCreateSPIRVVectorType(baseType, 2 * count, MIRBuilder);
+ Register bitcastReg = MRI->createVirtualRegister(GR.getRegClass(postCastT));
+ bool Result =
+ selectUnOpWithSrc(bitcastReg, postCastT, I, OpReg, SPIRV::OpBitcast);
+
+ // 2. call firstbithigh
+ Register FBHReg = MRI->createVirtualRegister(GR.getRegClass(postCastT));
+ Result &= selectFirstBitHigh32(FBHReg, postCastT, I, bitcastReg, IsSigned);
+
+ // 3. check if result of each top 32 bits is == -1
+ // split result vector into vector of high bits and vector of low bits
+ // get high bits
+ // if ResType is a scalar we need a vector anyways because our code
+ // operates on vectors, even vectors of length one.
+ SPIRVType *VResType = ResType;
+ bool isScalarRes = ResType->getOpcode() != SPIRV::OpTypeVector;
+ if (isScalarRes)
+ VResType = GR.getOrCreateSPIRVVectorType(ResType, count, MIRBuilder);
+ // count should be one.
+
+ Register HighReg = MRI->createVirtualRegister(GR.getRegClass(VResType));
+ auto MIB =
+ BuildMI(*I.getParent(), I, I.getDebugLoc(),
+ TII.get(SPIRV::OpVectorShuffle))
+ .addDef(HighReg)
+ .addUse(GR.getSPIRVTypeID(VResType))
+ .addUse(FBHReg)
+ .addUse(
+ FBHReg); // this vector will not be selected from; could be empty
+ unsigned i;
+ for (i = 0; i < count * 2; i += 2) {
+ MIB.addImm(i);
+ }
+ Result &= MIB.constrainAllUses(TII, TRI, RBI);
+
+ // get low bits
+ Register LowReg = MRI->createVirtualRegister(GR.getRegClass(VResType));
+ MIB =
+ BuildMI(*I.getParent(), I, I.getDebugLoc(),
+ TII.get(SPIRV::OpVectorShuffle))
+ .addDef(LowReg)
+ .addUse(GR.getSPIRVTypeID(VResType))
+ .addUse(FBHReg)
+ .addUse(
+ FBHReg); // this vector will not be selected from; could be empty
+ for (i = 1; i < count * 2; i += 2) {
+ MIB.addImm(i);
+ }
+ Result &= MIB.constrainAllUses(TII, TRI, RBI);
+
+ SPIRVType *BoolType = GR.getOrCreateSPIRVVectorType(
+ GR.getOrCreateSPIRVBoolType(I, TII), count, MIRBuilder);
+ // check if the high bits are == -1;
+ Register NegOneReg = GR.getOrCreateConstVector(-1, I, VResType, TII);
+ // true if -1
+ Register BReg = MRI->createVirtualRegister(GR.getRegClass(BoolType));
+ Result &= selectNAryOpWithSrcs(BReg, BoolType, I, {HighReg, NegOneReg},
+ SPIRV::OpIEqual);
+
+ // Select low bits if true in BReg, otherwise high bits
+ Register TmpReg = MRI->createVirtualRegister(GR.getRegClass(VResType));
+ Result &= selectNAryOpWithSrcs(TmpReg, VResType, I, {BReg, LowReg, HighReg},
+ SPIRV::OpSelectVIVCond);
+
+ // Add 32 for high bits, 0 for low bits
+ Register ValReg = MRI->createVirtualRegister(GR.getRegClass(VResType));
+ bool ZeroAsNull = STI.isOpenCLEnv();
+ Register Reg32 = GR.getOrCreateConstVector(32, I, VResType, TII, ZeroAsNull);
+ Register Reg0 = GR.getOrCreateConstVector(0, I, VResType, TII, ZeroAsNull);
+ Result &= selectNAryOpWithSrcs(ValReg, VResType, I, {BReg, Reg0, Reg32},
+ SPIRV::OpSelectVIVCond);
+
+ Register AddReg = ResVReg;
+ if (isScalarRes)
+ AddReg = MRI->createVirtualRegister(GR.getRegClass(VResType));
+ Result &= selectNAryOpWithSrcs(AddReg, VResType, I, {ValReg, TmpReg},
----------------
farzonl wrote:
put a space here so it is clear result update isn't mean to be a part of the `if (isScalarRes)` block.
https://github.com/llvm/llvm-project/pull/111082
More information about the llvm-commits
mailing list