@@ -768,18 +768,75 @@ const DeclGen = struct {
768
768
};
769
769
}
770
770
771
- /// Construct a composite value at runtime. If the parameters are in direct
772
- /// representation, then the result is also in direct representation. Otherwise,
773
- /// if the parameters are in indirect representation, then the result is too.
774
- fn constructComposite (self : * DeclGen , ty : Type , constituents : []const IdRef ) ! IdRef {
775
- const constituents_id = self .spv .allocId ();
776
- const type_id = try self .resolveType (ty , .direct );
777
- try self .func .body .emit (self .spv .gpa , .OpCompositeConstruct , .{
778
- .id_result_type = self .typeId (type_id ),
779
- .id_result = constituents_id ,
780
- .constituents = constituents ,
781
- });
782
- return constituents_id ;
771
+ /// Construct a struct at runtime.
772
+ /// ty must be a struct type.
773
+ /// Constituents should be in `indirect` representation (as the elements of a struct should be).
774
+ /// Result is in `direct` representation.
775
+ fn constructStruct (self : * DeclGen , ty : Type , types : []const Type , constituents : []const IdRef ) ! IdRef {
776
+ assert (types .len == constituents .len );
777
+ // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which'
778
+ // operands are not constant.
779
+ // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349
780
+ // For now, just initialize the struct by setting the fields manually...
781
+ // TODO: Make this OpCompositeConstruct when we can
782
+ const ptr_composite_id = try self .alloc (ty , .{ .storage_class = .Function });
783
+ for (constituents , types , 0.. ) | constitent_id , member_ty , index | {
784
+ const ptr_member_ty_ref = try self .ptrType (member_ty , .Function );
785
+ const ptr_id = try self .accessChain (ptr_member_ty_ref , ptr_composite_id , &.{@as (u32 , @intCast (index ))});
786
+ try self .func .body .emit (self .spv .gpa , .OpStore , .{
787
+ .pointer = ptr_id ,
788
+ .object = constitent_id ,
789
+ });
790
+ }
791
+ return try self .load (ty , ptr_composite_id , .{});
792
+ }
793
+
794
+ /// Construct a vector at runtime.
795
+ /// ty must be an vector type.
796
+ /// Constituents should be in `indirect` representation (as the elements of an vector should be).
797
+ /// Result is in `direct` representation.
798
+ fn constructVector (self : * DeclGen , ty : Type , constituents : []const IdRef ) ! IdRef {
799
+ // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which'
800
+ // operands are not constant.
801
+ // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349
802
+ // For now, just initialize the struct by setting the fields manually...
803
+ // TODO: Make this OpCompositeConstruct when we can
804
+ const mod = self .module ;
805
+ const ptr_composite_id = try self .alloc (ty , .{ .storage_class = .Function });
806
+ const ptr_elem_ty_ref = try self .ptrType (ty .elemType2 (mod ), .Function );
807
+ for (constituents , 0.. ) | constitent_id , index | {
808
+ const ptr_id = try self .accessChain (ptr_elem_ty_ref , ptr_composite_id , &.{@as (u32 , @intCast (index ))});
809
+ try self .func .body .emit (self .spv .gpa , .OpStore , .{
810
+ .pointer = ptr_id ,
811
+ .object = constitent_id ,
812
+ });
813
+ }
814
+
815
+ return try self .load (ty , ptr_composite_id , .{});
816
+ }
817
+
818
+ /// Construct an array at runtime.
819
+ /// ty must be an array type.
820
+ /// Constituents should be in `indirect` representation (as the elements of an array should be).
821
+ /// Result is in `direct` representation.
822
+ fn constructArray (self : * DeclGen , ty : Type , constituents : []const IdRef ) ! IdRef {
823
+ // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which'
824
+ // operands are not constant.
825
+ // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349
826
+ // For now, just initialize the struct by setting the fields manually...
827
+ // TODO: Make this OpCompositeConstruct when we can
828
+ const mod = self .module ;
829
+ const ptr_composite_id = try self .alloc (ty , .{ .storage_class = .Function });
830
+ const ptr_elem_ty_ref = try self .ptrType (ty .elemType2 (mod ), .Function );
831
+ for (constituents , 0.. ) | constitent_id , index | {
832
+ const ptr_id = try self .accessChain (ptr_elem_ty_ref , ptr_composite_id , &.{@as (u32 , @intCast (index ))});
833
+ try self .func .body .emit (self .spv .gpa , .OpStore , .{
834
+ .pointer = ptr_id ,
835
+ .object = constitent_id ,
836
+ });
837
+ }
838
+
839
+ return try self .load (ty , ptr_composite_id , .{});
783
840
}
784
841
785
842
/// This function generates a load for a constant in direct (ie, non-memory) representation.
@@ -887,15 +944,18 @@ const DeclGen = struct {
887
944
});
888
945
889
946
var constituents : [2 ]IdRef = undefined ;
947
+ var types : [2 ]Type = undefined ;
890
948
if (eu_layout .error_first ) {
891
949
constituents [0 ] = try self .constant (err_ty , err_val , .indirect );
892
950
constituents [1 ] = try self .constant (payload_ty , payload_val , .indirect );
951
+ types = .{ err_ty , payload_ty };
893
952
} else {
894
953
constituents [0 ] = try self .constant (payload_ty , payload_val , .indirect );
895
954
constituents [1 ] = try self .constant (err_ty , err_val , .indirect );
955
+ types = .{ payload_ty , err_ty };
896
956
}
897
957
898
- return try self .constructComposite (ty , & constituents );
958
+ return try self .constructStruct (ty , & types , & constituents );
899
959
},
900
960
.enum_tag = > {
901
961
const int_val = try val .intFromEnum (ty , mod );
@@ -907,7 +967,11 @@ const DeclGen = struct {
907
967
const ptr_ty = ty .slicePtrFieldType (mod );
908
968
const ptr_id = try self .constantPtr (ptr_ty , Value .fromInterned (slice .ptr ));
909
969
const len_id = try self .constant (Type .usize , Value .fromInterned (slice .len ), .indirect );
910
- return self .constructComposite (ty , &.{ ptr_id , len_id });
970
+ return self .constructStruct (
971
+ ty ,
972
+ &.{ ptr_ty , Type .usize },
973
+ &.{ ptr_id , len_id },
974
+ );
911
975
},
912
976
.opt = > {
913
977
const payload_ty = ty .optionalChild (mod );
@@ -934,7 +998,11 @@ const DeclGen = struct {
934
998
else
935
999
try self .spv .constUndef (try self .resolveType (payload_ty , .indirect ));
936
1000
937
- return try self .constructComposite (ty , &.{ payload_id , has_pl_id });
1001
+ return try self .constructStruct (
1002
+ ty ,
1003
+ &.{ payload_ty , Type .bool },
1004
+ &.{ payload_id , has_pl_id },
1005
+ );
938
1006
},
939
1007
.aggregate = > | aggregate | switch (ip .indexToKey (ty .ip_index )) {
940
1008
inline .array_type , .vector_type = > | array_type , tag | {
@@ -971,9 +1039,9 @@ const DeclGen = struct {
971
1039
const sentinel = Value .fromInterned (array_type .sentinel );
972
1040
constituents [constituents .len - 1 ] = try self .constant (elem_ty , sentinel , .indirect );
973
1041
}
974
- return self .constructComposite (ty , constituents );
1042
+ return self .constructArray (ty , constituents );
975
1043
},
976
- inline .vector_type = > return self .constructComposite (ty , constituents ),
1044
+ inline .vector_type = > return self .constructVector (ty , constituents ),
977
1045
else = > unreachable ,
978
1046
}
979
1047
},
@@ -983,6 +1051,9 @@ const DeclGen = struct {
983
1051
return self .todo ("packed struct constants" , .{});
984
1052
}
985
1053
1054
+ var types = std .ArrayList (Type ).init (self .gpa );
1055
+ defer types .deinit ();
1056
+
986
1057
var constituents = std .ArrayList (IdRef ).init (self .gpa );
987
1058
defer constituents .deinit ();
988
1059
@@ -998,10 +1069,11 @@ const DeclGen = struct {
998
1069
const field_val = try val .fieldValue (mod , field_index );
999
1070
const field_id = try self .constant (field_ty , field_val , .indirect );
1000
1071
1072
+ try types .append (field_ty );
1001
1073
try constituents .append (field_id );
1002
1074
}
1003
1075
1004
- return try self .constructComposite (ty , constituents .items );
1076
+ return try self .constructStruct (ty , types . items , constituents .items );
1005
1077
},
1006
1078
.anon_struct_type = > unreachable , // TODO
1007
1079
else = > unreachable ,
@@ -1841,7 +1913,7 @@ const DeclGen = struct {
1841
1913
for (wip .results ) | * result | {
1842
1914
result .* = try wip .dg .convertToIndirect (wip .ty , result .* );
1843
1915
}
1844
- return try wip .dg .constructComposite (wip .result_ty , wip .results );
1916
+ return try wip .dg .constructArray (wip .result_ty , wip .results );
1845
1917
} else {
1846
1918
return wip .results [0 ];
1847
1919
}
@@ -2792,8 +2864,9 @@ const DeclGen = struct {
2792
2864
ov_id .* = try self .intFromBool (wip_ov .ty_ref , overflowed_id );
2793
2865
}
2794
2866
2795
- return try self .constructComposite (
2867
+ return try self .constructStruct (
2796
2868
result_ty ,
2869
+ &.{ operand_ty , ov_ty },
2797
2870
&.{ try wip_result .finalize (), try wip_ov .finalize () },
2798
2871
);
2799
2872
}
@@ -2885,8 +2958,9 @@ const DeclGen = struct {
2885
2958
ov_id .* = try self .intFromBool (wip_ov .ty_ref , overflowed_id );
2886
2959
}
2887
2960
2888
- return try self .constructComposite (
2961
+ return try self .constructStruct (
2889
2962
result_ty ,
2963
+ &.{ operand_ty , ov_ty },
2890
2964
&.{ try wip_result .finalize (), try wip_ov .finalize () },
2891
2965
);
2892
2966
}
@@ -3588,19 +3662,28 @@ const DeclGen = struct {
3588
3662
// Convert the pointer-to-array to a pointer to the first element.
3589
3663
try self .accessChain (elem_ptr_ty_ref , array_ptr_id , &.{0 });
3590
3664
3591
- return try self .constructComposite (slice_ty , &.{ elem_ptr_id , len_id });
3665
+ return try self .constructStruct (
3666
+ slice_ty ,
3667
+ &.{ elem_ptr_ty , Type .usize },
3668
+ &.{ elem_ptr_id , len_id },
3669
+ );
3592
3670
}
3593
3671
3594
3672
fn airSlice (self : * DeclGen , inst : Air.Inst.Index ) ! ? IdRef {
3595
3673
const ty_pl = self .air .instructions .items (.data )[@intFromEnum (inst )].ty_pl ;
3596
3674
const bin_op = self .air .extraData (Air .Bin , ty_pl .payload ).data ;
3597
3675
const ptr_id = try self .resolve (bin_op .lhs );
3598
3676
const len_id = try self .resolve (bin_op .rhs );
3677
+ const ptr_ty = self .typeOf (bin_op .lhs );
3599
3678
const slice_ty = self .typeOfIndex (inst );
3600
3679
3601
3680
// Note: Types should not need to be converted to direct, these types
3602
3681
// dont need to be converted.
3603
- return try self .constructComposite (slice_ty , &.{ ptr_id , len_id });
3682
+ return try self .constructStruct (
3683
+ slice_ty ,
3684
+ &.{ ptr_ty , Type .usize },
3685
+ &.{ ptr_id , len_id },
3686
+ );
3604
3687
}
3605
3688
3606
3689
fn airAggregateInit (self : * DeclGen , inst : Air.Inst.Index ) ! ? IdRef {
@@ -3618,6 +3701,8 @@ const DeclGen = struct {
3618
3701
unreachable ; // TODO
3619
3702
}
3620
3703
3704
+ const types = try self .gpa .alloc (Type , elements .len );
3705
+ defer self .gpa .free (types );
3621
3706
const constituents = try self .gpa .alloc (IdRef , elements .len );
3622
3707
defer self .gpa .free (constituents );
3623
3708
var index : usize = 0 ;
@@ -3629,6 +3714,7 @@ const DeclGen = struct {
3629
3714
assert (Type .fromInterned (field_ty ).hasRuntimeBits (mod ));
3630
3715
3631
3716
const id = try self .resolve (element );
3717
+ types [index ] = Type .fromInterned (field_ty );
3632
3718
constituents [index ] = try self .convertToIndirect (Type .fromInterned (field_ty ), id );
3633
3719
index += 1 ;
3634
3720
}
@@ -3643,14 +3729,19 @@ const DeclGen = struct {
3643
3729
assert (field_ty .hasRuntimeBitsIgnoreComptime (mod ));
3644
3730
3645
3731
const id = try self .resolve (element );
3732
+ types [index ] = field_ty ;
3646
3733
constituents [index ] = try self .convertToIndirect (field_ty , id );
3647
3734
index += 1 ;
3648
3735
}
3649
3736
},
3650
3737
else = > unreachable ,
3651
3738
}
3652
3739
3653
- return try self .constructComposite (result_ty , constituents [0.. index ]);
3740
+ return try self .constructStruct (
3741
+ result_ty ,
3742
+ types [0.. index ],
3743
+ constituents [0.. index ],
3744
+ );
3654
3745
},
3655
3746
.Vector = > {
3656
3747
const n_elems = result_ty .vectorLen (mod );
@@ -3662,7 +3753,7 @@ const DeclGen = struct {
3662
3753
elem_ids [i ] = try self .convertToIndirect (result_ty .childType (mod ), id );
3663
3754
}
3664
3755
3665
- return try self .constructComposite (result_ty , elem_ids );
3756
+ return try self .constructVector (result_ty , elem_ids );
3666
3757
},
3667
3758
.Array = > {
3668
3759
const array_info = result_ty .arrayInfo (mod );
@@ -3679,7 +3770,7 @@ const DeclGen = struct {
3679
3770
elem_ids [n_elems - 1 ] = try self .constant (array_info .elem_type , sentinel_val , .indirect );
3680
3771
}
3681
3772
3682
- return try self .constructComposite (result_ty , elem_ids );
3773
+ return try self .constructArray (result_ty , elem_ids );
3683
3774
},
3684
3775
else = > unreachable ,
3685
3776
}
@@ -4792,7 +4883,11 @@ const DeclGen = struct {
4792
4883
members [eu_layout .errorFieldIndex ()] = operand_id ;
4793
4884
members [eu_layout .payloadFieldIndex ()] = try self .spv .constUndef (payload_ty_ref );
4794
4885
4795
- return try self .constructComposite (err_union_ty , & members );
4886
+ var types : [2 ]Type = undefined ;
4887
+ types [eu_layout .errorFieldIndex ()] = Type .anyerror ;
4888
+ types [eu_layout .payloadFieldIndex ()] = payload_ty ;
4889
+
4890
+ return try self .constructStruct (err_union_ty , & types , & members );
4796
4891
}
4797
4892
4798
4893
fn airWrapErrUnionPayload (self : * DeclGen , inst : Air.Inst.Index ) ! ? IdRef {
@@ -4811,7 +4906,11 @@ const DeclGen = struct {
4811
4906
members [eu_layout .errorFieldIndex ()] = try self .constInt (err_ty_ref , 0 );
4812
4907
members [eu_layout .payloadFieldIndex ()] = try self .convertToIndirect (payload_ty , operand_id );
4813
4908
4814
- return try self .constructComposite (err_union_ty , & members );
4909
+ var types : [2 ]Type = undefined ;
4910
+ types [eu_layout .errorFieldIndex ()] = Type .anyerror ;
4911
+ types [eu_layout .payloadFieldIndex ()] = payload_ty ;
4912
+
4913
+ return try self .constructStruct (err_union_ty , & types , & members );
4815
4914
}
4816
4915
4817
4916
fn airIsNull (self : * DeclGen , inst : Air.Inst.Index , is_pointer : bool , pred : enum { is_null , is_non_null }) ! ? IdRef {
@@ -4978,7 +5077,8 @@ const DeclGen = struct {
4978
5077
4979
5078
const payload_id = try self .convertToIndirect (payload_ty , operand_id );
4980
5079
const members = [_ ]IdRef { payload_id , try self .constBool (true , .indirect ) };
4981
- return try self .constructComposite (optional_ty , & members );
5080
+ const types = [_ ]Type { payload_ty , Type .bool };
5081
+ return try self .constructStruct (optional_ty , & types , & members );
4982
5082
}
4983
5083
4984
5084
fn airSwitchBr (self : * DeclGen , inst : Air.Inst.Index ) ! void {
0 commit comments