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.decl.var; 5 6 import vox.all; 7 8 enum VariableFlags : ushort { 9 forceMemoryStorage = AstFlags.userFlag << 0, 10 isParameter = AstFlags.userFlag << 1, 11 isVariadicParam = AstFlags.userFlag << 2, 12 isAddressTaken = AstFlags.userFlag << 3, 13 isAnonymous = AstFlags.userFlag << 4, 14 } 15 16 @(AstType.decl_var) 17 struct VariableDeclNode 18 { 19 mixin AstNodeData!(AstType.decl_var); 20 ScopeIndex parentScope; 21 AstIndex type; 22 AstIndex initializer; // may be null, stores initializer for variables, default argument for parameters 23 Identifier id; 24 ushort scopeIndex; // stores index of parameter or index of member (for struct fields) 25 // for local vars kind is variable or stackSlot, unique id of variable within a function 26 // for global it is IrValueKind.global 27 // nothing is generated for members 28 ExprValue irValue; 29 IrIndex defaultVal; 30 bool forceMemoryStorage() { return cast(bool)(flags & VariableFlags.forceMemoryStorage); } 31 bool isParameter() { return cast(bool)(flags & VariableFlags.isParameter); } 32 bool isVariadicParam() { return cast(bool)(flags & VariableFlags.isVariadicParam); } 33 bool isAddressTaken() { return cast(bool)(flags & VariableFlags.isAddressTaken); } 34 bool isAnonymous() { return cast(bool)(flags & VariableFlags.isAnonymous); } 35 36 IrIndex getIrIndex(CompilationContext* c) 37 { 38 c.assertf(isGlobal, "Must be used for globals only"); 39 c.assertf(irValue.irValue.isDefined, "Value is undefined"); 40 return irValue.irValue; 41 } 42 } 43 44 void print_var(VariableDeclNode* node, ref AstPrintState state) 45 { 46 state.print( 47 node.isParameter ? "PARAM " : "VAR ", 48 node.type.printer(state.context), " ", state.context.idString(node.id)); 49 if (node.initializer) print_ast(node.initializer, state); 50 } 51 52 void post_clone_var(VariableDeclNode* node, ref CloneState state) 53 { 54 state.fixScope(node.parentScope); 55 state.fixAstIndex(node.type); 56 state.fixAstIndex(node.initializer); 57 } 58 59 void name_register_self_var(AstIndex nodeIndex, VariableDeclNode* node, ref NameRegisterState state) { 60 node.state = AstNodeState.name_register_self; 61 if (!node.isAnonymous) { 62 // registered during expansion in function signature 63 node.parentScope.insert_scope(node.id, nodeIndex, state.context); 64 } 65 node.state = AstNodeState.name_register_self_done; 66 } 67 68 void name_register_nested_var(AstIndex nodeIndex, VariableDeclNode* node, ref NameRegisterState state) { 69 node.state = AstNodeState.name_register_nested; 70 if (node.initializer) require_name_register(node.initializer, state); 71 node.state = AstNodeState.name_register_nested_done; 72 } 73 74 void name_resolve_var(VariableDeclNode* node, ref NameResolveState state) { 75 node.state = AstNodeState.name_resolve; 76 require_name_resolve(node.type, state); 77 if (node.initializer) require_name_resolve(node.initializer, state); 78 node.state = AstNodeState.name_resolve_done; 79 } 80 81 void type_check_var(VariableDeclNode* node, ref TypeCheckState state) 82 { 83 CompilationContext* c = state.context; 84 85 node.state = AstNodeState.type_check; 86 scope (exit) node.state = AstNodeState.type_check_done; 87 88 require_type_check(node.type, state); 89 check_is_type(node.type, c); 90 91 TypeNode* type = node.type.get_type(c); 92 93 if (type.isOpaqueStruct(c)) { 94 if (node.isParameter) { 95 c.error(node.loc, 96 "cannot declare parameter of opaque type `%s`", 97 type.printer(c)); 98 } else { 99 c.error(node.loc, 100 "cannot declare variable `%s` of opaque type `%s`", 101 c.idString(node.id), 102 type.printer(c)); 103 } 104 } 105 106 if (node.initializer) { 107 require_type_check(node.initializer, state); 108 if (type.isAuto) 109 { 110 node.type = node.initializer.get_expr_type(c); 111 } 112 else 113 { 114 bool res = autoconvTo(node.initializer, node.type, c); 115 if (!res) { 116 c.error(node.loc, 117 "cannot convert initializer of type `%s` to `%s`", 118 node.initializer.get_expr_type(c).printer(c), type.printer(c)); 119 } 120 } 121 } 122 123 if (!node.isParameter) 124 { 125 switch (type.astType) with(AstType) 126 { 127 case type_static_array, decl_struct, type_slice: 128 node.flags |= VariableFlags.forceMemoryStorage; 129 break; 130 131 default: break; 132 } 133 } 134 135 if (!node.isLocal) 136 gen_init_value_var(node, c); 137 } 138 139 // only called for members, parameters and globals 140 IrIndex gen_init_value_var(VariableDeclNode* node, CompilationContext* c) 141 { 142 if (node.defaultVal.isDefined) return node.defaultVal; 143 c.assertf(node.isParameter || node.isMember || node.isGlobal, node.loc, "gen_init_value_var"); 144 if (node.initializer) 145 { 146 node.defaultVal = eval_static_expr(node.initializer, c); 147 } 148 else 149 { 150 node.defaultVal = node.type.get_type(c).gen_init_value(c); 151 } 152 return node.defaultVal; 153 } 154 155 void ir_gen_local_var(ref IrGenState gen, IrIndex curBlock, ref IrLabel nextStmt, VariableDeclNode* v) 156 { 157 CompilationContext* c = gen.context; 158 159 if (v.isGlobal) 160 { 161 ir_gen_decl_var(c, v); 162 gen.builder.addJumpToLabel(curBlock, nextStmt); 163 return; 164 } 165 166 TypeNode* varType = c.getAstType(v.type).foldAliases(c); 167 168 IrIndex irType = varType.gen_ir_type(c); 169 170 if (c.buildDebug) 171 v.flags |= VariableFlags.forceMemoryStorage; 172 173 bool needsStackSlot = v.forceMemoryStorage || v.isAddressTaken; 174 175 if (needsStackSlot) 176 { 177 // allocate stack slot 178 IrIndex slot = gen.builder.appendStackSlot(irType, c.types.typeSizeAndAlignment(irType), StackSlotKind.local); 179 v.irValue = ExprValue(slot, ExprValueKind.ptr_to_data, IsLvalue.yes); 180 } 181 else 182 { 183 // allocate new variable 184 v.irValue = ExprValue(gen.builder.newIrVarIndex(irType), ExprValueKind.value, IsLvalue.yes); 185 } 186 187 if (v.isParameter) 188 { 189 ExtraInstrArgs extra = {type : irType}; 190 InstrWithResult param = gen.builder.emitInstr!(IrOpcode.parameter)(gen.ir.entryBasicBlock, extra); 191 gen.ir.get!IrInstr_parameter(param.instruction).index(gen.ir) = v.scopeIndex; 192 v.irValue.store(gen, v.loc, curBlock, param.result); 193 } 194 else 195 { 196 // initialize variable by default or with user-specified value 197 if (v.initializer) 198 { 199 IrLabel afterExpr = IrLabel(curBlock); 200 ExprValue initValue = ir_gen_expr(gen, v.initializer, curBlock, afterExpr); 201 curBlock = afterExpr.blockIndex; 202 IrIndex val = initValue.rvalue(gen, v.loc, curBlock); 203 v.irValue.store(gen, v.loc, curBlock, val); 204 } 205 else 206 { 207 IrIndex value = varType.gen_init_value(c); 208 v.irValue.store(gen, v.loc, curBlock, value); 209 } 210 } 211 212 gen.builder.addJumpToLabel(curBlock, nextStmt); 213 } 214 215 void ir_gen_decl_var(CompilationContext* c, VariableDeclNode* node) 216 { 217 if (node.isGlobal) 218 { 219 if (node.irValue.irValue.isDefined) return; 220 221 // register global variable, type is not set yet 222 IrIndex globalIndex = c.globals.add(); 223 IrGlobal* global = c.globals.get(globalIndex); 224 node.irValue = ExprValue(globalIndex, ExprValueKind.ptr_to_data, IsLvalue.yes); 225 226 AstIndex moduleIndex = find_innermost_owner(node.parentScope, AstType.decl_module, c); 227 228 ObjectSymbol sym = { 229 kind : ObjectSymbolKind.isLocal, 230 sectionIndex : c.builtinSections[ObjectSectionType.rw_data], 231 moduleIndex : moduleIndex.get!ModuleDeclNode(c).objectSymIndex, 232 flags : ObjectSymbolFlags.isMutable, 233 id : node.id, 234 }; 235 236 global.objectSymIndex = c.objSymTab.addSymbol(sym); 237 238 TypeNode* varType = c.getAstType(node.type).foldAliases(c); 239 IrIndex irType = varType.gen_ir_type(c); 240 global.type = c.types.appendPtr(irType); 241 242 SizeAndAlignment valueSizealign = c.types.typeSizeAndAlignment(irType); 243 244 // symbol is created in parser 245 ObjectSymbol* globalSym = c.objSymTab.getSymbol(global.objectSymIndex); 246 globalSym.length = valueSizealign.size; 247 globalSym.alignmentPower = valueSizealign.alignmentPower; 248 249 IrIndex initializer = node.defaultVal; 250 251 if (initializer.isConstantZero) 252 { 253 globalSym.flags |= ObjectSymbolFlags.isAllZero; 254 } 255 else 256 { 257 ubyte[] buffer = c.globals.allocateInitializer(valueSizealign.size); 258 void onGlobal(ubyte[] subbuffer, IrIndex index, CompilationContext* c) 259 { 260 c.assertf(index.isGlobal, "%s is not a constant", index); 261 262 // initialize with 0 263 // generate ObjectSymbolReference for linker to fix 264 subbuffer[] = 0; 265 266 assert(subbuffer.ptr >= buffer.ptr); 267 size_t offset = subbuffer.ptr - buffer.ptr; 268 assert(offset <= uint.max); 269 270 IrGlobal* toGlobal = c.globals.get(index); 271 assert(toGlobal.objectSymIndex.isDefined); 272 273 ObjectSymbolReference r = { 274 fromSymbol : global.objectSymIndex, 275 referencedSymbol : toGlobal.objectSymIndex, 276 refOffset : cast(uint)offset, 277 extraOffset : 0, 278 refKind : ObjectSymbolRefKind.absolute64, 279 }; 280 c.objSymTab.addReference(r); 281 } 282 constantToMem(buffer, initializer, c, &onGlobal); 283 globalSym.setInitializer(buffer); 284 } 285 286 return; 287 } 288 }