Skip to content

Commit 994c99b

Browse files
author
Alexander Johnston
committed
Wrap OpDPdx/yCoarse with OpFConvert where needed.
HLSL allows half types as arg and result to dd/y_coarse. This is not allowed in SPIRV, so to manage this we must detect these cases and wrap the OpDPd instructions in OpFConvert from half -> float -> half.
1 parent aba4b5b commit 994c99b

File tree

4 files changed

+76
-15
lines changed

4 files changed

+76
-15
lines changed

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
325325
MachineInstr &I) const;
326326
bool selectFrexp(Register ResVReg, const SPIRVType *ResType,
327327
MachineInstr &I) const;
328+
bool selectDpdCoarse(Register ResVReg, const SPIRVType *ResType,
329+
MachineInstr &I, const unsigned DPdOpCode) const;
328330
// Utilities
329331
std::pair<Register, bool>
330332
buildI32Constant(uint32_t Val, MachineInstr &I,
@@ -3099,6 +3101,59 @@ bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
30993101
return Result;
31003102
}
31013103

3104+
bool SPIRVInstructionSelector::selectDpdCoarse(Register ResVReg,
3105+
const SPIRVType *ResType,
3106+
MachineInstr &I,
3107+
const unsigned DPdOpCode) const {
3108+
// If the arg/result types are half then we need to wrap the instr in
3109+
// conversions to float
3110+
// This case occurs because a half arg/result is legal in HLSL but not spirv.
3111+
Register SrcReg = I.getOperand(2).getReg();
3112+
SPIRVType *SrcType = GR.getSPIRVTypeForVReg(SrcReg);
3113+
unsigned BitWidth = std::min(GR.getScalarOrVectorBitWidth(SrcType),
3114+
GR.getScalarOrVectorBitWidth(ResType));
3115+
if (BitWidth == 32) {
3116+
return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
3117+
.addDef(ResVReg)
3118+
.addUse(GR.getSPIRVTypeID(ResType))
3119+
.addUse(I.getOperand(2).getReg());
3120+
} else {
3121+
MachineIRBuilder MIRBuilder(I);
3122+
unsigned componentCount = GR.getScalarOrVectorComponentCount(SrcType);
3123+
SPIRVType *Float32Ty = GR.getOrCreateSPIRVFloatType(32, I, TII);
3124+
SPIRVType *F32ConvertTy;
3125+
if (componentCount == 1) {
3126+
F32ConvertTy = Float32Ty;
3127+
} else {
3128+
F32ConvertTy = GR.getOrCreateSPIRVVectorType(Float32Ty, componentCount,
3129+
MIRBuilder, false);
3130+
}
3131+
3132+
const TargetRegisterClass *RegClass = GR.getRegClass(SrcType);
3133+
Register ConvertToVReg = MRI->createVirtualRegister(RegClass);
3134+
Register DpdOpVReg = MRI->createVirtualRegister(RegClass);
3135+
3136+
bool Result =
3137+
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
3138+
.addDef(ConvertToVReg)
3139+
.addUse(GR.getSPIRVTypeID(F32ConvertTy))
3140+
.addUse(SrcReg)
3141+
.constrainAllUses(TII, TRI, RBI);
3142+
Result &= BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
3143+
.addDef(DpdOpVReg)
3144+
.addUse(GR.getSPIRVTypeID(F32ConvertTy))
3145+
.addUse(ConvertToVReg)
3146+
.constrainAllUses(TII, TRI, RBI);
3147+
Result &=
3148+
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
3149+
.addDef(ResVReg)
3150+
.addUse(GR.getSPIRVTypeID(ResType))
3151+
.addUse(DpdOpVReg)
3152+
.constrainAllUses(TII, TRI, RBI);
3153+
return Result;
3154+
}
3155+
}
3156+
31023157
bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
31033158
const SPIRVType *ResType,
31043159
MachineInstr &I) const {
@@ -3473,18 +3528,10 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
34733528
return selectResourceNonUniformIndex(ResVReg, ResType, I);
34743529
}
34753530
case Intrinsic::spv_ddx_coarse: {
3476-
return BuildMI(*I.getParent(), I, I.getDebugLoc(),
3477-
TII.get(SPIRV::OpDPdxCoarse))
3478-
.addDef(ResVReg)
3479-
.addUse(GR.getSPIRVTypeID(ResType))
3480-
.addUse(I.getOperand(2).getReg());
3531+
return selectDpdCoarse(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
34813532
}
34823533
case Intrinsic::spv_ddy_coarse: {
3483-
return BuildMI(*I.getParent(), I, I.getDebugLoc(),
3484-
TII.get(SPIRV::OpDPdyCoarse))
3485-
.addDef(ResVReg)
3486-
.addUse(GR.getSPIRVTypeID(ResType))
3487-
.addUse(I.getOperand(2).getReg());
3534+
return selectDpdCoarse(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
34883535
}
34893536
default: {
34903537
std::string DiagMsg;

llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,8 @@ void RequirementHandler::initAvailableCapabilitiesForVulkan(
934934
Capability::UniformBufferArrayDynamicIndexing,
935935
Capability::SampledImageArrayDynamicIndexing,
936936
Capability::StorageBufferArrayDynamicIndexing,
937-
Capability::StorageImageArrayDynamicIndexing});
937+
Capability::StorageImageArrayDynamicIndexing,
938+
Capability::DerivativeControl});
938939

939940
// Became core in Vulkan 1.2
940941
if (ST.isAtLeastSPIRVVer(VersionTuple(1, 5))) {
@@ -2061,6 +2062,11 @@ void addInstrRequirements(const MachineInstr &MI,
20612062
Reqs.addCapability(SPIRV::Capability::PredicatedIOINTEL);
20622063
break;
20632064
}
2065+
case SPIRV::OpDPdxCoarse:
2066+
case SPIRV::OpDPdyCoarse: {
2067+
Reqs.addCapability(SPIRV::Capability::DerivativeControl);
2068+
break;
2069+
}
20642070

20652071
default:
20662072
break;

llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddx_coarse.ll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ entry:
1818
define noundef half @ddx_coarse_half(half noundef %a) {
1919
entry:
2020
; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
21-
; CHECK: %[[#]] = OpDPdxCoarse %[[#float_16]] %[[#float_16_arg]]
21+
; CHECK: %[[#converted:]] = OpFConvert %[[#float_32:]] %[[#float_16_arg]]
22+
; CHECK: %[[#coarse:]] = OpDPdxCoarse %[[#float_32]] %[[#converted]]
23+
; CHECK: %[[#]] = OpFConvert %[[#float_16]] %[[#coarse]]
2224
%elt.ddx.coarse = call half @llvm.spv.ddx.coarse.f16(half %a)
2325
ret half %elt.ddx.coarse
2426
}
@@ -34,7 +36,9 @@ entry:
3436
define noundef <4 x half> @ddx_coarse_half_vector(<4 x half> noundef %a) {
3537
entry:
3638
; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
37-
; CHECK: %[[#]] = OpDPdxCoarse %[[#vec4_float_16]] %[[#vec4_float_16_arg]]
39+
; CHECK: %[[#converted:]] = OpFConvert %[[#vec4_float_32:]] %[[#vec4_float_16_arg]]
40+
; CHECK: %[[#coarse:]] = OpDPdxCoarse %[[#vec4_float_32]] %[[#converted]]
41+
; CHECK: %[[#]] = OpFConvert %[[#vec4_float_16]] %[[#coarse]]
3842
%elt.ddx.coarse = call <4 x half> @llvm.spv.ddx.coarse.v4f16(<4 x half> %a)
3943
ret <4 x half> %elt.ddx.coarse
4044
}

llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddy_coarse.ll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ entry:
1818
define noundef half @ddy_coarse_half(half noundef %a) {
1919
entry:
2020
; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
21-
; CHECK: %[[#]] = OpDPdyCoarse %[[#float_16]] %[[#float_16_arg]]
21+
; CHECK: %[[#converted:]] = OpFConvert %[[#float_32:]] %[[#float_16_arg]]
22+
; CHECK: %[[#coarse:]] = OpDPdyCoarse %[[#float_32]] %[[#converted]]
23+
; CHECK: %[[#]] = OpFConvert %[[#float_16]] %[[#coarse]]
2224
%elt.ddy.coarse = call half @llvm.spv.ddy.coarse.f16(half %a)
2325
ret half %elt.ddy.coarse
2426
}
@@ -34,7 +36,9 @@ entry:
3436
define noundef <4 x half> @ddy_coarse_half_vector(<4 x half> noundef %a) {
3537
entry:
3638
; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
37-
; CHECK: %[[#]] = OpDPdyCoarse %[[#vec4_float_16]] %[[#vec4_float_16_arg]]
39+
; CHECK: %[[#converted:]] = OpFConvert %[[#vec4_float_32:]] %[[#vec4_float_16_arg]]
40+
; CHECK: %[[#coarse:]] = OpDPdyCoarse %[[#vec4_float_32]] %[[#converted]]
41+
; CHECK: %[[#]] = OpFConvert %[[#vec4_float_16]] %[[#coarse]]
3842
%elt.ddy.coarse = call <4 x half> @llvm.spv.ddy.coarse.v4f16(<4 x half> %a)
3943
ret <4 x half> %elt.ddy.coarse
4044
}

0 commit comments

Comments
 (0)