Add f16
inline ASM support for RISC-V · rust-lang/rust@771e44e (original) (raw)
`@@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*;
`
13
13
`use rustc_data_structures::fx::FxHashMap;
`
14
14
`use rustc_middle::ty::layout::TyAndLayout;
`
15
15
`use rustc_middle::{bug, span_bug, ty::Instance};
`
16
``
`-
use rustc_span::{Pos, Span};
`
``
16
`+
use rustc_span::{sym, Pos, Span, Symbol};
`
17
17
`use rustc_target::abi::*;
`
18
18
`use rustc_target::asm::*;
`
19
19
`use tracing::debug;
`
`@@ -64,7 +64,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
`
64
64
`let mut layout = None;
`
65
65
`let ty = if let Some(ref place) = place {
`
66
66
` layout = Some(&place.layout);
`
67
``
`-
llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout)
`
``
67
`+
llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout, instance)
`
68
68
`} else if matches!(
`
69
69
` reg.reg_class(),
`
70
70
`InlineAsmRegClass::X86(
`
`@@ -112,7 +112,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
`
112
112
`// so we just use the type of the input.
`
113
113
`&in_value.layout
`
114
114
`};
`
115
``
`-
let ty = llvm_fixup_output_type(self.cx, reg.reg_class(), layout);
`
``
115
`+
let ty = llvm_fixup_output_type(self.cx, reg.reg_class(), layout, instance);
`
116
116
` output_types.push(ty);
`
117
117
` op_idx.insert(idx, constraints.len());
`
118
118
`let prefix = if late { "=" } else { "=&" };
`
`@@ -127,8 +127,13 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
`
127
127
`for (idx, op) in operands.iter().enumerate() {
`
128
128
`match *op {
`
129
129
`InlineAsmOperandRef::In { reg, value } => {
`
130
``
`-
let llval =
`
131
``
`-
llvm_fixup_input(self, value.immediate(), reg.reg_class(), &value.layout);
`
``
130
`+
let llval = llvm_fixup_input(
`
``
131
`+
self,
`
``
132
`+
value.immediate(),
`
``
133
`+
reg.reg_class(),
`
``
134
`+
&value.layout,
`
``
135
`+
instance,
`
``
136
`+
);
`
132
137
` inputs.push(llval);
`
133
138
` op_idx.insert(idx, constraints.len());
`
134
139
` constraints.push(reg_to_llvm(reg, Some(&value.layout)));
`
`@@ -139,6 +144,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
`
139
144
` in_value.immediate(),
`
140
145
` reg.reg_class(),
`
141
146
`&in_value.layout,
`
``
147
`+
instance,
`
142
148
`);
`
143
149
` inputs.push(value);
`
144
150
``
`@@ -341,7 +347,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
`
341
347
`} else {
`
342
348
`self.extract_value(result, op_idx[&idx] as u64)
`
343
349
`};
`
344
``
`-
let value = llvm_fixup_output(self, value, reg.reg_class(), &place.layout);
`
``
350
`+
let value =
`
``
351
`+
llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance);
`
345
352
`OperandValue::Immediate(value).store(self, place);
`
346
353
`}
`
347
354
`}
`
`@@ -913,12 +920,22 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty
`
913
920
`}
`
914
921
`}
`
915
922
``
``
923
`+
fn any_target_feature_enabled(
`
``
924
`+
cx: &CodegenCx<'_, '_>,
`
``
925
`+
instance: Instance<'_>,
`
``
926
`+
features: &[Symbol],
`
``
927
`+
) -> bool {
`
``
928
`+
let enabled = cx.tcx.asm_target_features(instance.def_id());
`
``
929
`+
features.iter().any(|feat| enabled.contains(feat))
`
``
930
`+
}
`
``
931
+
916
932
`/// Fix up an input value to work around LLVM bugs.
`
917
933
`fn llvm_fixup_input<'ll, 'tcx>(
`
918
934
`bx: &mut Builder<'_, 'll, 'tcx>,
`
919
935
`mut value: &'ll Value,
`
920
936
`reg: InlineAsmRegClass,
`
921
937
`layout: &TyAndLayout<'tcx>,
`
``
938
`+
instance: Instance<'_>,
`
922
939
`) -> &'ll Value {
`
923
940
`let dl = &bx.tcx.data_layout;
`
924
941
`match (reg, layout.abi) {
`
`@@ -1029,6 +1046,16 @@ fn llvm_fixup_input<'ll, 'tcx>(
`
1029
1046
` _ => value,
`
1030
1047
`}
`
1031
1048
`}
`
``
1049
`+
(InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s))
`
``
1050
`+
if s.primitive() == Primitive::Float(Float::F16)
`
``
1051
`+
&& !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) =>
`
``
1052
`+
{
`
``
1053
`+
// Smaller floats are always "NaN-boxed" inside larger floats on RISC-V.
`
``
1054
`+
let value = bx.bitcast(value, bx.type_i16());
`
``
1055
`+
let value = bx.zext(value, bx.type_i32());
`
``
1056
`+
let value = bx.or(value, bx.const_u32(0xFFFF_0000));
`
``
1057
`+
bx.bitcast(value, bx.type_f32())
`
``
1058
`+
}
`
1032
1059
` _ => value,
`
1033
1060
`}
`
1034
1061
`}
`
`@@ -1039,6 +1066,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
`
1039
1066
`mut value: &'ll Value,
`
1040
1067
`reg: InlineAsmRegClass,
`
1041
1068
`layout: &TyAndLayout<'tcx>,
`
``
1069
`+
instance: Instance<'_>,
`
1042
1070
`) -> &'ll Value {
`
1043
1071
`match (reg, layout.abi) {
`
1044
1072
`(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
`
`@@ -1140,6 +1168,14 @@ fn llvm_fixup_output<'ll, 'tcx>(
`
1140
1168
` _ => value,
`
1141
1169
`}
`
1142
1170
`}
`
``
1171
`+
(InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s))
`
``
1172
`+
if s.primitive() == Primitive::Float(Float::F16)
`
``
1173
`+
&& !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) =>
`
``
1174
`+
{
`
``
1175
`+
let value = bx.bitcast(value, bx.type_i32());
`
``
1176
`+
let value = bx.trunc(value, bx.type_i16());
`
``
1177
`+
bx.bitcast(value, bx.type_f16())
`
``
1178
`+
}
`
1143
1179
` _ => value,
`
1144
1180
`}
`
1145
1181
`}
`
`@@ -1149,6 +1185,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
`
1149
1185
`cx: &CodegenCx<'ll, 'tcx>,
`
1150
1186
`reg: InlineAsmRegClass,
`
1151
1187
`layout: &TyAndLayout<'tcx>,
`
``
1188
`+
instance: Instance<'_>,
`
1152
1189
`) -> &'ll Type {
`
1153
1190
`match (reg, layout.abi) {
`
1154
1191
`(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
`
`@@ -1242,6 +1279,12 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
`
1242
1279
` _ => layout.llvm_type(cx),
`
1243
1280
`}
`
1244
1281
`}
`
``
1282
`+
(InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s))
`
``
1283
`+
if s.primitive() == Primitive::Float(Float::F16)
`
``
1284
`+
&& !any_target_feature_enabled(cx, instance, &[sym::zfhmin, sym::zfh]) =>
`
``
1285
`+
{
`
``
1286
`+
cx.type_f32()
`
``
1287
`+
}
`
1245
1288
` _ => layout.llvm_type(cx),
`
1246
1289
`}
`
1247
1290
`}
`