1 module d.llvm.codegen;
2 
3 import d.ir.expression;
4 import d.ir.symbol;
5 import d.ir.type;
6 
7 import util.visitor;
8 
9 import llvm.c.analysis;
10 import llvm.c.core;
11 import llvm.c.target;
12 
13 // Conflict with Interface in object.di
14 alias Interface = d.ir.symbol.Interface;
15 
16 final class CodeGen {
17 	import source.context;
18 	Context context;
19 	
20 	import d.semantic.scheduler;
21 	Scheduler scheduler;
22 	
23 	import d.object;
24 	ObjectReference object;
25 	
26 	LLVMContextRef llvmCtx;
27 	LLVMModuleRef dmodule;
28 	
29 	LLVMValueRef[ValueSymbol] globals;
30 	
31 	import d.llvm.local;
32 	LocalData localData;
33 	
34 	LLVMTargetDataRef targetData;
35 	
36 	import d.llvm.type;
37 	TypeGenData typeGenData;
38 	
39 	private LLVMValueRef[string] stringLiterals;
40 	
41 	import d.llvm.statement;
42 	StatementGenData statementGenData;
43 	
44 	import d.llvm.intrinsic;
45 	IntrinsicGenData intrinsicGenData;
46 	
47 	LLVMValueRef unlikelyBranch;
48 	uint profKindID;
49 	
50 	// FIXME: We hold a refernece to the backend here so it is not GCed.
51 	// Now that JIT use its own codegen, no reference to the JIT backend
52 	// is held if that one goes. The whole thing needs to be refactored
53 	// in a way that is more sensible.
54 	import d.llvm.backend;
55 	LLVMBackend backend;
56 	
57 	import d.semantic.semantic;
58 	this(SemanticPass sema, string name, LLVMBackend backend, LLVMTargetDataRef targetData) {
59 		this.context   = sema.context;
60 		this.scheduler = sema.scheduler;
61 		this.object    = sema.object;
62 		this.backend   = backend;
63 		
64 		// Make sure globals are initialized.
65 		globals[null] = null;
66 		globals.remove(null);
67 		
68 		llvmCtx = LLVMContextCreate();
69 		
70 		import std.string;
71 		dmodule = LLVMModuleCreateWithNameInContext(name.toStringz(), llvmCtx);
72 		
73 		LLVMSetModuleDataLayout(dmodule, targetData);
74 		this.targetData = LLVMGetModuleDataLayout(dmodule);
75 		
76 		LLVMValueRef[3] branch_metadata;
77 		
78 		auto id = "branch_weights";
79 		branch_metadata[0] = LLVMMDStringInContext(llvmCtx, id.ptr, cast(uint) id.length);
80 		branch_metadata[1] = LLVMConstInt(LLVMInt32TypeInContext(llvmCtx), 65536, false);
81 		branch_metadata[2] = LLVMConstInt(LLVMInt32TypeInContext(llvmCtx), 0, false);
82 		
83 		unlikelyBranch = LLVMMDNodeInContext(llvmCtx, branch_metadata.ptr, cast(uint) branch_metadata.length);
84 		
85 		id = "prof";
86 		profKindID = LLVMGetMDKindIDInContext(llvmCtx, id.ptr, cast(uint) id.length);
87 	}
88 	
89 	~this() {
90 		LLVMDisposeModule(dmodule);
91 		LLVMContextDispose(llvmCtx);
92 	}
93 	
94 	Module visit(Module m) {
95 		// Dump module content on failure (for debug purpose).
96 		scope(failure) LLVMDumpModule(dmodule);
97 		
98 		foreach(s; m.members) {
99 			import d.llvm.global;
100 			GlobalGen(this).define(s);
101 		}
102 		
103 		checkModule();
104 		return m;
105 	}
106 	
107 	auto buildDString(string str) in {
108 		assert(str.length <= uint.max, "string length must be <= uint.max");
109 	} do {
110 		return stringLiterals.get(str, stringLiterals[str] = {
111 			auto cstr = str ~ '\0';
112 			auto charArray = LLVMConstStringInContext(llvmCtx, cstr.ptr, cast(uint) cstr.length, true);
113 			
114 			auto globalVar = LLVMAddGlobal(dmodule, LLVMTypeOf(charArray), ".str");
115 			LLVMSetInitializer(globalVar, charArray);
116 			LLVMSetLinkage(globalVar, LLVMLinkage.Private);
117 			LLVMSetGlobalConstant(globalVar, true);
118 			LLVMSetUnnamedAddr(globalVar, true);
119 			
120 			auto zero = LLVMConstInt(LLVMInt64TypeInContext(llvmCtx), 0, true);
121 			LLVMValueRef[2] indices = [zero, zero];
122 			
123 			LLVMValueRef[2] slice;
124 			slice[0] = LLVMConstInt(LLVMInt64TypeInContext(llvmCtx), str.length, false);
125 			slice[1] = LLVMConstInBoundsGEP(globalVar, indices.ptr, indices.length);
126 			
127 			return LLVMConstStructInContext(llvmCtx, slice.ptr, indices.length, false);
128 		}());
129 	}
130 	
131 	auto checkModule() {
132 		char* msg;
133 		if (LLVMVerifyModule(dmodule, LLVMVerifierFailureAction.ReturnStatus, &msg)) {
134 			scope(exit) LLVMDisposeMessage(msg);
135 			
136 			import core.stdc.string;
137 			auto error = msg[0 .. strlen(msg)].idup;
138 			
139 			throw new Exception(error);
140 		}
141 	}
142 	
143 	auto getAttribute(string name, ulong val = 0) {
144 		auto id = LLVMGetEnumAttributeKindForName(name.ptr, name.length);
145 		return LLVMCreateEnumAttribute(llvmCtx, id, val);
146 	}
147 }