Skip to content

Commit 65b87aa

Browse files
committed
Support new target builtins
1 parent 06af88e commit 65b87aa

File tree

1 file changed

+244
-1
lines changed

1 file changed

+244
-1
lines changed

Diff for: src/intrinsic/llvm.rs

+244-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,86 @@
11
use std::borrow::Cow;
22

3-
use gccjit::{CType, Context, Function, FunctionPtrType, RValue, ToRValue};
3+
use gccjit::{CType, Context, Field, Function, FunctionPtrType, RValue, ToRValue, Type};
44
use rustc_codegen_ssa::traits::BuilderMethods;
55

66
use crate::builder::Builder;
77
use crate::context::CodegenCx;
88

9+
fn encode_key_128_type<'a, 'gcc, 'tcx>(
10+
builder: &Builder<'a, 'gcc, 'tcx>,
11+
) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
12+
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
13+
let field1 = builder.context.new_field(None, builder.u32_type, "field1");
14+
let field2 = builder.context.new_field(None, m128i, "field2");
15+
let field3 = builder.context.new_field(None, m128i, "field3");
16+
let field4 = builder.context.new_field(None, m128i, "field4");
17+
let field5 = builder.context.new_field(None, m128i, "field5");
18+
let field6 = builder.context.new_field(None, m128i, "field6");
19+
let field7 = builder.context.new_field(None, m128i, "field7");
20+
let encode_type = builder.context.new_struct_type(
21+
None,
22+
"EncodeKey128Output",
23+
&[field1, field2, field3, field4, field5, field6, field7],
24+
);
25+
encode_type.as_type().set_packed();
26+
(encode_type.as_type(), field1, field2)
27+
}
28+
29+
fn encode_key_256_type<'a, 'gcc, 'tcx>(
30+
builder: &Builder<'a, 'gcc, 'tcx>,
31+
) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
32+
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
33+
let field1 = builder.context.new_field(None, builder.u32_type, "field1");
34+
let field2 = builder.context.new_field(None, m128i, "field2");
35+
let field3 = builder.context.new_field(None, m128i, "field3");
36+
let field4 = builder.context.new_field(None, m128i, "field4");
37+
let field5 = builder.context.new_field(None, m128i, "field5");
38+
let field6 = builder.context.new_field(None, m128i, "field6");
39+
let field7 = builder.context.new_field(None, m128i, "field7");
40+
let field8 = builder.context.new_field(None, m128i, "field8");
41+
let encode_type = builder.context.new_struct_type(
42+
None,
43+
"EncodeKey256Output",
44+
&[field1, field2, field3, field4, field5, field6, field7, field8],
45+
);
46+
encode_type.as_type().set_packed();
47+
(encode_type.as_type(), field1, field2)
48+
}
49+
50+
fn aes_output_type<'a, 'gcc, 'tcx>(
51+
builder: &Builder<'a, 'gcc, 'tcx>,
52+
) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
53+
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
54+
let field1 = builder.context.new_field(None, builder.u8_type, "field1");
55+
let field2 = builder.context.new_field(None, m128i, "field2");
56+
let aes_output_type = builder.context.new_struct_type(None, "AesOutput", &[field1, field2]);
57+
let typ = aes_output_type.as_type();
58+
typ.set_packed();
59+
(typ, field1, field2)
60+
}
61+
62+
fn wide_aes_output_type<'a, 'gcc, 'tcx>(
63+
builder: &Builder<'a, 'gcc, 'tcx>,
64+
) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
65+
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
66+
let field1 = builder.context.new_field(None, builder.u8_type, "field1");
67+
let field2 = builder.context.new_field(None, m128i, "field2");
68+
let field3 = builder.context.new_field(None, m128i, "field3");
69+
let field4 = builder.context.new_field(None, m128i, "field4");
70+
let field5 = builder.context.new_field(None, m128i, "field5");
71+
let field6 = builder.context.new_field(None, m128i, "field6");
72+
let field7 = builder.context.new_field(None, m128i, "field7");
73+
let field8 = builder.context.new_field(None, m128i, "field8");
74+
let field9 = builder.context.new_field(None, m128i, "field9");
75+
let aes_output_type = builder.context.new_struct_type(
76+
None,
77+
"WideAesOutput",
78+
&[field1, field2, field3, field4, field5, field6, field7, field8, field9],
79+
);
80+
aes_output_type.as_type().set_packed();
81+
(aes_output_type.as_type(), field1, field2)
82+
}
83+
984
#[cfg_attr(not(feature = "master"), allow(unused_variables))]
1085
pub fn adjust_function<'gcc>(
1186
context: &'gcc Context<'gcc>,
@@ -503,6 +578,74 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
503578
let arg4 = builder.context.new_rvalue_from_int(arg4_type, -1);
504579
args = vec![a, b, c, arg4, new_args[3]].into();
505580
}
581+
"__builtin_ia32_encodekey128_u32" => {
582+
let mut new_args = args.to_vec();
583+
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
584+
let array_type = builder.context.new_array_type(None, m128i, 6);
585+
let result = builder.current_func().new_local(None, array_type, "result");
586+
new_args.push(result.get_address(None));
587+
args = new_args.into();
588+
}
589+
"__builtin_ia32_encodekey256_u32" => {
590+
let mut new_args = args.to_vec();
591+
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
592+
let array_type = builder.context.new_array_type(None, m128i, 7);
593+
let result = builder.current_func().new_local(None, array_type, "result");
594+
new_args.push(result.get_address(None));
595+
args = new_args.into();
596+
}
597+
"__builtin_ia32_aesenc128kl_u8"
598+
| "__builtin_ia32_aesdec128kl_u8"
599+
| "__builtin_ia32_aesenc256kl_u8"
600+
| "__builtin_ia32_aesdec256kl_u8" => {
601+
let mut new_args = vec![];
602+
// TODO: directly create a variable of type m128i instead of the whole struct?
603+
let (aes_output_type, _, field2) = aes_output_type(builder);
604+
let result = builder.current_func().new_local(None, aes_output_type, "result");
605+
let field2 = result.access_field(None, field2);
606+
new_args.push(field2.get_address(None));
607+
new_args.extend(args.to_vec());
608+
args = new_args.into();
609+
}
610+
"__builtin_ia32_aesencwide128kl_u8"
611+
| "__builtin_ia32_aesdecwide128kl_u8"
612+
| "__builtin_ia32_aesencwide256kl_u8"
613+
| "__builtin_ia32_aesdecwide256kl_u8" => {
614+
let mut new_args = vec![];
615+
616+
let mut old_args = args.to_vec();
617+
let handle = old_args.swap_remove(0); // Called __P in GCC.
618+
let first_value = old_args.swap_remove(0);
619+
620+
let element_type = first_value.get_type();
621+
let array_type = builder.context.new_array_type(None, element_type, 8);
622+
let result = builder.current_func().new_local(None, array_type, "result");
623+
new_args.push(result.get_address(None));
624+
625+
let array = builder.current_func().new_local(None, array_type, "array");
626+
let input = builder.context.new_array_constructor(
627+
None,
628+
array_type,
629+
&[
630+
first_value,
631+
old_args.swap_remove(0),
632+
old_args.swap_remove(0),
633+
old_args.swap_remove(0),
634+
old_args.swap_remove(0),
635+
old_args.swap_remove(0),
636+
old_args.swap_remove(0),
637+
old_args.swap_remove(0),
638+
],
639+
);
640+
builder.llbb().add_assignment(None, array, input);
641+
let input_ptr = array.get_address(None);
642+
let arg2_type = gcc_func.get_param_type(1);
643+
let input_ptr = builder.context.new_cast(None, input_ptr, arg2_type);
644+
new_args.push(input_ptr);
645+
646+
new_args.push(handle);
647+
args = new_args.into();
648+
}
506649
_ => (),
507650
}
508651
} else {
@@ -700,6 +843,96 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
700843
let f16_type = builder.context.new_c_type(CType::Float16);
701844
return_value = builder.context.new_cast(None, return_value, f16_type);
702845
}
846+
"__builtin_ia32_encodekey128_u32" => {
847+
// The builtin __builtin_ia32_encodekey128_u32 writes the result in its pointer argument while
848+
// llvm.x86.encodekey128 returns a value.
849+
// We added a result pointer argument and now need to assign its value to the return_value expected by
850+
// the LLVM intrinsic.
851+
let (encode_type, field1, field2) = encode_key_128_type(builder);
852+
let result = builder.current_func().new_local(None, encode_type, "result");
853+
let field1 = result.access_field(None, field1);
854+
builder.llbb().add_assignment(None, field1, return_value);
855+
let field2 = result.access_field(None, field2);
856+
let field2_type = field2.to_rvalue().get_type();
857+
let array_type = builder.context.new_array_type(None, field2_type, 6);
858+
let ptr = builder.context.new_cast(None, args[2], array_type.make_pointer());
859+
let field2_ptr =
860+
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
861+
builder.llbb().add_assignment(
862+
None,
863+
field2_ptr.dereference(None),
864+
ptr.dereference(None),
865+
);
866+
return_value = result.to_rvalue();
867+
}
868+
"__builtin_ia32_encodekey256_u32" => {
869+
// The builtin __builtin_ia32_encodekey256_u32 writes the result in its pointer argument while
870+
// llvm.x86.encodekey256 returns a value.
871+
// We added a result pointer argument and now need to assign its value to the return_value expected by
872+
// the LLVM intrinsic.
873+
let (encode_type, field1, field2) = encode_key_256_type(builder);
874+
let result = builder.current_func().new_local(None, encode_type, "result");
875+
let field1 = result.access_field(None, field1);
876+
builder.llbb().add_assignment(None, field1, return_value);
877+
let field2 = result.access_field(None, field2);
878+
let field2_type = field2.to_rvalue().get_type();
879+
let array_type = builder.context.new_array_type(None, field2_type, 7);
880+
let ptr = builder.context.new_cast(None, args[3], array_type.make_pointer());
881+
let field2_ptr =
882+
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
883+
builder.llbb().add_assignment(
884+
None,
885+
field2_ptr.dereference(None),
886+
ptr.dereference(None),
887+
);
888+
return_value = result.to_rvalue();
889+
}
890+
"__builtin_ia32_aesdec128kl_u8"
891+
| "__builtin_ia32_aesenc128kl_u8"
892+
| "__builtin_ia32_aesdec256kl_u8"
893+
| "__builtin_ia32_aesenc256kl_u8" => {
894+
// The builtin for aesdec/aesenc writes the result in its pointer argument while
895+
// llvm.x86.aesdec128kl returns a value.
896+
// We added a result pointer argument and now need to assign its value to the return_value expected by
897+
// the LLVM intrinsic.
898+
let (aes_output_type, field1, field2) = aes_output_type(builder);
899+
let result = builder.current_func().new_local(None, aes_output_type, "result");
900+
let field1 = result.access_field(None, field1);
901+
builder.llbb().add_assignment(None, field1, return_value);
902+
let field2 = result.access_field(None, field2);
903+
let ptr = builder.context.new_cast(
904+
None,
905+
args[0],
906+
field2.to_rvalue().get_type().make_pointer(),
907+
);
908+
builder.llbb().add_assignment(None, field2, ptr.dereference(None));
909+
return_value = result.to_rvalue();
910+
}
911+
"__builtin_ia32_aesencwide128kl_u8"
912+
| "__builtin_ia32_aesdecwide128kl_u8"
913+
| "__builtin_ia32_aesencwide256kl_u8"
914+
| "__builtin_ia32_aesdecwide256kl_u8" => {
915+
// The builtin for aesdecwide/aesencwide writes the result in its pointer argument while
916+
// llvm.x86.aesencwide128kl returns a value.
917+
// We added a result pointer argument and now need to assign its value to the return_value expected by
918+
// the LLVM intrinsic.
919+
let (aes_output_type, field1, field2) = wide_aes_output_type(builder);
920+
let result = builder.current_func().new_local(None, aes_output_type, "result");
921+
let field1 = result.access_field(None, field1);
922+
builder.llbb().add_assignment(None, field1, return_value);
923+
let field2 = result.access_field(None, field2);
924+
let field2_type = field2.to_rvalue().get_type();
925+
let array_type = builder.context.new_array_type(None, field2_type, 8);
926+
let ptr = builder.context.new_cast(None, args[0], array_type.make_pointer());
927+
let field2_ptr =
928+
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
929+
builder.llbb().add_assignment(
930+
None,
931+
field2_ptr.dereference(None),
932+
ptr.dereference(None),
933+
);
934+
return_value = result.to_rvalue();
935+
}
703936
_ => (),
704937
}
705938

@@ -1284,6 +1517,16 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
12841517
"llvm.x86.avx512fp16.mask.vfmadd.cph.256" => "__builtin_ia32_vfmaddcph256_mask3",
12851518
"llvm.x86.avx512fp16.mask.vfcmadd.cph.128" => "__builtin_ia32_vfcmaddcph128_mask3",
12861519
"llvm.x86.avx512fp16.mask.vfmadd.cph.128" => "__builtin_ia32_vfmaddcph128_mask3",
1520+
"llvm.x86.encodekey128" => "__builtin_ia32_encodekey128_u32",
1521+
"llvm.x86.encodekey256" => "__builtin_ia32_encodekey256_u32",
1522+
"llvm.x86.aesenc128kl" => "__builtin_ia32_aesenc128kl_u8",
1523+
"llvm.x86.aesdec128kl" => "__builtin_ia32_aesdec128kl_u8",
1524+
"llvm.x86.aesenc256kl" => "__builtin_ia32_aesenc256kl_u8",
1525+
"llvm.x86.aesdec256kl" => "__builtin_ia32_aesdec256kl_u8",
1526+
"llvm.x86.aesencwide128kl" => "__builtin_ia32_aesencwide128kl_u8",
1527+
"llvm.x86.aesdecwide128kl" => "__builtin_ia32_aesdecwide128kl_u8",
1528+
"llvm.x86.aesencwide256kl" => "__builtin_ia32_aesencwide256kl_u8",
1529+
"llvm.x86.aesdecwide256kl" => "__builtin_ia32_aesdecwide256kl_u8",
12871530

12881531
// TODO: support the tile builtins:
12891532
"llvm.x86.ldtilecfg" => "__builtin_trap",

0 commit comments

Comments
 (0)