@@ -4539,7 +4539,7 @@ pub const FuncGen = struct {
4539
4539
}
4540
4540
// We need to emit instructions to check for equality/inequality
4541
4541
// of optionals that are not pointers.
4542
- const is_by_ref = isByRef (operand_ty );
4542
+ const is_by_ref = isByRef (scalar_ty );
4543
4543
const lhs_non_null = self .optIsNonNull (lhs , is_by_ref );
4544
4544
const rhs_non_null = self .optIsNonNull (rhs , is_by_ref );
4545
4545
const llvm_i2 = self .context .intType (2 );
@@ -4564,8 +4564,8 @@ pub const FuncGen = struct {
4564
4564
_ = self .builder .buildBr (end_block );
4565
4565
4566
4566
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 );
4569
4569
const payload_cmp = try self .cmp (lhs_payload , rhs_payload , payload_ty , op );
4570
4570
_ = self .builder .buildBr (end_block );
4571
4571
const both_pl_block_end = self .builder .getInsertBlock ();
@@ -4740,12 +4740,14 @@ pub const FuncGen = struct {
4740
4740
const err_set_ty = try fg .dg .lowerType (Type .anyerror );
4741
4741
const zero = err_set_ty .constNull ();
4742
4742
if (! payload_has_bits ) {
4743
+ // TODO add alignment to this load
4743
4744
const loaded = if (operand_is_ptr ) fg .builder .buildLoad (err_union , "" ) else err_union ;
4744
4745
break :err fg .builder .buildICmp (.NE , loaded , zero , "" );
4745
4746
}
4746
4747
const err_field_index = errUnionErrorOffset (payload_ty , target );
4747
4748
if (operand_is_ptr or isByRef (err_union_ty )) {
4748
4749
const err_field_ptr = fg .builder .buildStructGEP (err_union , err_field_index , "" );
4750
+ // TODO add alignment to this load
4749
4751
const loaded = fg .builder .buildLoad (err_field_ptr , "" );
4750
4752
break :err fg .builder .buildICmp (.NE , loaded , zero , "" );
4751
4753
}
@@ -4765,13 +4767,22 @@ pub const FuncGen = struct {
4765
4767
if (! payload_has_bits ) {
4766
4768
if (! operand_is_ptr ) return null ;
4767
4769
4768
- // TODO once we update to LLVM 14 this bitcast won't be necessary.
4770
+ // TODO once we update to an LLVM version with opaque pointers
4771
+ // this bitcast won't be necessary.
4769
4772
const res_ptr_ty = try fg .dg .lowerType (result_ty );
4770
4773
return fg .builder .buildBitCast (err_union , res_ptr_ty , "" );
4771
4774
}
4772
4775
const offset = errUnionPayloadOffset (payload_ty , target );
4773
4776
if (operand_is_ptr or isByRef (payload_ty )) {
4774
4777
return fg .builder .buildStructGEP (err_union , offset , "" );
4778
+ } else if (isByRef (err_union_ty )) {
4779
+ const payload_ptr = fg .builder .buildStructGEP (err_union , offset , "" );
4780
+ if (isByRef (payload_ty )) {
4781
+ return payload_ptr ;
4782
+ }
4783
+ const load_inst = fg .builder .buildLoad (payload_ptr , "" );
4784
+ load_inst .setAlignment (payload_ty .abiAlignment (target ));
4785
+ return load_inst ;
4775
4786
}
4776
4787
return fg .builder .buildExtractValue (err_union , offset , "" );
4777
4788
}
@@ -5730,12 +5741,7 @@ pub const FuncGen = struct {
5730
5741
// The payload and the optional are the same value.
5731
5742
return operand ;
5732
5743
}
5733
- const index_type = self .context .intType (32 );
5734
- const indices : [2 ]* const llvm.Value = .{
5735
- index_type .constNull (), // dereference the pointer
5736
- index_type .constNull (), // first field is the payload
5737
- };
5738
- return self .builder .buildInBoundsGEP (operand , & indices , indices .len , "" );
5744
+ return self .builder .buildStructGEP (operand , 0 , "" );
5739
5745
}
5740
5746
5741
5747
fn airOptionalPayloadPtrSet (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -5761,24 +5767,17 @@ pub const FuncGen = struct {
5761
5767
// Setting to non-null will be done when the payload is set.
5762
5768
return operand ;
5763
5769
}
5764
- const index_type = self .context .intType (32 );
5765
- {
5766
- // First set the non-null bit.
5767
- const indices : [2 ]* const llvm.Value = .{
5768
- index_type .constNull (), // dereference the pointer
5769
- index_type .constInt (1 , .False ), // second field is the non-null bit
5770
- };
5771
- const non_null_ptr = self .builder .buildInBoundsGEP (operand , & indices , indices .len , "" );
5772
- _ = self .builder .buildStore (non_null_bit , non_null_ptr );
5773
- }
5770
+
5771
+ // First set the non-null bit.
5772
+ const non_null_ptr = self .builder .buildStructGEP (operand , 1 , "" );
5773
+ // TODO set alignment on this store
5774
+ _ = self .builder .buildStore (non_null_bit , non_null_ptr );
5775
+
5774
5776
// Then return the payload pointer (only if it's used).
5775
5777
if (self .liveness .isUnused (inst ))
5776
5778
return null ;
5777
- const indices : [2 ]* const llvm.Value = .{
5778
- index_type .constNull (), // dereference the pointer
5779
- index_type .constNull (), // first field is the payload
5780
- };
5781
- return self .builder .buildInBoundsGEP (operand , & indices , indices .len , "" );
5779
+
5780
+ return self .builder .buildStructGEP (operand , 0 , "" );
5782
5781
}
5783
5782
5784
5783
fn airOptionalPayload (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -5795,7 +5794,7 @@ pub const FuncGen = struct {
5795
5794
return operand ;
5796
5795
}
5797
5796
5798
- return self .optPayloadHandle (operand , isByRef ( payload_ty ) );
5797
+ return self .optPayloadHandle (operand , optional_ty );
5799
5798
}
5800
5799
5801
5800
fn airErrUnionPayload (
@@ -5807,6 +5806,8 @@ pub const FuncGen = struct {
5807
5806
5808
5807
const ty_op = self .air .instructions .items (.data )[inst ].ty_op ;
5809
5808
const operand = try self .resolveInst (ty_op .operand );
5809
+ const operand_ty = self .air .typeOf (ty_op .operand );
5810
+ const err_union_ty = if (operand_is_ptr ) operand_ty .childType () else operand_ty ;
5810
5811
const result_ty = self .air .typeOfIndex (inst );
5811
5812
const payload_ty = if (operand_is_ptr ) result_ty .childType () else result_ty ;
5812
5813
const target = self .dg .module .getTarget ();
@@ -5821,6 +5822,14 @@ pub const FuncGen = struct {
5821
5822
const offset = errUnionPayloadOffset (payload_ty , target );
5822
5823
if (operand_is_ptr or isByRef (payload_ty )) {
5823
5824
return self .builder .buildStructGEP (operand , offset , "" );
5825
+ } else if (isByRef (err_union_ty )) {
5826
+ const payload_ptr = self .builder .buildStructGEP (operand , offset , "" );
5827
+ if (isByRef (payload_ty )) {
5828
+ return payload_ptr ;
5829
+ }
5830
+ const load_inst = self .builder .buildLoad (payload_ptr , "" );
5831
+ load_inst .setAlignment (payload_ty .abiAlignment (target ));
5832
+ return load_inst ;
5824
5833
}
5825
5834
return self .builder .buildExtractValue (operand , offset , "" );
5826
5835
}
@@ -5874,16 +5883,11 @@ pub const FuncGen = struct {
5874
5883
_ = self .builder .buildStore (non_error_val , operand );
5875
5884
return operand ;
5876
5885
}
5877
- const index_type = self .context .intType (32 );
5878
5886
const target = self .dg .module .getTarget ();
5879
5887
{
5880
5888
const error_offset = errUnionErrorOffset (payload_ty , target );
5881
5889
// First set the non-error value.
5882
- const indices : [2 ]* const llvm.Value = .{
5883
- index_type .constNull (), // dereference the pointer
5884
- index_type .constInt (error_offset , .False ),
5885
- };
5886
- const non_null_ptr = self .builder .buildInBoundsGEP (operand , & indices , indices .len , "" );
5890
+ const non_null_ptr = self .builder .buildStructGEP (operand , error_offset , "" );
5887
5891
const store_inst = self .builder .buildStore (non_error_val , non_null_ptr );
5888
5892
store_inst .setAlignment (Type .anyerror .abiAlignment (target ));
5889
5893
}
@@ -5892,11 +5896,7 @@ pub const FuncGen = struct {
5892
5896
return null ;
5893
5897
5894
5898
const payload_offset = errUnionPayloadOffset (payload_ty , target );
5895
- const indices : [2 ]* const llvm.Value = .{
5896
- index_type .constNull (), // dereference the pointer
5897
- index_type .constInt (payload_offset , .False ),
5898
- };
5899
- return self .builder .buildInBoundsGEP (operand , & indices , indices .len , "" );
5899
+ return self .builder .buildStructGEP (operand , payload_offset , "" );
5900
5900
}
5901
5901
5902
5902
fn airErrReturnTrace (self : * FuncGen , _ : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -6391,8 +6391,30 @@ pub const FuncGen = struct {
6391
6391
const overflow_bit = self .builder .buildExtractValue (result_struct , 1 , "" );
6392
6392
6393
6393
var ty_buf : Type.Payload.Pointer = undefined ;
6394
- const partial = self .builder .buildInsertValue (llvm_dest_ty .getUndef (), result , llvmFieldIndex (dest_ty , 0 , tg , & ty_buf ).? , "" );
6395
- return self .builder .buildInsertValue (partial , overflow_bit , llvmFieldIndex (dest_ty , 1 , tg , & ty_buf ).? , "" );
6394
+ const result_index = llvmFieldIndex (dest_ty , 0 , tg , & ty_buf ).? ;
6395
+ const overflow_index = llvmFieldIndex (dest_ty , 1 , tg , & ty_buf ).? ;
6396
+
6397
+ if (isByRef (dest_ty )) {
6398
+ const target = self .dg .module .getTarget ();
6399
+ const alloca_inst = self .buildAlloca (llvm_dest_ty );
6400
+ const result_alignment = dest_ty .abiAlignment (target );
6401
+ alloca_inst .setAlignment (result_alignment );
6402
+ {
6403
+ const field_ptr = self .builder .buildStructGEP (alloca_inst , result_index , "" );
6404
+ const store_inst = self .builder .buildStore (result , field_ptr );
6405
+ store_inst .setAlignment (result_alignment );
6406
+ }
6407
+ {
6408
+ const field_ptr = self .builder .buildStructGEP (alloca_inst , overflow_index , "" );
6409
+ const store_inst = self .builder .buildStore (overflow_bit , field_ptr );
6410
+ store_inst .setAlignment (1 );
6411
+ }
6412
+
6413
+ return alloca_inst ;
6414
+ }
6415
+
6416
+ const partial = self .builder .buildInsertValue (llvm_dest_ty .getUndef (), result , result_index , "" );
6417
+ return self .builder .buildInsertValue (partial , overflow_bit , overflow_index , "" );
6396
6418
}
6397
6419
6398
6420
fn buildElementwiseCall (
@@ -6721,8 +6743,30 @@ pub const FuncGen = struct {
6721
6743
const overflow_bit = self .builder .buildICmp (.NE , lhs , reconstructed , "" );
6722
6744
6723
6745
var ty_buf : Type.Payload.Pointer = undefined ;
6724
- const partial = self .builder .buildInsertValue (llvm_dest_ty .getUndef (), result , llvmFieldIndex (dest_ty , 0 , tg , & ty_buf ).? , "" );
6725
- return self .builder .buildInsertValue (partial , overflow_bit , llvmFieldIndex (dest_ty , 1 , tg , & ty_buf ).? , "" );
6746
+ const result_index = llvmFieldIndex (dest_ty , 0 , tg , & ty_buf ).? ;
6747
+ const overflow_index = llvmFieldIndex (dest_ty , 1 , tg , & ty_buf ).? ;
6748
+
6749
+ if (isByRef (dest_ty )) {
6750
+ const target = self .dg .module .getTarget ();
6751
+ const alloca_inst = self .buildAlloca (llvm_dest_ty );
6752
+ const result_alignment = dest_ty .abiAlignment (target );
6753
+ alloca_inst .setAlignment (result_alignment );
6754
+ {
6755
+ const field_ptr = self .builder .buildStructGEP (alloca_inst , result_index , "" );
6756
+ const store_inst = self .builder .buildStore (result , field_ptr );
6757
+ store_inst .setAlignment (result_alignment );
6758
+ }
6759
+ {
6760
+ const field_ptr = self .builder .buildStructGEP (alloca_inst , overflow_index , "" );
6761
+ const store_inst = self .builder .buildStore (overflow_bit , field_ptr );
6762
+ store_inst .setAlignment (1 );
6763
+ }
6764
+
6765
+ return alloca_inst ;
6766
+ }
6767
+
6768
+ const partial = self .builder .buildInsertValue (llvm_dest_ty .getUndef (), result , result_index , "" );
6769
+ return self .builder .buildInsertValue (partial , overflow_bit , overflow_index , "" );
6726
6770
}
6727
6771
6728
6772
fn airAnd (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -7347,11 +7391,9 @@ pub const FuncGen = struct {
7347
7391
}
7348
7392
7349
7393
comptime assert (optional_layout_version == 3 );
7350
- const optional_llvm_ty = try self . dg . lowerType ( optional_ty );
7394
+
7351
7395
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 , "" );
7396
+ return buildOptional (self , optional_ty , payload , non_null_bit );
7355
7397
}
7356
7398
7357
7399
fn airAtomicRmw (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -7515,11 +7557,13 @@ pub const FuncGen = struct {
7515
7557
const union_ptr = try self .resolveInst (bin_op .lhs );
7516
7558
const new_tag = try self .resolveInst (bin_op .rhs );
7517
7559
if (layout .payload_size == 0 ) {
7560
+ // TODO alignment on this store
7518
7561
_ = self .builder .buildStore (new_tag , union_ptr );
7519
7562
return null ;
7520
7563
}
7521
7564
const tag_index = @boolToInt (layout .tag_align < layout .payload_align );
7522
7565
const tag_field_ptr = self .builder .buildStructGEP (union_ptr , tag_index , "" );
7566
+ // TODO alignment on this store
7523
7567
_ = self .builder .buildStore (new_tag , tag_field_ptr );
7524
7568
return null ;
7525
7569
}
@@ -8336,17 +8380,9 @@ pub const FuncGen = struct {
8336
8380
fn optIsNonNull (self : * FuncGen , opt_handle : * const llvm.Value , is_by_ref : bool ) * const llvm.Value {
8337
8381
const field = b : {
8338
8382
if (is_by_ref ) {
8339
- const index_type = self .context .intType (32 );
8340
-
8341
- const indices : [2 ]* const llvm.Value = .{
8342
- index_type .constNull (),
8343
- index_type .constInt (1 , .False ),
8344
- };
8345
-
8346
- const field_ptr = self .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8383
+ const field_ptr = self .builder .buildStructGEP (opt_handle , 1 , "" );
8347
8384
break :b self .builder .buildLoad (field_ptr , "" );
8348
8385
}
8349
-
8350
8386
break :b self .builder .buildExtractValue (opt_handle , 1 , "" );
8351
8387
};
8352
8388
comptime assert (optional_layout_version == 3 );
@@ -8355,18 +8391,63 @@ pub const FuncGen = struct {
8355
8391
}
8356
8392
8357
8393
/// 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 ) {
8394
+ fn optPayloadHandle (
8395
+ fg : * FuncGen ,
8396
+ opt_handle : * const llvm.Value ,
8397
+ opt_ty : Type ,
8398
+ ) * const llvm.Value {
8399
+ var buf : Type.Payload.ElemType = undefined ;
8400
+ const payload_ty = opt_ty .optionalChild (& buf );
8401
+
8402
+ if (isByRef (opt_ty )) {
8360
8403
// We have a pointer and we need to return a pointer to the first field.
8361
- const index_type = self .context .intType (32 );
8362
- const indices : [2 ]* const llvm.Value = .{
8363
- index_type .constNull (), // dereference the pointer
8364
- index_type .constNull (), // first field is the payload
8365
- };
8366
- return self .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8404
+ const payload_ptr = fg .builder .buildStructGEP (opt_handle , 0 , "" );
8405
+
8406
+ if (isByRef (payload_ty )) {
8407
+ return payload_ptr ;
8408
+ }
8409
+ const target = fg .dg .module .getTarget ();
8410
+ const payload_alignment = payload_ty .abiAlignment (target );
8411
+ const load_inst = fg .builder .buildLoad (payload_ptr , "" );
8412
+ load_inst .setAlignment (payload_alignment );
8413
+ return load_inst ;
8414
+ }
8415
+
8416
+ assert (! isByRef (payload_ty ));
8417
+ return fg .builder .buildExtractValue (opt_handle , 0 , "" );
8418
+ }
8419
+
8420
+ fn buildOptional (
8421
+ self : * FuncGen ,
8422
+ optional_ty : Type ,
8423
+ payload : * const llvm.Value ,
8424
+ non_null_bit : * const llvm.Value ,
8425
+ ) ! ? * const llvm.Value {
8426
+ const optional_llvm_ty = try self .dg .lowerType (optional_ty );
8427
+ const non_null_field = self .builder .buildZExt (non_null_bit , self .dg .context .intType (8 ), "" );
8428
+
8429
+ if (isByRef (optional_ty )) {
8430
+ const target = self .dg .module .getTarget ();
8431
+ const alloca_inst = self .buildAlloca (optional_llvm_ty );
8432
+ const payload_alignment = optional_ty .abiAlignment (target );
8433
+ alloca_inst .setAlignment (payload_alignment );
8434
+
8435
+ {
8436
+ const field_ptr = self .builder .buildStructGEP (alloca_inst , 0 , "" );
8437
+ const store_inst = self .builder .buildStore (payload , field_ptr );
8438
+ store_inst .setAlignment (payload_alignment );
8439
+ }
8440
+ {
8441
+ const field_ptr = self .builder .buildStructGEP (alloca_inst , 1 , "" );
8442
+ const store_inst = self .builder .buildStore (non_null_field , field_ptr );
8443
+ store_inst .setAlignment (1 );
8444
+ }
8445
+
8446
+ return alloca_inst ;
8367
8447
}
8368
8448
8369
- return self .builder .buildExtractValue (opt_handle , 0 , "" );
8449
+ const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
8450
+ return self .builder .buildInsertValue (partial , non_null_field , 1 , "" );
8370
8451
}
8371
8452
8372
8453
fn fieldPtr (
@@ -9275,10 +9356,12 @@ fn ccAbiPromoteInt(
9275
9356
return null ;
9276
9357
}
9277
9358
9359
+ /// This is the one source of truth for whether a type is passed around as an LLVM pointer,
9360
+ /// or as an LLVM value.
9278
9361
fn isByRef (ty : Type ) bool {
9279
9362
// For tuples and structs, if there are more than this many non-void
9280
9363
// fields, then we make it byref, otherwise byval.
9281
- const max_fields_byval = 2 ;
9364
+ const max_fields_byval = 0 ;
9282
9365
9283
9366
switch (ty .zigTypeTag ()) {
9284
9367
.Type ,
@@ -9332,10 +9415,23 @@ fn isByRef(ty: Type) bool {
9332
9415
return false ;
9333
9416
},
9334
9417
.Union = > return ty .hasRuntimeBits (),
9335
- .ErrorUnion = > return isByRef (ty .errorUnionPayload ()),
9418
+ .ErrorUnion = > {
9419
+ const payload_ty = ty .errorUnionPayload ();
9420
+ if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
9421
+ return false ;
9422
+ }
9423
+ return true ;
9424
+ },
9336
9425
.Optional = > {
9337
9426
var buf : Type.Payload.ElemType = undefined ;
9338
- return isByRef (ty .optionalChild (& buf ));
9427
+ const payload_ty = ty .optionalChild (& buf );
9428
+ if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
9429
+ return false ;
9430
+ }
9431
+ if (ty .optionalReprIsPayload ()) {
9432
+ return false ;
9433
+ }
9434
+ return true ;
9339
9435
},
9340
9436
}
9341
9437
}
0 commit comments