Index: llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp =================================================================== --- llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -2463,10 +2463,10 @@ // FIXME: Redundant check, but even less readable when factored out. if (isFP) { - if (Ty != s32 && Ty != s64 && Ty != s128) { + if (Ty != s16 && Ty != s32 && Ty != s64 && Ty != s128) { LLVM_DEBUG(dbgs() << "Unable to materialize FP " << Ty - << " constant, expected: " << s32 << " or " << s64 - << " or " << s128 << '\n'); + << " constant, expected: " << s16 << " or " << s32 + << " or " << s64 << " or " << s128 << '\n'); return false; } @@ -2500,23 +2500,20 @@ } } - // We allow G_CONSTANT of types < 32b. - const unsigned MovOpc = - DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm; - if (isFP) { - // Either emit a FMOV, or emit a copy to emit a normal mov. - const TargetRegisterClass &GPRRC = - DefSize == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass; - const TargetRegisterClass &FPRRC = - DefSize == 32 ? AArch64::FPR32RegClass - : (DefSize == 64 ? AArch64::FPR64RegClass - : AArch64::FPR128RegClass); - - // For 64b values, emit a constant pool load instead. - // For s32, use a cp load if we have optsize/minsize. - if (DefSize == 64 || DefSize == 128 || - (DefSize == 32 && shouldOptForSize(&MF))) { + const TargetRegisterClass &FPRRC = *getMinClassForRegBank(RB, DefSize); + // For 16, 64, and 128b values, emit a constant pool load. + switch (DefSize) { + default: + llvm_unreachable("Unexpected destination size for G_FCONSTANT?"); + case 32: + // For s32, use a cp load if we have optsize/minsize. + if (!shouldOptForSize(&MF)) + break; + LLVM_FALLTHROUGH; + case 16: + case 64: + case 128: { auto *FPImm = I.getOperand(1).getFPImm(); auto *LoadMI = emitLoadFromConstantPool(FPImm, MIB); if (!LoadMI) { @@ -2527,9 +2524,13 @@ I.eraseFromParent(); return RBI.constrainGenericRegister(DefReg, FPRRC, MRI); } + } - // Nope. Emit a copy and use a normal mov instead. - const Register DefGPRReg = MRI.createVirtualRegister(&GPRRC); + // Either emit a FMOV, or emit a copy to emit a normal mov. + assert(DefSize == 32 && + "Expected constant pool loads for all sizes other than 32!"); + const Register DefGPRReg = + MRI.createVirtualRegister(&AArch64::GPR32RegClass); MachineOperand &RegOp = I.getOperand(0); RegOp.setReg(DefGPRReg); MIB.setInsertPt(MIB.getMBB(), std::next(I.getIterator())); @@ -2552,6 +2553,8 @@ I.getOperand(1).ChangeToImmediate(Val); } + const unsigned MovOpc = + DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm; I.setDesc(TII.get(MovOpc)); constrainSelectedInstRegOperands(I, TII, TRI, RBI); return true; @@ -4194,6 +4197,13 @@ .addConstantPoolIndex(CPIdx, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC); break; + case 2: + LoadMI = + &*MIRBuilder + .buildInstr(AArch64::LDRHui, {&AArch64::FPR16RegClass}, {Adrp}) + .addConstantPoolIndex(CPIdx, 0, + AArch64II::MO_PAGEOFF | AArch64II::MO_NC); + break; default: LLVM_DEBUG(dbgs() << "Could not load from constant pool of type " << *CPVal->getType()); Index: llvm/test/CodeGen/AArch64/GlobalISel/select-fp16-fconstant.mir =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/select-fp16-fconstant.mir +++ llvm/test/CodeGen/AArch64/GlobalISel/select-fp16-fconstant.mir @@ -30,3 +30,19 @@ %0:fpr(s16) = G_FCONSTANT half 1.0 $h0 = COPY %0(s16) RET_ReallyLR implicit $h0 +... +--- +name: constant_pool_load +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: constant_pool_load + ; CHECK: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) %const.0 + ; CHECK: [[LDRHui:%[0-9]+]]:fpr16 = LDRHui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) %const.0 :: (load (s16) from constant-pool) + ; CHECK: $h0 = COPY [[LDRHui]] + ; CHECK: RET_ReallyLR implicit $h0 + %0:fpr(s16) = G_FCONSTANT half 0xH000B + $h0 = COPY %0(s16) + RET_ReallyLR implicit $h0