1 /// Copyright: Copyright (c) 2017-2019 Andrey Penechko.
2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
3 /// Authors: Andrey Penechko.
4 module vox.fe.ast.expr.slice;
5 
6 import vox.all;
7 
8 
9 @(AstType.expr_slice)
10 struct SliceExprNode {
11 	mixin ExpressionNodeData!(AstType.expr_slice);
12 	AstIndex array;
13 	AstIndex fromIndex;
14 	AstIndex toIndex;
15 }
16 
17 void print_expr_slice(SliceExprNode* node, ref AstPrintState state)
18 {
19 	state.print("SLICE");
20 	print_ast(node.array, state);
21 	print_ast(node.fromIndex, state);
22 	print_ast(node.toIndex, state);
23 }
24 
25 void post_clone_expr_slice(SliceExprNode* node, ref CloneState state)
26 {
27 	state.fixAstIndex(node.array);
28 	state.fixAstIndex(node.fromIndex);
29 	state.fixAstIndex(node.toIndex);
30 }
31 
32 void name_register_nested_expr_slice(SliceExprNode* node, ref NameRegisterState state) {
33 	node.state = AstNodeState.name_register_nested;
34 	require_name_register(node.array, state);
35 	require_name_register(node.fromIndex, state);
36 	require_name_register(node.toIndex, state);
37 	node.state = AstNodeState.name_register_nested_done;
38 }
39 
40 void name_resolve_expr_slice(SliceExprNode* node, ref NameResolveState state)
41 {
42 	CompilationContext* c = state.context;
43 
44 	node.state = AstNodeState.name_resolve;
45 	require_name_resolve(node.array, state);
46 	require_name_resolve(node.fromIndex, state);
47 	require_name_resolve(node.toIndex, state);
48 	node.state = AstNodeState.name_resolve_done;
49 }
50 
51 void type_check_expr_slice(SliceExprNode* node, ref TypeCheckState state)
52 {
53 	CompilationContext* c = state.context;
54 
55 	node.state = AstNodeState.type_check;
56 	node.array.flags(c) |= AstFlags.isLvalue;
57 	require_type_check(node.array, state);
58 	require_type_check(node.fromIndex, state);
59 	autoconvTo(node.fromIndex, CommonAstNodes.type_i64, c);
60 	require_type_check(node.toIndex, state);
61 	autoconvTo(node.toIndex, CommonAstNodes.type_i64, c);
62 	switch (node.array.get_expr_type(c).astType(c)) with(AstType)
63 	{
64 		case type_ptr, type_static_array:
65 			AstIndex elemType = node.array.get_expr_type(c).get_type(c).getElementType(c);
66 			node.type = c.appendAst!SliceTypeNode(node.loc, CommonAstNodes.type_type, elemType);
67 			break;
68 		case type_slice:
69 			node.type = node.array.get_expr_type(c);
70 			break;
71 		default: c.internal_error("Cannot slice value of type `%s`", node.array.get_expr_type(c).printer(c));
72 	}
73 	node.state = AstNodeState.type_check_done;
74 }
75 
76 ExprValue ir_gen_expr_slice(ref IrGenState gen, IrIndex curBlock, ref IrLabel nextStmt, SliceExprNode* node)
77 {
78 	CompilationContext* c = gen.context;
79 	ExpressionNode* arrayExpr = node.array.get_expr(c);
80 
81 	IrLabel afterFrom = IrLabel(curBlock);
82 	ExprValue fromIndexLvalue = ir_gen_expr(gen, node.fromIndex, curBlock, afterFrom);
83 	curBlock = afterFrom.blockIndex;
84 	IrIndex fromIndexRvalue = fromIndexLvalue.rvalue(gen, node.loc, curBlock);
85 
86 	IrLabel afterTo = IrLabel(curBlock);
87 	ExprValue toIndexLvalue = ir_gen_expr(gen, node.toIndex, curBlock, afterTo);
88 	curBlock = afterTo.blockIndex;
89 	IrIndex toIndexRvalue = toIndexLvalue.rvalue(gen, node.loc, curBlock);
90 
91 	IrLabel afterArray = IrLabel(curBlock);
92 	ExprValue arrayLvalue = ir_gen_expr(gen, node.array, curBlock, afterArray);
93 	curBlock = afterArray.blockIndex;
94 
95 	IrIndex aggregateIndex = c.constants.addZeroConstant(makeIrType(IrBasicType.i32));
96 	IrIndex slicePtrIndex = c.constants.add(makeIrType(IrBasicType.i32), 1);
97 
98 	AstType astType = arrayExpr.type.get_type(c).astType;
99 	IrIndex ptr; // pointer to first element
100 	IrIndex length; // slice length
101 
102 	if (fromIndexRvalue.isSimpleConstant && c.constants.get(fromIndexRvalue).i64 == 0)
103 	{
104 		// special case for array[0..to];
105 		ptr = arrayLvalue.irValue;
106 		switch (astType) with(AstType)
107 		{
108 			case type_ptr:
109 				// read pointer variable for T*
110 				ptr = arrayLvalue.rvalue(gen, node.loc, curBlock);
111 				break;
112 			case type_static_array:
113 				// need to convert [n x T]* into T* for static arrays
114 				IrIndex ZERO = c.constants.addZeroConstant(makeIrType(IrBasicType.i32));
115 				ptr = buildGEP(gen, node.loc, curBlock, ptr, ZERO, ZERO);
116 				break;
117 			case type_slice:
118 				ExprValue ptrLvalue = arrayLvalue.member(gen, node.loc, curBlock, slicePtrIndex);
119 				ptr = ptrLvalue.rvalue(gen, node.loc, curBlock);
120 				break;
121 			default: assert(false);
122 		}
123 		length = toIndexRvalue;
124 	}
125 	else
126 	{
127 		switch (astType) with(AstType)
128 		{
129 			case type_ptr:
130 				ptr = buildGEP(gen, node.loc, curBlock, arrayLvalue.irValue, fromIndexRvalue);
131 				break;
132 			case type_static_array:
133 				IrIndex ZERO = c.constants.addZeroConstant(makeIrType(IrBasicType.i32));
134 				ptr = buildGEP(gen, node.loc, curBlock, arrayLvalue.irValue, ZERO, fromIndexRvalue);
135 				break;
136 			case type_slice:
137 				ExprValue ptrLvalue = arrayLvalue.member(gen, node.loc, curBlock, slicePtrIndex);
138 				ptr = ptrLvalue.rvalue(gen, node.loc, curBlock);
139 				ptr = buildGEP(gen, node.loc, curBlock, ptr, fromIndexRvalue);
140 				break;
141 			default: assert(false);
142 		}
143 
144 		ExtraInstrArgs extra1 = {
145 			type : makeIrType(IrBasicType.i64),
146 			argSize : IrArgSize.size64
147 		};
148 		length = gen.builder.emitInstr!(IrOpcode.sub)(curBlock, extra1, toIndexRvalue, fromIndexRvalue).result;
149 	}
150 	//writefln("len %s, ptr %s", length, ptr);
151 	// combine into slice {u64, T*}
152 	IrIndex resType = node.type.gen_ir_type(c);
153 	ExtraInstrArgs extra = { type : resType };
154 	InstrWithResult res = gen.builder.emitInstr!(IrOpcode.create_aggregate)(curBlock, extra, length, ptr);
155 	gen.builder.addJumpToLabel(curBlock, nextStmt);
156 	return ExprValue(res.result);
157 }