[llvm] [LoongArch] Pass 'half' in the lower 16 bits of an f32 value with F/D ABI (PR #109368)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 24 06:15:58 PDT 2024
================
@@ -1354,6 +1358,40 @@ SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
return SDValue();
}
+SDValue LoongArchTargetLowering::lowerFP_TO_FP16(SDValue Op,
+ SelectionDAG &DAG) const {
+ // Custom lower to ensure the libcall return is passed in an FPR on hard
+ // float ABIs.
+ SDLoc DL(Op);
+ MakeLibCallOptions CallOptions;
+ SDValue Op0 = Op.getOperand(0);
+ SDValue Chain = SDValue();
+ RTLIB::Libcall LC = RTLIB::getFPROUND(Op0.getValueType(), MVT::f16);
+ SDValue Res;
+ std::tie(Res, Chain) =
+ makeLibCall(DAG, LC, MVT::f32, Op0, CallOptions, DL, Chain);
+ if (Subtarget.is64Bit())
+ return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
+ return DAG.getBitcast(MVT::i32, Res);
+}
+
+SDValue LoongArchTargetLowering::lowerFP16_TO_FP(SDValue Op,
+ SelectionDAG &DAG) const {
+ // Custom lower to ensure the libcall argument is passed in an FPR on hard
+ // float ABIs.
----------------
heiher wrote:
For this case:
```llvm
define float @test_fpextend_float(half %a) nounwind {
%r = fpext half %a to float
ret float %r
}
```
Debug log (without FP16_TO_FP custom lowering):
```
Optimized lowered selection DAG: %bb.0 'test_fpextend_float:'
SelectionDAG has 10 nodes:
t0: ch,glue = EntryToken
t2: f32,ch = CopyFromReg t0, Register:f32 %0
t3: i32 = bitcast t2
t4: i16 = truncate t3
t5: f16 = bitcast t4
t6: f32 = fp_extend t5
t8: ch,glue = CopyToReg t0, Register:f32 $f0, t6
t9: ch = LoongArchISD::RET t8, Register:f32 $f0, t8:1
Type-legalized selection DAG: %bb.0 'test_fpextend_float:'
SelectionDAG has 10 nodes:
t0: ch,glue = EntryToken
t2: f32,ch = CopyFromReg t0, Register:f32 %0
t10: i64 = LoongArchISD::MOVFR2GR_S_LA64 t2
t14: i64 = and t10, Constant:i64<65535>
t12: f32 = fp16_to_fp t14
t8: ch,glue = CopyToReg t0, Register:f32 $f0, t12
t9: ch = LoongArchISD::RET t8, Register:f32 $f0, t8:1
Optimized type-legalized selection DAG: %bb.0 'test_fpextend_float:'
SelectionDAG has 8 nodes:
t0: ch,glue = EntryToken
t2: f32,ch = CopyFromReg t0, Register:f32 %0
t10: i64 = LoongArchISD::MOVFR2GR_S_LA64 t2
t15: f32 = fp16_to_fp t10
t8: ch,glue = CopyToReg t0, Register:f32 $f0, t15
t9: ch = LoongArchISD::RET t8, Register:f32 $f0, t8:1
Legalized selection DAG: %bb.0 'test_fpextend_float:'
SelectionDAG has 8 nodes:
t0: ch,glue = EntryToken
t2: f32,ch = CopyFromReg t0, Register:f32 %0
t10: i64 = LoongArchISD::MOVFR2GR_S_LA64 t2
t18: ch,glue = CopyToReg t0, Register:i64 $r4, t10
t20: ch,glue = LoongArchISD::TAIL t18, TargetExternalSymbol:i64'__gnu_h2f_ieee' [TF=2], Register:i64 $r4, t18:1
```
In joinRegisterPartsIntoValue, the fp16 (wrapped as f32) in the parameter register (FPR) is first bitcast to i32, truncated to i16, and then bitcast to f16. Following this, the software promotion of FP_EXTEND generates FP16_TO_FP. At this point, the source operand of FP16_TO_FP is already i64, losing its association with the fp16 type. It seems that the target calling convention cannot handle passing through the FPR? :sob:
https://github.com/llvm/llvm-project/pull/109368
More information about the llvm-commits
mailing list