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 }