diff --git a/lgc/builder/ArithBuilder.cpp b/lgc/builder/ArithBuilder.cpp index 6e63f5f57c..9f412825e5 100644 --- a/lgc/builder/ArithBuilder.cpp +++ b/lgc/builder/ArithBuilder.cpp @@ -236,8 +236,7 @@ Value *BuilderImpl::CreateSMod(Value *dividend, Value *divisor, const Twine &ins } // ===================================================================================================================== -// Create FP modulo operation, where the sign of the result (if not zero) is the same as the sign -// of the divisor. +// Create FP modulo operation, where the sign of the result is the same as the sign of the divisor. // // @param dividend : Dividend value // @param divisor : Divisor value @@ -248,6 +247,28 @@ Value *BuilderImpl::CreateFMod(Value *dividend, Value *divisor, const Twine &ins return CreateFSub(dividend, CreateFMul(divisor, floor), instName); } +// ===================================================================================================================== +// Create FP modulo operation, where the sign of the result is the same as the sign of the dividend. +// +// @param dividend : Dividend value +// @param divisor : Divisor value +// @param instName : Name to give instruction(s) +Value *BuilderImpl::CreateFRem(Value *dividend, Value *divisor, const Twine &instName) { + Value *result = IRBuilder::CreateFRem(dividend, divisor); + if (!getFastMathFlags().noSignedZeros()) { + // NOTE: If the fast math flags might have signed zeros, we should check the special case when dividend is signed + // zero. According to SPIR-V spec, the result of FRem must have the same sign of the dividend but we lower FRem to + // this: frem(x, y) = x - y * trunc(x/y). When x=-0.0, we get an addition of (-0.0) + 0.0. HW returns +0.0 rather + // than -0.0, which violates the spec expectation. + Value *zero = Constant::getNullValue(divisor->getType()); + Value *isZero = CreateFCmpOEQ(dividend, zero); + result = canonicalize(CreateSelect(isZero, dividend, result)); // Ensure we flush denorms as expected + } + + result->setName(instName); + return result; +} + // ===================================================================================================================== // Create scalar/vector float/half fused multiply-and-add, to compute a * b + c // diff --git a/lgc/builder/BuilderRecorder.cpp b/lgc/builder/BuilderRecorder.cpp index f954ff787e..6f0b0900aa 100644 --- a/lgc/builder/BuilderRecorder.cpp +++ b/lgc/builder/BuilderRecorder.cpp @@ -82,6 +82,8 @@ StringRef BuilderRecorder::getCallName(BuilderOpcode opcode) { return "smod"; case BuilderOpcode::FMod: return "fmod"; + case BuilderOpcode::FRem: + return "frem"; case BuilderOpcode::Fma: return "fma"; case BuilderOpcode::Tan: @@ -846,8 +848,7 @@ Value *Builder::CreateSMod(Value *dividend, Value *divisor, const Twine &instNam } // ===================================================================================================================== -// Create FP modulo operation, where the sign of the result (if not zero) is the same as the sign -// of the divisor. +// Create FP modulo operation, where the sign of the result is the same as the sign of the divisor. // // @param dividend : Dividend value // @param divisor : Divisor value @@ -856,6 +857,16 @@ Value *Builder::CreateFMod(Value *dividend, Value *divisor, const Twine &instNam return record(BuilderOpcode::FMod, dividend->getType(), {dividend, divisor}, instName); } +// ===================================================================================================================== +// Create FP modulo operation, where the sign of the result is the same as the sign of the dividend. +// +// @param dividend : Dividend value +// @param divisor : Divisor value +// @param instName : Name to give instruction(s) +Value *Builder::CreateFRem(Value *dividend, Value *divisor, const Twine &instName) { + return record(BuilderOpcode::FRem, dividend->getType(), {dividend, divisor}, instName); +} + // ===================================================================================================================== // Create scalar/vector float/half fused multiply-and-add, to compute a * b + c // @@ -2012,6 +2023,7 @@ Instruction *Builder::record(BuilderOpcode opcode, Type *resultTy, ArrayRefCreateFMod(args[0], args[1]); } + case BuilderOpcode::FRem: { + return m_builder->CreateFRem(args[0], args[1]); + } + case BuilderOpcode::Fma: { return m_builder->CreateFma(args[0], args[1], args[2]); } diff --git a/lgc/include/lgc/builder/BuilderImpl.h b/lgc/include/lgc/builder/BuilderImpl.h index 311d7016c0..9e9cb97f3f 100644 --- a/lgc/include/lgc/builder/BuilderImpl.h +++ b/lgc/include/lgc/builder/BuilderImpl.h @@ -155,6 +155,7 @@ class BuilderImpl : public BuilderDefs { // Create signed integer or FP modulo operation. llvm::Value *CreateSMod(llvm::Value *dividend, llvm::Value *divisor, const llvm::Twine &instName = ""); llvm::Value *CreateFMod(llvm::Value *dividend, llvm::Value *divisor, const llvm::Twine &instName = ""); + llvm::Value *CreateFRem(llvm::Value *dividend, llvm::Value *divisor, const llvm::Twine &instName = ""); // Create scalar/vector float/half fused multiply-and-add, to compute a * b + c llvm::Value *CreateFma(llvm::Value *a, llvm::Value *b, llvm::Value *c, const llvm::Twine &instName = ""); diff --git a/lgc/interface/lgc/Builder.h b/lgc/interface/lgc/Builder.h index 77c8ec571f..8ea1db8f1b 100644 --- a/lgc/interface/lgc/Builder.h +++ b/lgc/interface/lgc/Builder.h @@ -485,14 +485,22 @@ class Builder : public BuilderDefs { // @param instName : Name to give instruction(s) llvm::Value *CreateSMod(llvm::Value *dividend, llvm::Value *divisor, const llvm::Twine &instName = ""); - // Create FP modulo operation, where the sign of the result (if not zero) is the same as - // the sign of the divisor. The result is undefined if divisor is zero. + // Create FP modulo operation, where the sign of the result is the same as the sign of the divisor. The result + // is undefined if divisor is zero. // // @param dividend : Dividend value // @param divisor : Divisor value // @param instName : Name to give instruction(s) llvm::Value *CreateFMod(llvm::Value *dividend, llvm::Value *divisor, const llvm::Twine &instName = ""); + // Create FP modulo operation, where the sign of the result is the same as the sign of the dividend. The result + // is undefined if divisor is zero. + // + // @param dividend : Dividend value + // @param divisor : Divisor value + // @param instName : Name to give instruction(s) + llvm::Value *CreateFRem(llvm::Value *dividend, llvm::Value *divisor, const llvm::Twine &instName = ""); + // Create scalar/vector float/half fused multiply-and-add, to compute a * b + c // // @param a : One value to multiply diff --git a/llpc/translator/lib/SPIRV/SPIRVReader.cpp b/llpc/translator/lib/SPIRV/SPIRVReader.cpp index 2a604639c8..12f2c604d0 100644 --- a/llpc/translator/lib/SPIRV/SPIRVReader.cpp +++ b/llpc/translator/lib/SPIRV/SPIRVReader.cpp @@ -5361,6 +5361,12 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *bv, Function *f, Bas Value *val1 = transValue(bc->getDivisor(), f, bb); return mapValue(bc, getBuilder()->CreateFMod(val0, val1)); } + case OpFRem: { + SPIRVBinary *bc = static_cast(bv); + Value *val0 = transValue(bc->getOperand(0), f, bb); + Value *val1 = transValue(bc->getOperand(1), f, bb); + return mapValue(bc, getBuilder()->CreateFRem(val0, val1)); + } case OpFNegate: { SPIRVUnary *bc = static_cast(bv); Value *val0 = transValue(bc->getOperand(0), f, bb);