1 /**
2 Copyright: Copyright (c) 2017-2019 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 /// IR global. Stores info about global variables, string/array/struct literals.
7 module vox.ir.ir_global;
8 
9 import vox.all;
10 
11 enum IrGlobalFlags : uint {
12 	isMutable = 1 << 0,
13 	isAllZero = 1 << 1,
14 	needsZeroTermination = 1 << 2,
15 	/// Global data is copied into static data buffer (or zeroes are reserved for isAllZero)
16 	/// If (and only if) set, then staticBufferOffset must be valid
17 	isInBuffer = 1 << 3,
18 	isString   = 1 << 4,
19 }
20 
21 ///
22 @(IrValueKind.global)
23 struct IrGlobal
24 {
25 	/// Type of global. Must be a pointer type
26 	IrIndex type;
27 	uint numUsers;
28 	LinkIndex objectSymIndex;
29 	//bool isMutable() { return (flags & IrGlobalFlags.isMutable) != 0; }
30 	//bool isAllZero() { return (flags & IrGlobalFlags.isAllZero) != 0; }
31 	//bool needsZeroTermination() { return (flags & IrGlobalFlags.needsZeroTermination) != 0; }
32 	//bool isInBuffer() { return (flags & IrGlobalFlags.isInBuffer) != 0; }
33 	//bool isString() { return (flags & IrGlobalFlags.isString) != 0; }
34 
35 	void addUser(IrIndex user) { ++numUsers; }
36 	void removeUser(IrIndex user) { --numUsers; }
37 }
38 
39 ///
40 struct IrGlobalStorage
41 {
42 	Arena!IrGlobal buffer;
43 	Arena!ubyte initializerBuffer;
44 
45 	private IrIndex f32_sign_bit_constant;
46 	private IrIndex f64_sign_bit_constant;
47 
48 	IrIndex get_or_add_f32_sign_bit_constant(CompilationContext* c) {
49 		if (f32_sign_bit_constant.isDefined) return f32_sign_bit_constant;
50 
51 		IrIndex type = makeIrType(IrBasicType.f32);
52 		ubyte[16] buf;
53 		(cast(uint[])buf[])[] = 0x80000000;
54 
55 		f32_sign_bit_constant = add_float_sign_bit_constant(type, buf[], c);
56 
57 		return f32_sign_bit_constant;
58 	}
59 
60 	IrIndex get_or_add_f64_sign_bit_constant(CompilationContext* c) {
61 		if (f64_sign_bit_constant.isDefined) return f64_sign_bit_constant;
62 
63 		IrIndex type = makeIrType(IrBasicType.f64);
64 		ubyte[16] buf;
65 		(cast(ulong[])buf[])[] = 0x8000000000000000;
66 
67 		f64_sign_bit_constant = add_float_sign_bit_constant(type, buf[], c);
68 
69 		return f64_sign_bit_constant;
70 	}
71 
72 	// Creates a bit pattern constant that is used to flip a bit sign of xmm register
73 	private IrIndex add_float_sign_bit_constant(IrIndex type, ubyte[] initializer, CompilationContext* c) {
74 		IrIndex globalIndex = add();
75 		IrGlobal* global = get(globalIndex);
76 		global.type = c.types.appendPtr(type);
77 
78 		ObjectSymbol sym = {
79 			kind : ObjectSymbolKind.isLocal,
80 			sectionIndex : c.builtinSections[ObjectSectionType.ro_data],
81 			moduleIndex : c.builtinModuleIndex,
82 			flags : ObjectSymbolFlags.isFloat,
83 			id : c.idMap.getOrReg(c, ":float"),
84 		};
85 		global.objectSymIndex = c.objSymTab.addSymbol(sym);
86 
87 		ObjectSymbol* globalSym = c.objSymTab.getSymbol(global.objectSymIndex);
88 		globalSym.alignmentPower = 4;
89 
90 		SizeAndAlignment valueSizealign = c.types.typeSizeAndAlignment(type);
91 		ubyte[] buffer = c.globals.allocateInitializer(16);
92 		buffer[] = initializer;
93 		globalSym.setInitializer(buffer);
94 
95 		return globalIndex;
96 	}
97 
98 	///
99 	IrIndex add()
100 	{
101 		IrIndex globalIndex = IrIndex(cast(uint)buffer.length, IrValueKind.global);
102 		buffer.put(IrGlobal());
103 		return globalIndex;
104 	}
105 
106 	/// Allocate space for compiletime generated initializers (struct initializers for example)
107 	/// String literals without escape sequences are sliced directly from source code
108 	ubyte[] allocateInitializer(uint length)
109 	{
110 		return initializerBuffer.voidPut(length);
111 	}
112 
113 	///
114 	IrGlobal* get(IrIndex index)
115 	{
116 		assert(index.kind == IrValueKind.global);
117 		assert(index.storageUintIndex < buffer.length);
118 		return &buffer.data[index.storageUintIndex];
119 	}
120 }