Skip to content

Conversation

@HolyMolyCowMan
Copy link
Contributor

This commit adds the intrinsic G_FMODF to GMIR & enables its translation, legalization and instruction selection in AArch64.

@llvmbot
Copy link
Member

llvmbot commented Sep 22, 2025

@llvm/pr-subscribers-backend-spir-v
@llvm/pr-subscribers-backend-risc-v
@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-llvm-support

@llvm/pr-subscribers-llvm-globalisel

Author: Ryan Cowan (HolyMolyCowMan)

Changes

This commit adds the intrinsic G_FMODF to GMIR & enables its translation, legalization and instruction selection in AArch64.


Patch is 48.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/160061.diff

14 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h (+5)
  • (modified) llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h (+7)
  • (modified) llvm/include/llvm/Support/TargetOpcodes.def (+3)
  • (modified) llvm/include/llvm/Target/GenericOpcodes.td (+7)
  • (modified) llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp (+7)
  • (modified) llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (+71)
  • (modified) llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp (+2-1)
  • (added) llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-modf.ll (+140)
  • (added) llvm/test/CodeGen/AArch64/GlobalISel/legalize-modf.mir (+206)
  • (modified) llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir (+4)
  • (added) llvm/test/CodeGen/AArch64/GlobalISel/select-modf.mir (+136)
  • (modified) llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td (+66-66)
  • (modified) llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td (+1-1)
  • (modified) llvm/test/TableGen/RegClassByHwMode.td (+1-1)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h index 22569aab236af..818fbc60bcf0f 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -300,6 +300,11 @@ class LegalizerHelper { Type *OpType, LostDebugLocObserver &LocObserver); + LegalizeResult emitModfLibcall(MachineInstr &MI, + MachineIRBuilder &MIRBuilder, unsigned Size, + Type *OpType, + LostDebugLocObserver &LocObserver); + public: /// Return the alignment to use for a stack temporary object with the given /// type. diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index 99d3cd0aac85c..6f48c2afef93d 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -2184,6 +2184,13 @@ class LLVM_ABI MachineIRBuilder { return buildInstr(TargetOpcode::G_FSINCOS, {Sin, Cos}, {Src}, Flags); } + /// Build and insert \p Fract, \p Int = G_FMODF \p Src + MachineInstrBuilder + buildModf(const DstOp &Fract, const DstOp &Int, const SrcOp &Src, + std::optional<unsigned> Flags = std::nullopt) { + return buildInstr(TargetOpcode::G_FMODF, {Fract, Int}, {Src}, Flags); + } + /// Build and insert \p Res = G_FCOPYSIGN \p Op0, \p Op1 MachineInstrBuilder buildFCopysign(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1) { diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index b905576b61791..5372ba4800d18 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -650,6 +650,9 @@ HANDLE_TARGET_OPCODE(G_FDIV) /// Generic FP remainder. HANDLE_TARGET_OPCODE(G_FREM) +/// Generic FP modulus and remainder +HANDLE_TARGET_OPCODE(G_FMODF) + /// Generic FP exponentiation. HANDLE_TARGET_OPCODE(G_FPOW) diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index ce4750db88c9a..2a8ef4cf80993 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -981,6 +981,13 @@ def G_FREM : GenericInstruction { let hasSideEffects = false; } +/// Generic FP modulus and remainder +def G_FMODF : GenericInstruction { + let OutOperandList = (outs type0:$dst1, type0:$dst2); + let InOperandList = (ins type0:$src1); + let hasSideEffects = false; +} + // Floating point exponentiation. def G_FPOW : GenericInstruction { let OutOperandList = (outs type0:$dst); diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 768e3713f78e2..17e7a00544b9f 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -2362,6 +2362,13 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, MachineInstr::copyFlagsFromInstruction(CI)); return true; } + case Intrinsic::modf: { + ArrayRef<Register> VRegs = getOrCreateVRegs(CI); + MIRBuilder.buildModf(VRegs[0], VRegs[1], + getOrCreateVReg(*CI.getArgOperand(0)), + MachineInstr::copyFlagsFromInstruction(CI)); + return true; + } case Intrinsic::sincos: { ArrayRef<Register> VRegs = getOrCreateVRegs(CI); MIRBuilder.buildFSincos(VRegs[0], VRegs[1], diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index f3e036ed1b947..26f2b85bcc24b 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -471,6 +471,8 @@ static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) { RTLIBCASE(TANH_F); case TargetOpcode::G_FSINCOS: RTLIBCASE(SINCOS_F); + case TargetOpcode::G_FMODF: + RTLIBCASE(MODF_F); case TargetOpcode::G_FLOG10: RTLIBCASE(LOG10_F); case TargetOpcode::G_FLOG: @@ -702,6 +704,47 @@ LegalizerHelper::LegalizeResult LegalizerHelper::emitSincosLibcall( return LegalizerHelper::Legalized; } +LegalizerHelper::LegalizeResult LegalizerHelper::emitModfLibcall( + MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType, + LostDebugLocObserver &LocObserver) { + MachineFunction &MF = *MI.getMF(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + + Register DstFrac = MI.getOperand(0).getReg(); + Register DstInt = MI.getOperand(1).getReg(); + Register Src = MI.getOperand(2).getReg(); + LLT DstTy = MRI.getType(DstFrac); + + int MemSize = DstTy.getSizeInBytes(); + Align Alignment = getStackTemporaryAlignment(DstTy); + const DataLayout &DL = MIRBuilder.getDataLayout(); + unsigned AddrSpace = DL.getAllocaAddrSpace(); + MachinePointerInfo PtrInfo; + + Register StackPtrInt = + createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo) + .getReg(0); + + auto &Ctx = MF.getFunction().getContext(); + auto LibcallResult = + createLibcall(MIRBuilder, getRTLibDesc(MI.getOpcode(), Size), + {DstFrac, OpType, 0}, + {{Src, OpType, 0}, + {StackPtrInt, PointerType::get(Ctx, AddrSpace), 1}}, + LocObserver, &MI); + + if (LibcallResult != LegalizeResult::Legalized) + return LegalizerHelper::UnableToLegalize; + + MachineMemOperand *LoadMMOInt = MF.getMachineMemOperand( + PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment); + + MIRBuilder.buildLoad(DstInt, StackPtrInt, *LoadMMOInt); + MI.eraseFromParent(); + + return LegalizerHelper::Legalized; +} + LegalizerHelper::LegalizeResult llvm::createMemLibcall(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, MachineInstr &MI, LostDebugLocObserver &LocObserver) { @@ -1341,6 +1384,16 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) { } return emitSincosLibcall(MI, MIRBuilder, Size, HLTy, LocObserver); } + case TargetOpcode::G_FMODF: { + LLT LLTy = MRI.getType(MI.getOperand(0).getReg()); + unsigned Size = LLTy.getSizeInBits(); + Type *HLTy = getFloatTypeForLLT(Ctx, LLTy); + if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) { + LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n"); + return UnableToLegalize; + } + return emitModfLibcall(MI, MIRBuilder, Size, HLTy, LocObserver); + } case TargetOpcode::G_LROUND: case TargetOpcode::G_LLROUND: case TargetOpcode::G_INTRINSIC_LRINT: @@ -3331,6 +3384,23 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC); Observer.changedInstr(MI); return Legalized; + case TargetOpcode::G_FMODF: { + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT); +  + Register DstFrac = MI.getOperand(0).getReg(); + Register DstInt = MI.getOperand(1).getReg(); + + Register DstFracWide = MRI.createGenericVirtualRegister(WideTy); + Register DstIntWide = MRI.createGenericVirtualRegister(WideTy); + Register SrcWide = MI.getOperand(2).getReg(); +  + MIRBuilder.buildInstr(TargetOpcode::G_FMODF, {DstFracWide, DstIntWide}, {SrcWide}); +  + MIRBuilder.buildFPTrunc(DstFrac, DstFracWide); + MIRBuilder.buildFPTrunc(DstInt, DstIntWide); + MI.eraseFromParent(); + return Legalized; + } case TargetOpcode::G_FPOWI: case TargetOpcode::G_FLDEXP: case TargetOpcode::G_STRICT_FLDEXP: { @@ -5470,6 +5540,7 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, case G_LROUND: case G_LLROUND: case G_INTRINSIC_TRUNC: + case G_FMODF: case G_FCOS: case G_FSIN: case G_FTAN: diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp index ea2196a584127..7c0b8302da1c2 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp @@ -438,12 +438,13 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) getActionDefinitionsBuilder({G_FCOS, G_FSIN, G_FPOW, G_FLOG, G_FLOG2, G_FLOG10, G_FTAN, G_FEXP, G_FEXP2, G_FEXP10, G_FACOS, G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, - G_FSINH, G_FTANH}) + G_FSINH, G_FTANH, G_FMODF}) // We need a call for these, so we always need to scalarize. .scalarize(0) // Regardless of FP16 support, widen 16-bit elements to 32-bits. .minScalar(0, s32) .libcallFor({s32, s64, s128}); + getActionDefinitionsBuilder(G_FPOWI) .scalarize(0) .minScalar(0, s32) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-modf.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-modf.ll new file mode 100644 index 0000000000000..b4ab099e6ac4f --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-modf.ll @@ -0,0 +1,140 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -O0 -mtriple=aarch64-linux-gnu -global-isel -stop-after=irtranslator %s -o - | FileCheck %s + +define { half, half } @test_modf_f16(half %a) { + ; CHECK-LABEL: name: test_modf_f16 + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $h0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s16) = COPY $h0 + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(s16), [[FMODF1:%[0-9]+]]:_ = G_FMODF [[COPY]] + ; CHECK-NEXT: $h0 = COPY [[FMODF]](s16) + ; CHECK-NEXT: $h1 = COPY [[FMODF1]](s16) + ; CHECK-NEXT: RET_ReallyLR implicit $h0, implicit $h1 + %result = call { half, half } @llvm.modf.f16(half %a) + ret { half, half } %result +} + +define { <2 x half>, <2 x half> } @test_modf_v2f16(<2 x half> %a) { + ; CHECK-LABEL: name: test_modf_v2f16 + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $d0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x s16>) = COPY $d0 + ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[COPY]](<4 x s16>) + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(<2 x s16>), [[FMODF1:%[0-9]+]]:_ = G_FMODF [[UV]] + ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(s16), [[UV3:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[FMODF]](<2 x s16>) + ; CHECK-NEXT: [[DEF:%[0-9]+]]:_(s16) = G_IMPLICIT_DEF + ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s16>) = G_BUILD_VECTOR [[UV2]](s16), [[UV3]](s16), [[DEF]](s16), [[DEF]](s16) + ; CHECK-NEXT: [[UV4:%[0-9]+]]:_(s16), [[UV5:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[FMODF1]](<2 x s16>) + ; CHECK-NEXT: [[BUILD_VECTOR1:%[0-9]+]]:_(<4 x s16>) = G_BUILD_VECTOR [[UV4]](s16), [[UV5]](s16), [[DEF]](s16), [[DEF]](s16) + ; CHECK-NEXT: $d0 = COPY [[BUILD_VECTOR]](<4 x s16>) + ; CHECK-NEXT: $d1 = COPY [[BUILD_VECTOR1]](<4 x s16>) + ; CHECK-NEXT: RET_ReallyLR implicit $d0, implicit $d1 + %result = call { <2 x half>, <2 x half> } @llvm.modf.v2f16(<2 x half> %a) + ret { <2 x half>, <2 x half> } %result +} + +define { float, float } @test_modf_f32(float %a) { + ; CHECK-LABEL: name: test_modf_f32 + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $s0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(s32), [[FMODF1:%[0-9]+]]:_ = G_FMODF [[COPY]] + ; CHECK-NEXT: $s0 = COPY [[FMODF]](s32) + ; CHECK-NEXT: $s1 = COPY [[FMODF1]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0, implicit $s1 + %result = call { float, float } @llvm.modf.f32(float %a) + ret { float, float } %result +} + +define { <2 x float>, <2 x float> } @test_modf_v2f32(<2 x float> %a) { + ; CHECK-LABEL: name: test_modf_v2f32 + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $d0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<2 x s32>) = COPY $d0 + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(<2 x s32>), [[FMODF1:%[0-9]+]]:_ = G_FMODF [[COPY]] + ; CHECK-NEXT: $d0 = COPY [[FMODF]](<2 x s32>) + ; CHECK-NEXT: $d1 = COPY [[FMODF1]](<2 x s32>) + ; CHECK-NEXT: RET_ReallyLR implicit $d0, implicit $d1 + %result = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> %a) + ret { <2 x float>, <2 x float> } %result +} + +define { double, double } @test_modf_f64(double %a) { + ; CHECK-LABEL: name: test_modf_f64 + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $d0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $d0 + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(s64), [[FMODF1:%[0-9]+]]:_ = G_FMODF [[COPY]] + ; CHECK-NEXT: $d0 = COPY [[FMODF]](s64) + ; CHECK-NEXT: $d1 = COPY [[FMODF1]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $d0, implicit $d1 + %result = call { double, double } @llvm.modf.f64(double %a) + ret { double, double } %result +} + +define { <2 x double>, <2 x double> } @test_modf_v2f64(<2 x double> %a) { + ; CHECK-LABEL: name: test_modf_v2f64 + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $q0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<2 x s64>) = COPY $q0 + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(<2 x s64>), [[FMODF1:%[0-9]+]]:_ = G_FMODF [[COPY]] + ; CHECK-NEXT: $q0 = COPY [[FMODF]](<2 x s64>) + ; CHECK-NEXT: $q1 = COPY [[FMODF1]](<2 x s64>) + ; CHECK-NEXT: RET_ReallyLR implicit $q0, implicit $q1 + %result = call { <2 x double>, <2 x double> } @llvm.modf.v2f64(<2 x double> %a) + ret { <2 x double>, <2 x double> } %result +} + +define { fp128, fp128 } @test_modf_fp128(fp128 %a) { + ; CHECK-LABEL: name: test_modf_fp128 + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $q0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s128) = COPY $q0 + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(s128), [[FMODF1:%[0-9]+]]:_ = G_FMODF [[COPY]] + ; CHECK-NEXT: $q0 = COPY [[FMODF]](s128) + ; CHECK-NEXT: $q1 = COPY [[FMODF1]](s128) + ; CHECK-NEXT: RET_ReallyLR implicit $q0, implicit $q1 + %result = call { fp128, fp128 } @llvm.modf.fp128(fp128 %a) + ret { fp128, fp128 } %result +} + +define { <2 x fp128>, <2 x fp128> } @test_modf_v2fp128(<2 x fp128> %a) { + ; CHECK-LABEL: name: test_modf_v2fp128 + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $q0, $q1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s128) = COPY $q0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s128) = COPY $q1 + ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x s128>) = G_BUILD_VECTOR [[COPY]](s128), [[COPY1]](s128) + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(<2 x s128>), [[FMODF1:%[0-9]+]]:_ = G_FMODF [[BUILD_VECTOR]] + ; CHECK-NEXT: [[UV:%[0-9]+]]:_(s128), [[UV1:%[0-9]+]]:_(s128) = G_UNMERGE_VALUES [[FMODF]](<2 x s128>) + ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(s128), [[UV3:%[0-9]+]]:_(s128) = G_UNMERGE_VALUES [[FMODF1]](<2 x s128>) + ; CHECK-NEXT: $q0 = COPY [[UV]](s128) + ; CHECK-NEXT: $q1 = COPY [[UV1]](s128) + ; CHECK-NEXT: $q2 = COPY [[UV2]](s128) + ; CHECK-NEXT: $q3 = COPY [[UV3]](s128) + ; CHECK-NEXT: RET_ReallyLR implicit $q0, implicit $q1, implicit $q2, implicit $q3 + %result = call { <2 x fp128>, <2 x fp128> } @llvm.modf.v2fp128(<2 x fp128> %a) + ret { <2 x fp128>, <2 x fp128> } %result +} + +define { float, float } @test_modf_f32_afn(float %a) { + ; CHECK-LABEL: name: test_modf_f32_afn + ; CHECK: bb.1 (%ir-block.0): + ; CHECK-NEXT: liveins: $s0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK-NEXT: [[FMODF:%[0-9]+]]:_(s32), [[FMODF1:%[0-9]+]]:_ = afn G_FMODF [[COPY]] + ; CHECK-NEXT: $s0 = COPY [[FMODF]](s32) + ; CHECK-NEXT: $s1 = COPY [[FMODF1]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0, implicit $s1 + %result = call afn { float, float } @llvm.modf.f32(float %a) + ret { float, float } %result +} diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-modf.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-modf.mir new file mode 100644 index 0000000000000..5d0d94ed2a274 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-modf.mir @@ -0,0 +1,206 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6 +# RUN: llc -mtriple=aarch64 -run-pass=legalizer %s -o - | FileCheck %s +--- +name: test_modf_f16 +body: | + bb.0.entry: + ; CHECK-LABEL: name: test_modf_f16 + ; CHECK: [[COPY:%[0-9]+]]:_(s16) = COPY $h0 + ; CHECK-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = G_FPEXT [[COPY]](s16) + ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0 + ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: $s0 = COPY [[FPEXT]](s32) + ; CHECK-NEXT: $x0 = COPY [[FRAME_INDEX]](p0) + ; CHECK-NEXT: BL &modff, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $s0, implicit $x0, implicit-def $s0 + ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %stack.0) + ; CHECK-NEXT: [[FPTRUNC:%[0-9]+]]:_(s16) = G_FPTRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[FPTRUNC1:%[0-9]+]]:_(s16) = G_FPTRUNC [[LOAD]](s32) + ; CHECK-NEXT: $h0 = COPY [[FPTRUNC]](s16) + ; CHECK-NEXT: $h1 = COPY [[FPTRUNC1]](s16) + ; CHECK-NEXT: RET_ReallyLR implicit $h0, implicit $h1 + %0:_(s16) = COPY $h0 + %1:_(s16), %2:_(s16) = G_FMODF %0 + $h0 = COPY %1(s16) + $h1 = COPY %2(s16) + RET_ReallyLR implicit $h0, implicit $h1 +... +--- +name: test_modf_f16_only_use_fractional_part +body: | + bb.0.entry: + ; CHECK-LABEL: name: test_modf_f16_only_use_fractional_part + ; CHECK: [[COPY:%[0-9]+]]:_(s16) = COPY $h0 + ; CHECK-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = G_FPEXT [[COPY]](s16) + ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0 + ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: $s0 = COPY [[FPEXT]](s32) + ; CHECK-NEXT: $x0 = COPY [[FRAME_INDEX]](p0) + ; CHECK-NEXT: BL &modff, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $s0, implicit $x0, implicit-def $s0 + ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK-NEXT: [[FPTRUNC:%[0-9]+]]:_(s16) = G_FPTRUNC [[COPY1]](s32) + ; CHECK-NEXT: $h0 = COPY [[FPTRUNC]](s16) + ; CHECK-NEXT: RET_ReallyLR implicit $h0 + %0:_(s16) = COPY $h0 + %1:_(s16), %2:_(s16) = G_FMODF %0 + $h0 = COPY %1(s16) + RET_ReallyLR implicit $h0 +... +--- +name: test_modf_v2f16 +body: | + bb.0.entry: + ; CHECK-LABEL: name: test_modf_v2f16 + ; CHECK: [[COPY:%[0-9]+]]:_(<4 x s16>) = COPY $d0 + ; CHECK-NEXT: [[UV:%[0-9]+]]:_(s16), [[UV1:%[0-9]+]]:_(s16), [[UV2:%[0-9]+]]:_(s16), [[UV3:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[COPY]](<4 x s16>) + ; CHECK-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = G_FPEXT [[UV]](s16) + ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1 + ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: $s0 = COPY [[FPEXT]](s32) + ; CHECK-NEXT: $x0 = COPY [[FRAME_INDEX]](p0) + ; CHECK-NEXT: BL &modff, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $s0, implicit $x0, implicit-def $s0 + ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %stack.1) + ; CHECK-NEXT: [[FPTRUNC:%[0-9]+]]:_(s16) = G_FPTRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[FPTRUNC1:%[0-9]+]]:_(s16) = G_FPTRUNC [[LOAD]](s32) + ; CHECK-NEXT: [[FPEXT1:%[0-9]+]]:_(s32) = G_FPEXT [[UV1]](s16) + ; CHECK-NEXT: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0 + ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: $s0 = COPY [[FPEXT1]](s32) + ; CHECK-NEXT: $x0 = COPY [[FRAME_INDEX1]](p0) + ; CHECK-NEXT: BL &modff, csr_aarch64_aa... [truncated] 
@github-actions
Copy link

github-actions bot commented Sep 22, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@HolyMolyCowMan HolyMolyCowMan marked this pull request as draft September 22, 2025 10:26
@arsenm arsenm changed the title [AArch64][GlobalISel] Add G_FMODF intrinsic [AArch64][GlobalISel] Add G_FMODF instruction Sep 22, 2025
@HolyMolyCowMan HolyMolyCowMan force-pushed the implement-g-modf branch 2 times, most recently from 9284ab8 to ead0af9 Compare September 23, 2025 12:32
@HolyMolyCowMan HolyMolyCowMan marked this pull request as ready for review September 23, 2025 14:22
@HolyMolyCowMan
Copy link
Contributor Author

I've checked the failing SPIR-V test, and all runs of this test have been failing since the 15th of September.

Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a global-isel run line for the tests in llvm/test/CodeGen/AArch64/llvm.modf.ll too? It will help test them end-to-end and see how the codegen compares to SDAG.

@HolyMolyCowMan
Copy link
Contributor Author

I've added this line and updated the tests. Thank you.

Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, providing that the failing CodeGen/SPIRV/instructions/integer-casts.ll test is being fixed in #158086.

Copy link
Contributor

@maarquitos14 maarquitos14 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SPIR-V part looks good to me. Just wondering if now the old call to selectModf from

should be removed because it becomes dead?

@HolyMolyCowMan
Copy link
Contributor Author

Yes, good catch. I've removed that call now, thank you.

@davemgreen davemgreen merged commit eb803df into llvm:main Oct 2, 2025
10 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 2, 2025

LLVM Buildbot has detected a new failure on builder cross-project-tests-sie-ubuntu-dwarf5 running on doug-worker-1b while building llvm at step 6 "test-build-unified-tree-check-cross-project".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/163/builds/27462

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-cross-project) failure: test (failure) ******************** TEST 'cross-project-tests :: debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp' FAILED ******************** Exit Code: 1 Command Output (stderr): -- clang++ -O0 -glldb -std=gnu++11 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp -o /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/Output/dex_step_function.cpp.tmp # RUN: at line 7 + clang++ -O0 -glldb -std=gnu++11 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp -o /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/Output/dex_step_function.cpp.tmp "/usr/bin/python3.10" "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/dexter.py" test --fail-lt 1.0 -w -v --debugger lldb-dap --lldb-executable "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/lldb-dap" --dap-message-log=-e -v --binary /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/Output/dex_step_function.cpp.tmp -- /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp 2>&1 | /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/FileCheck /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp # RUN: at line 8 + /usr/bin/python3.10 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/dexter.py test --fail-lt 1.0 -w -v --debugger lldb-dap --lldb-executable /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/lldb-dap --dap-message-log=-e -v --binary /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/Output/dex_step_function.cpp.tmp -- /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp + /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/FileCheck /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp �[1m/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp:34:15: �[0m�[0;1;31merror: �[0m�[1mCHECK-NEXT: expected string not found in input �[0m// CHECK-NEXT:. [0, "a(int)", "{{.*}}dex_step_function.cpp", 22, 3, "StopReason.BREAKPOINT", "StepKind.FUNC", []] �[0;1;32m ^ �[0m�[1m<stdin>:1527:12: �[0m�[0;1;30mnote: �[0m�[1mscanning from here �[0m## BEGIN ## �[0;1;32m ^ �[0m�[1m<stdin>:1531:157: �[0m�[0;1;30mnote: �[0m�[1mpossible intended match here �[0m. . . [3, "c(int)", "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp", 12, 3, "StopReason.BREAKPOINT", "StepKind.FUNC", []] �[0;1;32m ^ �[0m Input file: <stdin> Check file: /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/control/dex_step_function.cpp -dump-input=help explains the following input dump. Input was: <<<<<< �[1m�[0m�[0;1;30m 1: �[0m�[1m�[0;1;46mnote: Opening DAP server: /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/lldb-dap �[0m �[0;1;30m 2: �[0m�[1m�[0;1;46m-> { �[0m �[0;1;30m 3: �[0m�[1m�[0;1;46m "type": "request", �[0m �[0;1;30m 4: �[0m�[1m�[0;1;46m "command": "initialize", �[0m �[0;1;30m 5: �[0m�[1m�[0;1;46m "arguments": { �[0m �[0;1;30m 6: �[0m�[1m�[0;1;46m "clientID": "dexter", �[0m �[0;1;30m 7: �[0m�[1m�[0;1;46m "adapterID": "lldb-dap", �[0m �[0;1;30m 8: �[0m�[1m�[0;1;46m "pathFormat": "path", �[0m �[0;1;30m 9: �[0m�[1m�[0;1;46m "linesStartAt1": true, �[0m �[0;1;30m 10: �[0m�[1m�[0;1;46m "columnsStartAt1": true, �[0m �[0;1;30m 11: �[0m�[1m�[0;1;46m "supportsVariableType": true, �[0m �[0;1;30m 12: �[0m�[1m�[0;1;46m "supportsVariablePaging": true, �[0m �[0;1;30m 13: �[0m�[1m�[0;1;46m "supportsRunInTerminalRequest": false �[0m �[0;1;30m 14: �[0m�[1m�[0;1;46m }, �[0m �[0;1;30m 15: �[0m�[1m�[0;1;46m "seq": 1 �[0m �[0;1;30m 16: �[0m�[1m�[0;1;46m} �[0m �[0;1;30m 17: �[0m�[1m�[0;1;46m<- { �[0m �[0;1;30m 18: �[0m�[1m�[0;1;46m "body": { �[0m �[0;1;30m 19: �[0m�[1m�[0;1;46m "$__lldb_version": "lldb version 22.0.0git (https://github.com/llvm/llvm-project.git revision eb803df5029d08321102d59ead4c61d03ddc8a7a)\n clang revision eb803df5029d08321102d59ead4c61d03ddc8a7a\n llvm revision eb803df5029d08321102d59ead4c61d03ddc8a7a", �[0m �[0;1;30m 20: �[0m�[1m�[0;1;46m "completionTriggerCharacters": [ �[0m �[0;1;30m 21: �[0m�[1m�[0;1;46m ".", �[0m �[0;1;30m 22: �[0m�[1m�[0;1;46m " ", �[0m �[0;1;30m 23: �[0m�[1m�[0;1;46m "\t" �[0m ... 
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Oct 3, 2025
This commit adds the intrinsic `G_FMODF` to GMIR & enables its translation, legalization and instruction selection in AArch64.
@HolyMolyCowMan HolyMolyCowMan deleted the implement-g-modf branch October 13, 2025 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment