@@ -4539,7 +4539,7 @@ pub const FuncGen = struct {
45394539 }
45404540 // We need to emit instructions to check for equality/inequality
45414541 // of optionals that are not pointers.
4542- const is_by_ref = isByRef (operand_ty );
4542+ const is_by_ref = isByRef (scalar_ty );
45434543 const lhs_non_null = self .optIsNonNull (lhs , is_by_ref );
45444544 const rhs_non_null = self .optIsNonNull (rhs , is_by_ref );
45454545 const llvm_i2 = self .context .intType (2 );
@@ -4564,8 +4564,8 @@ pub const FuncGen = struct {
45644564 _ = self .builder .buildBr (end_block );
45654565
45664566 self .builder .positionBuilderAtEnd (both_pl_block );
4567- const lhs_payload = self .optPayloadHandle (lhs , is_by_ref );
4568- const rhs_payload = self .optPayloadHandle (rhs , is_by_ref );
4567+ const lhs_payload = self .optPayloadHandle (lhs , scalar_ty );
4568+ const rhs_payload = self .optPayloadHandle (rhs , scalar_ty );
45694569 const payload_cmp = try self .cmp (lhs_payload , rhs_payload , payload_ty , op );
45704570 _ = self .builder .buildBr (end_block );
45714571 const both_pl_block_end = self .builder .getInsertBlock ();
@@ -5795,7 +5795,7 @@ pub const FuncGen = struct {
57955795 return operand ;
57965796 }
57975797
5798- return self .optPayloadHandle (operand , isByRef ( payload_ty ) );
5798+ return self .optPayloadHandle (operand , optional_ty );
57995799 }
58005800
58015801 fn airErrUnionPayload (
@@ -7347,11 +7347,9 @@ pub const FuncGen = struct {
73477347 }
73487348
73497349 comptime assert (optional_layout_version == 3 );
7350- const optional_llvm_ty = try self . dg . lowerType ( optional_ty );
7350+
73517351 const non_null_bit = self .builder .buildNot (success_bit , "" );
7352- const non_null_field = self .builder .buildZExt (non_null_bit , self .dg .context .intType (8 ), "" );
7353- const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
7354- return self .builder .buildInsertValue (partial , non_null_field , 1 , "" );
7352+ return buildOptional (self , optional_ty , payload , non_null_bit );
73557353 }
73567354
73577355 fn airAtomicRmw (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -7515,11 +7513,13 @@ pub const FuncGen = struct {
75157513 const union_ptr = try self .resolveInst (bin_op .lhs );
75167514 const new_tag = try self .resolveInst (bin_op .rhs );
75177515 if (layout .payload_size == 0 ) {
7516+ // TODO alignment on this store
75187517 _ = self .builder .buildStore (new_tag , union_ptr );
75197518 return null ;
75207519 }
75217520 const tag_index = @boolToInt (layout .tag_align < layout .payload_align );
75227521 const tag_field_ptr = self .builder .buildStructGEP (union_ptr , tag_index , "" );
7522+ // TODO alignment on this store
75237523 _ = self .builder .buildStore (new_tag , tag_field_ptr );
75247524 return null ;
75257525 }
@@ -8355,18 +8355,77 @@ pub const FuncGen = struct {
83558355 }
83568356
83578357 /// Assumes the optional is not pointer-like and payload has bits.
8358- fn optPayloadHandle (self : * FuncGen , opt_handle : * const llvm.Value , is_by_ref : bool ) * const llvm.Value {
8359- if (is_by_ref ) {
8358+ fn optPayloadHandle (
8359+ fg : * FuncGen ,
8360+ opt_handle : * const llvm.Value ,
8361+ opt_ty : Type ,
8362+ ) * const llvm.Value {
8363+ var buf : Type.Payload.ElemType = undefined ;
8364+ const payload_ty = opt_ty .optionalChild (& buf );
8365+
8366+ if (isByRef (opt_ty )) {
83608367 // We have a pointer and we need to return a pointer to the first field.
8361- const index_type = self .context .intType (32 );
8368+ const index_type = fg .context .intType (32 );
83628369 const indices : [2 ]* const llvm.Value = .{
83638370 index_type .constNull (), // dereference the pointer
83648371 index_type .constNull (), // first field is the payload
83658372 };
8366- return self .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8373+ const payload_ptr = fg .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8374+
8375+ if (isByRef (payload_ty )) {
8376+ return payload_ptr ;
8377+ }
8378+ const target = fg .dg .module .getTarget ();
8379+ const payload_alignment = payload_ty .abiAlignment (target );
8380+ const load_inst = fg .builder .buildLoad (payload_ptr , "" );
8381+ load_inst .setAlignment (payload_alignment );
8382+ return load_inst ;
8383+ }
8384+
8385+ assert (! isByRef (payload_ty ));
8386+ return fg .builder .buildExtractValue (opt_handle , 0 , "" );
8387+ }
8388+
8389+ fn buildOptional (
8390+ self : * FuncGen ,
8391+ optional_ty : Type ,
8392+ payload : * const llvm.Value ,
8393+ non_null_bit : * const llvm.Value ,
8394+ ) ! ? * const llvm.Value {
8395+ const optional_llvm_ty = try self .dg .lowerType (optional_ty );
8396+ const non_null_field = self .builder .buildZExt (non_null_bit , self .dg .context .intType (8 ), "" );
8397+
8398+ if (isByRef (optional_ty )) {
8399+ const target = self .dg .module .getTarget ();
8400+ const alloca_inst = self .buildAlloca (optional_llvm_ty );
8401+ const payload_alignment = optional_ty .abiAlignment (target );
8402+ alloca_inst .setAlignment (payload_alignment );
8403+
8404+ const index_type = self .context .intType (32 );
8405+ {
8406+ const indices : [2 ]* const llvm.Value = .{
8407+ index_type .constNull (), // dereference the pointer
8408+ index_type .constNull (), // first field is the payload
8409+ };
8410+ const field_ptr = self .builder .buildInBoundsGEP (alloca_inst , & indices , indices .len , "" );
8411+ const store_inst = self .builder .buildStore (payload , field_ptr );
8412+ store_inst .setAlignment (payload_alignment );
8413+ }
8414+ {
8415+ const indices : [2 ]* const llvm.Value = .{
8416+ index_type .constNull (), // dereference the pointer
8417+ index_type .constInt (1 , .False ), // second field is the non-null bit
8418+ };
8419+ const field_ptr = self .builder .buildInBoundsGEP (alloca_inst , & indices , indices .len , "" );
8420+ const store_inst = self .builder .buildStore (non_null_field , field_ptr );
8421+ store_inst .setAlignment (1 );
8422+ }
8423+
8424+ return alloca_inst ;
83678425 }
83688426
8369- return self .builder .buildExtractValue (opt_handle , 0 , "" );
8427+ const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
8428+ return self .builder .buildInsertValue (partial , non_null_field , 1 , "" );
83708429 }
83718430
83728431 fn fieldPtr (
@@ -9335,7 +9394,18 @@ fn isByRef(ty: Type) bool {
93359394 .ErrorUnion = > return isByRef (ty .errorUnionPayload ()),
93369395 .Optional = > {
93379396 var buf : Type.Payload.ElemType = undefined ;
9338- return isByRef (ty .optionalChild (& buf ));
9397+ const payload_ty = ty .optionalChild (& buf );
9398+ if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
9399+ return false ;
9400+ }
9401+ if (ty .optionalReprIsPayload ()) {
9402+ return false ;
9403+ }
9404+ return true ;
9405+ // TODO we actually want this logic:
9406+ // however it is tripping an LLVM 14 regression:
9407+ // https://github.com/llvm/llvm-project/issues/56585
9408+ //return isByRef(payload_ty);
93399409 },
93409410 }
93419411}
0 commit comments