| ... | @@ -397,6 +397,7 @@ pub const LLVMIRModule = struct { | ... | @@ -397,6 +397,7 @@ pub const LLVMIRModule = struct { |
| 397 | .block => try self.genBlock(inst.castTag(.block).?), | 397 | .block => try self.genBlock(inst.castTag(.block).?), |
| 398 | .br => try self.genBr(inst.castTag(.br).?), | 398 | .br => try self.genBr(inst.castTag(.br).?), |
| 399 | .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?), | 399 | .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?), |
| | 400 | .br_void => try self.genBrVoid(inst.castTag(.br_void).?), |
| 400 | .call => try self.genCall(inst.castTag(.call).?), | 401 | .call => try self.genCall(inst.castTag(.call).?), |
| 401 | .cmp_eq => try self.genCmp(inst.castTag(.cmp_eq).?, .eq), | 402 | .cmp_eq => try self.genCmp(inst.castTag(.cmp_eq).?, .eq), |
| 402 | .cmp_gt => try self.genCmp(inst.castTag(.cmp_gt).?, .gt), | 403 | .cmp_gt => try self.genCmp(inst.castTag(.cmp_gt).?, .gt), |
| ... | @@ -406,6 +407,10 @@ pub const LLVMIRModule = struct { | ... | @@ -406,6 +407,10 @@ pub const LLVMIRModule = struct { |
| 406 | .cmp_neq => try self.genCmp(inst.castTag(.cmp_neq).?, .neq), | 407 | .cmp_neq => try self.genCmp(inst.castTag(.cmp_neq).?, .neq), |
| 407 | .condbr => try self.genCondBr(inst.castTag(.condbr).?), | 408 | .condbr => try self.genCondBr(inst.castTag(.condbr).?), |
| 408 | .intcast => try self.genIntCast(inst.castTag(.intcast).?), | 409 | .intcast => try self.genIntCast(inst.castTag(.intcast).?), |
| | 410 | .is_non_null => try self.genIsNonNull(inst.castTag(.is_non_null).?, false), |
| | 411 | .is_non_null_ptr => try self.genIsNonNull(inst.castTag(.is_non_null_ptr).?, true), |
| | 412 | .is_null => try self.genIsNull(inst.castTag(.is_null).?, false), |
| | 413 | .is_null_ptr => try self.genIsNull(inst.castTag(.is_null_ptr).?, true), |
| 409 | .load => try self.genLoad(inst.castTag(.load).?), | 414 | .load => try self.genLoad(inst.castTag(.load).?), |
| 410 | .loop => try self.genLoop(inst.castTag(.loop).?), | 415 | .loop => try self.genLoop(inst.castTag(.loop).?), |
| 411 | .not => try self.genNot(inst.castTag(.not).?), | 416 | .not => try self.genNot(inst.castTag(.not).?), |
| ... | @@ -414,6 +419,8 @@ pub const LLVMIRModule = struct { | ... | @@ -414,6 +419,8 @@ pub const LLVMIRModule = struct { |
| 414 | .store => try self.genStore(inst.castTag(.store).?), | 419 | .store => try self.genStore(inst.castTag(.store).?), |
| 415 | .sub => try self.genSub(inst.castTag(.sub).?), | 420 | .sub => try self.genSub(inst.castTag(.sub).?), |
| 416 | .unreach => self.genUnreach(inst.castTag(.unreach).?), | 421 | .unreach => self.genUnreach(inst.castTag(.unreach).?), |
| | 422 | .optional_payload => try self.genOptionalPayload(inst.castTag(.optional_payload).?, false), |
| | 423 | .optional_payload_ptr => try self.genOptionalPayload(inst.castTag(.optional_payload_ptr).?, true), |
| 417 | .dbg_stmt => blk: { | 424 | .dbg_stmt => blk: { |
| 418 | // TODO: implement debug info | 425 | // TODO: implement debug info |
| 419 | break :blk null; | 426 | break :blk null; |
| ... | @@ -534,21 +541,29 @@ pub const LLVMIRModule = struct { | ... | @@ -534,21 +541,29 @@ pub const LLVMIRModule = struct { |
| 534 | } | 541 | } |
| 535 | | 542 | |
| 536 | fn genBr(self: *LLVMIRModule, inst: *Inst.Br) !?*const llvm.Value { | 543 | fn genBr(self: *LLVMIRModule, inst: *Inst.Br) !?*const llvm.Value { |
| 537 | // Get the block that we want to break to. | | |
| 538 | var block = self.blocks.get(inst.block).?; | 544 | var block = self.blocks.get(inst.block).?; |
| 539 | _ = self.builder.buildBr(block.parent_bb); | | |
| 540 | | 545 | |
| 541 | // If the break doesn't break a value, then we don't have to add | 546 | // If the break doesn't break a value, then we don't have to add |
| 542 | // the values to the lists. | 547 | // the values to the lists. |
| 543 | if (!inst.operand.ty.hasCodeGenBits()) return null; | 548 | if (!inst.operand.ty.hasCodeGenBits()) { |
| | 549 | // TODO: in astgen these instructions should turn into `br_void` instructions. |
| | 550 | _ = self.builder.buildBr(block.parent_bb); |
| | 551 | } else { |
| | 552 | const val = try self.resolveInst(inst.operand); |
| 544 | | 553 | |
| 545 | // For the phi node, we need the basic blocks and the values of the | 554 | // For the phi node, we need the basic blocks and the values of the |
| 546 | // break instructions. | 555 | // break instructions. |
| 547 | try block.break_bbs.append(self.gpa, self.builder.getInsertBlock()); | 556 | try block.break_bbs.append(self.gpa, self.builder.getInsertBlock()); |
| | 557 | try block.break_vals.append(self.gpa, val); |
| 548 | | 558 | |
| 549 | const val = try self.resolveInst(inst.operand); | 559 | _ = self.builder.buildBr(block.parent_bb); |
| 550 | try block.break_vals.append(self.gpa, val); | 560 | } |
| | 561 | return null; |
| | 562 | } |
| 551 | | 563 | |
| | 564 | fn genBrVoid(self: *LLVMIRModule, inst: *Inst.BrVoid) !?*const llvm.Value { |
| | 565 | var block = self.blocks.get(inst.block).?; |
| | 566 | _ = self.builder.buildBr(block.parent_bb); |
| 552 | return null; | 567 | return null; |
| 553 | } | 568 | } |
| 554 | | 569 | |
| ... | @@ -591,6 +606,44 @@ pub const LLVMIRModule = struct { | ... | @@ -591,6 +606,44 @@ pub const LLVMIRModule = struct { |
| 591 | return null; | 606 | return null; |
| 592 | } | 607 | } |
| 593 | | 608 | |
| | 609 | fn genIsNonNull(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value { |
| | 610 | const operand = try self.resolveInst(inst.operand); |
| | 611 | |
| | 612 | if (operand_is_ptr) { |
| | 613 | const index_type = self.context.intType(32); |
| | 614 | |
| | 615 | var indices: [2]*const llvm.Value = .{ |
| | 616 | index_type.constNull(), |
| | 617 | index_type.constInt(1, false), |
| | 618 | }; |
| | 619 | |
| | 620 | return self.builder.buildLoad(self.builder.buildInBoundsGEP(operand, &indices, 2, ""), ""); |
| | 621 | } else { |
| | 622 | return self.builder.buildExtractValue(operand, 1, ""); |
| | 623 | } |
| | 624 | } |
| | 625 | |
| | 626 | fn genIsNull(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value { |
| | 627 | return self.builder.buildNot((try self.genIsNonNull(inst, operand_is_ptr)).?, ""); |
| | 628 | } |
| | 629 | |
| | 630 | fn genOptionalPayload(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value { |
| | 631 | const operand = try self.resolveInst(inst.operand); |
| | 632 | |
| | 633 | if (operand_is_ptr) { |
| | 634 | const index_type = self.context.intType(32); |
| | 635 | |
| | 636 | var indices: [2]*const llvm.Value = .{ |
| | 637 | index_type.constNull(), |
| | 638 | index_type.constNull(), |
| | 639 | }; |
| | 640 | |
| | 641 | return self.builder.buildInBoundsGEP(operand, &indices, 2, ""); |
| | 642 | } else { |
| | 643 | return self.builder.buildExtractValue(operand, 0, ""); |
| | 644 | } |
| | 645 | } |
| | 646 | |
| 594 | fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value { | 647 | fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value { |
| 595 | const lhs = try self.resolveInst(inst.lhs); | 648 | const lhs = try self.resolveInst(inst.lhs); |
| 596 | const rhs = try self.resolveInst(inst.rhs); | 649 | const rhs = try self.resolveInst(inst.rhs); |
| ... | @@ -751,6 +804,13 @@ pub const LLVMIRModule = struct { | ... | @@ -751,6 +804,13 @@ pub const LLVMIRModule = struct { |
| 751 | // TODO: consider using buildInBoundsGEP2 for opaque pointers | 804 | // TODO: consider using buildInBoundsGEP2 for opaque pointers |
| 752 | return self.builder.buildInBoundsGEP(val, &indices, 2, ""); | 805 | return self.builder.buildInBoundsGEP(val, &indices, 2, ""); |
| 753 | }, | 806 | }, |
| | 807 | .ref_val => { |
| | 808 | const elem_value = tv.val.castTag(.ref_val).?.data; |
| | 809 | const elem_type = tv.ty.castPointer().?.data; |
| | 810 | const alloca = self.buildAlloca(try self.getLLVMType(elem_type, src)); |
| | 811 | _ = self.builder.buildStore(try self.genTypedValue(src, .{ .ty = elem_type, .val = elem_value }), alloca); |
| | 812 | return alloca; |
| | 813 | }, |
| 754 | else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}), | 814 | else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}), |
| 755 | }, | 815 | }, |
| 756 | .Array => { | 816 | .Array => { |
| ... | @@ -765,6 +825,29 @@ pub const LLVMIRModule = struct { | ... | @@ -765,6 +825,29 @@ pub const LLVMIRModule = struct { |
| 765 | return self.fail(src, "TODO handle more array values", .{}); | 825 | return self.fail(src, "TODO handle more array values", .{}); |
| 766 | } | 826 | } |
| 767 | }, | 827 | }, |
| | 828 | .Optional => { |
| | 829 | if (!tv.ty.isPtrLikeOptional()) { |
| | 830 | var buf: Type.Payload.ElemType = undefined; |
| | 831 | const child_type = tv.ty.optionalChild(&buf); |
| | 832 | const llvm_child_type = try self.getLLVMType(child_type, src); |
| | 833 | |
| | 834 | if (tv.val.tag() == .null_value) { |
| | 835 | var optional_values: [2]*const llvm.Value = .{ |
| | 836 | llvm_child_type.constNull(), |
| | 837 | self.context.intType(1).constNull(), |
| | 838 | }; |
| | 839 | return self.context.constStruct(&optional_values, 2, false); |
| | 840 | } else { |
| | 841 | var optional_values: [2]*const llvm.Value = .{ |
| | 842 | try self.genTypedValue(src, .{ .ty = child_type, .val = tv.val }), |
| | 843 | self.context.intType(1).constAllOnes(), |
| | 844 | }; |
| | 845 | return self.context.constStruct(&optional_values, 2, false); |
| | 846 | } |
| | 847 | } else { |
| | 848 | return self.fail(src, "TODO implement const of optional pointer", .{}); |
| | 849 | } |
| | 850 | }, |
| 768 | else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}), | 851 | else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}), |
| 769 | } | 852 | } |
| 770 | } | 853 | } |
| ... | @@ -790,6 +873,20 @@ pub const LLVMIRModule = struct { | ... | @@ -790,6 +873,20 @@ pub const LLVMIRModule = struct { |
| 790 | const elem_type = try self.getLLVMType(t.elemType(), src); | 873 | const elem_type = try self.getLLVMType(t.elemType(), src); |
| 791 | return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget()))); | 874 | return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget()))); |
| 792 | }, | 875 | }, |
| | 876 | .Optional => { |
| | 877 | if (!t.isPtrLikeOptional()) { |
| | 878 | var buf: Type.Payload.ElemType = undefined; |
| | 879 | const child_type = t.optionalChild(&buf); |
| | 880 | |
| | 881 | var optional_types: [2]*const llvm.Type = .{ |
| | 882 | try self.getLLVMType(child_type, src), |
| | 883 | self.context.intType(1), |
| | 884 | }; |
| | 885 | return self.context.structType(&optional_types, 2, false); |
| | 886 | } else { |
| | 887 | return self.fail(src, "TODO implement optional pointers as actual pointers", .{}); |
| | 888 | } |
| | 889 | }, |
| 793 | else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}), | 890 | else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}), |
| 794 | } | 891 | } |
| 795 | } | 892 | } |