@@ -4538,7 +4538,7 @@ pub const FuncGen = struct {
45384538 }
45394539 // We need to emit instructions to check for equality/inequality
45404540 // of optionals that are not pointers.
4541- const is_by_ref = isByRef (operand_ty );
4541+ const is_by_ref = isByRef (scalar_ty );
45424542 const lhs_non_null = self .optIsNonNull (lhs , is_by_ref );
45434543 const rhs_non_null = self .optIsNonNull (rhs , is_by_ref );
45444544 const llvm_i2 = self .context .intType (2 );
@@ -4563,8 +4563,8 @@ pub const FuncGen = struct {
45634563 _ = self .builder .buildBr (end_block );
45644564
45654565 self .builder .positionBuilderAtEnd (both_pl_block );
4566- const lhs_payload = self .optPayloadHandle (lhs , is_by_ref );
4567- const rhs_payload = self .optPayloadHandle (rhs , is_by_ref );
4566+ const lhs_payload = self .optPayloadHandle (lhs , scalar_ty );
4567+ const rhs_payload = self .optPayloadHandle (rhs , scalar_ty );
45684568 const payload_cmp = try self .cmp (lhs_payload , rhs_payload , payload_ty , op );
45694569 _ = self .builder .buildBr (end_block );
45704570 const both_pl_block_end = self .builder .getInsertBlock ();
@@ -5794,7 +5794,7 @@ pub const FuncGen = struct {
57945794 return operand ;
57955795 }
57965796
5797- return self .optPayloadHandle (operand , isByRef ( payload_ty ) );
5797+ return self .optPayloadHandle (operand , optional_ty );
57985798 }
57995799
58005800 fn airErrUnionPayload (
@@ -7345,10 +7345,8 @@ pub const FuncGen = struct {
73457345 return self .builder .buildSelect (success_bit , payload .typeOf ().constNull (), payload , "" );
73467346 }
73477347
7348- const optional_llvm_ty = try self .dg .lowerType (optional_ty );
73497348 const non_null_bit = self .builder .buildNot (success_bit , "" );
7350- const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
7351- return self .builder .buildInsertValue (partial , non_null_bit , 1 , "" );
7349+ return buildOptional (self , optional_ty , payload , non_null_bit );
73527350 }
73537351
73547352 fn airAtomicRmw (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -7512,11 +7510,13 @@ pub const FuncGen = struct {
75127510 const union_ptr = try self .resolveInst (bin_op .lhs );
75137511 const new_tag = try self .resolveInst (bin_op .rhs );
75147512 if (layout .payload_size == 0 ) {
7513+ // TODO alignment on this store
75157514 _ = self .builder .buildStore (new_tag , union_ptr );
75167515 return null ;
75177516 }
75187517 const tag_index = @boolToInt (layout .tag_align < layout .payload_align );
75197518 const tag_field_ptr = self .builder .buildStructGEP (union_ptr , tag_index , "" );
7519+ // TODO alignment on this store
75207520 _ = self .builder .buildStore (new_tag , tag_field_ptr );
75217521 return null ;
75227522 }
@@ -8347,18 +8347,76 @@ pub const FuncGen = struct {
83478347 }
83488348
83498349 /// Assumes the optional is not pointer-like and payload has bits.
8350- fn optPayloadHandle (self : * FuncGen , opt_handle : * const llvm.Value , is_by_ref : bool ) * const llvm.Value {
8351- if (is_by_ref ) {
8350+ fn optPayloadHandle (
8351+ fg : * FuncGen ,
8352+ opt_handle : * const llvm.Value ,
8353+ opt_ty : Type ,
8354+ ) * const llvm.Value {
8355+ var buf : Type.Payload.ElemType = undefined ;
8356+ const payload_ty = opt_ty .optionalChild (& buf );
8357+
8358+ if (isByRef (opt_ty )) {
83528359 // We have a pointer and we need to return a pointer to the first field.
8353- const index_type = self .context .intType (32 );
8360+ const index_type = fg .context .intType (32 );
83548361 const indices : [2 ]* const llvm.Value = .{
83558362 index_type .constNull (), // dereference the pointer
83568363 index_type .constNull (), // first field is the payload
83578364 };
8358- return self .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8365+ const payload_ptr = fg .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8366+
8367+ if (isByRef (payload_ty )) {
8368+ return payload_ptr ;
8369+ }
8370+ const target = fg .dg .module .getTarget ();
8371+ const payload_alignment = payload_ty .abiAlignment (target );
8372+ const load_inst = fg .builder .buildLoad (payload_ptr , "" );
8373+ load_inst .setAlignment (payload_alignment );
8374+ return load_inst ;
8375+ }
8376+
8377+ assert (! isByRef (payload_ty ));
8378+ return fg .builder .buildExtractValue (opt_handle , 0 , "" );
8379+ }
8380+
8381+ fn buildOptional (
8382+ self : * FuncGen ,
8383+ optional_ty : Type ,
8384+ payload : * const llvm.Value ,
8385+ non_null_bit : * const llvm.Value ,
8386+ ) ! ? * const llvm.Value {
8387+ const optional_llvm_ty = try self .dg .lowerType (optional_ty );
8388+
8389+ if (isByRef (optional_ty )) {
8390+ const target = self .dg .module .getTarget ();
8391+ const alloca_inst = self .buildAlloca (optional_llvm_ty );
8392+ const payload_alignment = optional_ty .abiAlignment (target );
8393+ alloca_inst .setAlignment (payload_alignment );
8394+
8395+ const index_type = self .context .intType (32 );
8396+ {
8397+ const indices : [2 ]* const llvm.Value = .{
8398+ index_type .constNull (), // dereference the pointer
8399+ index_type .constNull (), // first field is the payload
8400+ };
8401+ const field_ptr = self .builder .buildInBoundsGEP (alloca_inst , & indices , indices .len , "" );
8402+ const store_inst = self .builder .buildStore (payload , field_ptr );
8403+ store_inst .setAlignment (payload_alignment );
8404+ }
8405+ {
8406+ const indices : [2 ]* const llvm.Value = .{
8407+ index_type .constNull (), // dereference the pointer
8408+ index_type .constInt (1 , .False ), // second field is the non-null bit
8409+ };
8410+ const field_ptr = self .builder .buildInBoundsGEP (alloca_inst , & indices , indices .len , "" );
8411+ const store_inst = self .builder .buildStore (non_null_bit , field_ptr );
8412+ store_inst .setAlignment (1 );
8413+ }
8414+
8415+ return alloca_inst ;
83598416 }
83608417
8361- return self .builder .buildExtractValue (opt_handle , 0 , "" );
8418+ const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
8419+ return self .builder .buildInsertValue (partial , non_null_bit , 1 , "" );
83628420 }
83638421
83648422 fn fieldPtr (
@@ -9327,7 +9385,18 @@ fn isByRef(ty: Type) bool {
93279385 .ErrorUnion = > return isByRef (ty .errorUnionPayload ()),
93289386 .Optional = > {
93299387 var buf : Type.Payload.ElemType = undefined ;
9330- return isByRef (ty .optionalChild (& buf ));
9388+ const payload_ty = ty .optionalChild (& buf );
9389+ if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
9390+ return false ;
9391+ }
9392+ if (ty .optionalReprIsPayload ()) {
9393+ return false ;
9394+ }
9395+ return true ;
9396+ // TODO we actually want this logic:
9397+ // however it is tripping an LLVM 14 regression:
9398+ // https://github.com/llvm/llvm-project/issues/56585
9399+ //return isByRef(payload_ty);
93319400 },
93329401 }
93339402}
0 commit comments