1
+ use std:: slice;
2
+
1
3
use crate :: attributes;
2
4
use crate :: builder:: Builder ;
3
5
use crate :: common:: Funclet ;
@@ -64,7 +66,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
64
66
let mut layout = None ;
65
67
let ty = if let Some ( ref place) = place {
66
68
layout = Some ( & place. layout ) ;
67
- llvm_fixup_output_type ( self . cx , reg. reg_class ( ) , & place. layout )
69
+ llvm_fixup_output_type ( self , reg. reg_class ( ) , & place. layout )
68
70
} else if matches ! (
69
71
reg. reg_class( ) ,
70
72
InlineAsmRegClass :: X86 (
@@ -112,7 +114,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
112
114
// so we just use the type of the input.
113
115
& in_value. layout
114
116
} ;
115
- let ty = llvm_fixup_output_type ( self . cx , reg. reg_class ( ) , layout) ;
117
+ let ty = llvm_fixup_output_type ( self , reg. reg_class ( ) , layout) ;
116
118
output_types. push ( ty) ;
117
119
op_idx. insert ( idx, constraints. len ( ) ) ;
118
120
let prefix = if late { "=" } else { "=&" } ;
@@ -913,6 +915,46 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty
913
915
}
914
916
}
915
917
918
+ fn function_target_features < ' ll > ( builder : & Builder < ' _ , ' ll , ' _ > ) -> impl Iterator < Item = & ' ll str > {
919
+ let llfn = builder. llfn ( ) ;
920
+ let key = "target-features" ;
921
+ let attr = unsafe {
922
+ llvm:: LLVMGetStringAttributeAtIndex (
923
+ llfn,
924
+ llvm:: AttributePlace :: Function . as_uint ( ) ,
925
+ key. as_ptr ( ) . cast ( ) ,
926
+ key. len ( ) . try_into ( ) . unwrap ( ) ,
927
+ )
928
+ } ;
929
+ let Some ( attr) = attr else {
930
+ return "" . split ( ',' ) ;
931
+ } ;
932
+ let value = unsafe {
933
+ let mut length = 0 ;
934
+ let ptr = llvm:: LLVMGetStringAttributeValue ( attr, & mut length) ;
935
+ slice:: from_raw_parts ( ptr. cast ( ) , length. try_into ( ) . unwrap ( ) )
936
+ } ;
937
+ let Ok ( value) = std:: str:: from_utf8 ( value) else {
938
+ return "" . split ( ',' ) ;
939
+ } ;
940
+ value. split ( ',' )
941
+ }
942
+
943
+ fn is_zfhmin_enabled ( builder : & Builder < ' _ , ' _ , ' _ > ) -> bool {
944
+ let mut zfhmin_enabled = false ;
945
+ let mut zfh_enabled = false ;
946
+ for feature in function_target_features ( builder) {
947
+ match feature {
948
+ "+zfhmin" => zfhmin_enabled = true ,
949
+ "-zfhmin" => zfhmin_enabled = false ,
950
+ "+zfh" => zfh_enabled = true ,
951
+ "-zfh" => zfh_enabled = false ,
952
+ _ => { }
953
+ }
954
+ }
955
+ zfhmin_enabled || zfh_enabled
956
+ }
957
+
916
958
/// Fix up an input value to work around LLVM bugs.
917
959
fn llvm_fixup_input < ' ll , ' tcx > (
918
960
bx : & mut Builder < ' _ , ' ll , ' tcx > ,
@@ -1029,6 +1071,15 @@ fn llvm_fixup_input<'ll, 'tcx>(
1029
1071
_ => value,
1030
1072
}
1031
1073
}
1074
+ ( InlineAsmRegClass :: RiscV ( RiscVInlineAsmRegClass :: freg) , Abi :: Scalar ( s) )
1075
+ if s. primitive ( ) == Primitive :: Float ( Float :: F16 ) && !is_zfhmin_enabled ( bx) =>
1076
+ {
1077
+ // Smaller floats are always "NaN-boxed" inside larger floats on RISC-V.
1078
+ let value = bx. bitcast ( value, bx. type_i16 ( ) ) ;
1079
+ let value = bx. zext ( value, bx. type_i32 ( ) ) ;
1080
+ let value = bx. or ( value, bx. const_u32 ( 0xFFFF_0000 ) ) ;
1081
+ bx. bitcast ( value, bx. type_f32 ( ) )
1082
+ }
1032
1083
_ => value,
1033
1084
}
1034
1085
}
@@ -1140,56 +1191,63 @@ fn llvm_fixup_output<'ll, 'tcx>(
1140
1191
_ => value,
1141
1192
}
1142
1193
}
1194
+ ( InlineAsmRegClass :: RiscV ( RiscVInlineAsmRegClass :: freg) , Abi :: Scalar ( s) )
1195
+ if s. primitive ( ) == Primitive :: Float ( Float :: F16 ) && !is_zfhmin_enabled ( bx) =>
1196
+ {
1197
+ let value = bx. bitcast ( value, bx. type_i32 ( ) ) ;
1198
+ let value = bx. trunc ( value, bx. type_i16 ( ) ) ;
1199
+ bx. bitcast ( value, bx. type_f16 ( ) )
1200
+ }
1143
1201
_ => value,
1144
1202
}
1145
1203
}
1146
1204
1147
1205
/// Output type to use for llvm_fixup_output.
1148
1206
fn llvm_fixup_output_type < ' ll , ' tcx > (
1149
- cx : & CodegenCx < ' ll , ' tcx > ,
1207
+ bx : & Builder < ' _ , ' ll , ' tcx > ,
1150
1208
reg : InlineAsmRegClass ,
1151
1209
layout : & TyAndLayout < ' tcx > ,
1152
1210
) -> & ' ll Type {
1153
1211
match ( reg, layout. abi ) {
1154
1212
( InlineAsmRegClass :: AArch64 ( AArch64InlineAsmRegClass :: vreg) , Abi :: Scalar ( s) ) => {
1155
1213
if let Primitive :: Int ( Integer :: I8 , _) = s. primitive ( ) {
1156
- cx . type_vector ( cx . type_i8 ( ) , 8 )
1214
+ bx . type_vector ( bx . type_i8 ( ) , 8 )
1157
1215
} else {
1158
- layout. llvm_type ( cx )
1216
+ layout. llvm_type ( bx )
1159
1217
}
1160
1218
}
1161
1219
( InlineAsmRegClass :: AArch64 ( AArch64InlineAsmRegClass :: vreg_low16) , Abi :: Scalar ( s) ) => {
1162
- let elem_ty = llvm_asm_scalar_type ( cx , s) ;
1220
+ let elem_ty = llvm_asm_scalar_type ( bx , s) ;
1163
1221
let count = 16 / layout. size . bytes ( ) ;
1164
- cx . type_vector ( elem_ty, count)
1222
+ bx . type_vector ( elem_ty, count)
1165
1223
}
1166
1224
(
1167
1225
InlineAsmRegClass :: AArch64 ( AArch64InlineAsmRegClass :: vreg_low16) ,
1168
1226
Abi :: Vector { element, count } ,
1169
1227
) if layout. size . bytes ( ) == 8 => {
1170
- let elem_ty = llvm_asm_scalar_type ( cx , element) ;
1171
- cx . type_vector ( elem_ty, count * 2 )
1228
+ let elem_ty = llvm_asm_scalar_type ( bx , element) ;
1229
+ bx . type_vector ( elem_ty, count * 2 )
1172
1230
}
1173
1231
( InlineAsmRegClass :: X86 ( X86InlineAsmRegClass :: reg_abcd) , Abi :: Scalar ( s) )
1174
1232
if s. primitive ( ) == Primitive :: Float ( Float :: F64 ) =>
1175
1233
{
1176
- cx . type_i64 ( )
1234
+ bx . type_i64 ( )
1177
1235
}
1178
1236
(
1179
1237
InlineAsmRegClass :: X86 ( X86InlineAsmRegClass :: xmm_reg | X86InlineAsmRegClass :: zmm_reg) ,
1180
1238
Abi :: Vector { .. } ,
1181
- ) if layout. size . bytes ( ) == 64 => cx . type_vector ( cx . type_f64 ( ) , 8 ) ,
1239
+ ) if layout. size . bytes ( ) == 64 => bx . type_vector ( bx . type_f64 ( ) , 8 ) ,
1182
1240
(
1183
1241
InlineAsmRegClass :: X86 (
1184
1242
X86InlineAsmRegClass :: xmm_reg
1185
1243
| X86InlineAsmRegClass :: ymm_reg
1186
1244
| X86InlineAsmRegClass :: zmm_reg,
1187
1245
) ,
1188
1246
Abi :: Scalar ( s) ,
1189
- ) if cx . sess ( ) . asm_arch == Some ( InlineAsmArch :: X86 )
1247
+ ) if bx . sess ( ) . asm_arch == Some ( InlineAsmArch :: X86 )
1190
1248
&& s. primitive ( ) == Primitive :: Float ( Float :: F128 ) =>
1191
1249
{
1192
- cx . type_vector ( cx . type_i32 ( ) , 4 )
1250
+ bx . type_vector ( bx . type_i32 ( ) , 4 )
1193
1251
}
1194
1252
(
1195
1253
InlineAsmRegClass :: X86 (
@@ -1198,7 +1256,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
1198
1256
| X86InlineAsmRegClass :: zmm_reg,
1199
1257
) ,
1200
1258
Abi :: Scalar ( s) ,
1201
- ) if s. primitive ( ) == Primitive :: Float ( Float :: F16 ) => cx . type_vector ( cx . type_i16 ( ) , 8 ) ,
1259
+ ) if s. primitive ( ) == Primitive :: Float ( Float :: F16 ) => bx . type_vector ( bx . type_i16 ( ) , 8 ) ,
1202
1260
(
1203
1261
InlineAsmRegClass :: X86 (
1204
1262
X86InlineAsmRegClass :: xmm_reg
@@ -1207,16 +1265,16 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
1207
1265
) ,
1208
1266
Abi :: Vector { element, count : count @ ( 8 | 16 ) } ,
1209
1267
) if element. primitive ( ) == Primitive :: Float ( Float :: F16 ) => {
1210
- cx . type_vector ( cx . type_i16 ( ) , count)
1268
+ bx . type_vector ( bx . type_i16 ( ) , count)
1211
1269
}
1212
1270
(
1213
1271
InlineAsmRegClass :: Arm ( ArmInlineAsmRegClass :: sreg | ArmInlineAsmRegClass :: sreg_low16) ,
1214
1272
Abi :: Scalar ( s) ,
1215
1273
) => {
1216
1274
if let Primitive :: Int ( Integer :: I32 , _) = s. primitive ( ) {
1217
- cx . type_f32 ( )
1275
+ bx . type_f32 ( )
1218
1276
} else {
1219
- layout. llvm_type ( cx )
1277
+ layout. llvm_type ( bx )
1220
1278
}
1221
1279
}
1222
1280
(
@@ -1228,20 +1286,25 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
1228
1286
Abi :: Scalar ( s) ,
1229
1287
) => {
1230
1288
if let Primitive :: Int ( Integer :: I64 , _) = s. primitive ( ) {
1231
- cx . type_f64 ( )
1289
+ bx . type_f64 ( )
1232
1290
} else {
1233
- layout. llvm_type ( cx )
1291
+ layout. llvm_type ( bx )
1234
1292
}
1235
1293
}
1236
1294
( InlineAsmRegClass :: Mips ( MipsInlineAsmRegClass :: reg) , Abi :: Scalar ( s) ) => {
1237
1295
match s. primitive ( ) {
1238
1296
// MIPS only supports register-length arithmetics.
1239
- Primitive :: Int ( Integer :: I8 | Integer :: I16 , _) => cx . type_i32 ( ) ,
1240
- Primitive :: Float ( Float :: F32 ) => cx . type_i32 ( ) ,
1241
- Primitive :: Float ( Float :: F64 ) => cx . type_i64 ( ) ,
1242
- _ => layout. llvm_type ( cx ) ,
1297
+ Primitive :: Int ( Integer :: I8 | Integer :: I16 , _) => bx . type_i32 ( ) ,
1298
+ Primitive :: Float ( Float :: F32 ) => bx . type_i32 ( ) ,
1299
+ Primitive :: Float ( Float :: F64 ) => bx . type_i64 ( ) ,
1300
+ _ => layout. llvm_type ( bx ) ,
1243
1301
}
1244
1302
}
1245
- _ => layout. llvm_type ( cx) ,
1303
+ ( InlineAsmRegClass :: RiscV ( RiscVInlineAsmRegClass :: freg) , Abi :: Scalar ( s) )
1304
+ if s. primitive ( ) == Primitive :: Float ( Float :: F16 ) && !is_zfhmin_enabled ( bx) =>
1305
+ {
1306
+ bx. type_f32 ( )
1307
+ }
1308
+ _ => layout. llvm_type ( bx) ,
1246
1309
}
1247
1310
}
0 commit comments