summaryrefslogtreecommitdiffstats
path: root/contrib/restricted/wavm/Lib/LLVMJIT/EmitVar.cpp
blob: e7e2512983a29eb5af6456d2e7110ec5fa0c049e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <vector>
#include "EmitFunctionContext.h"
#include "EmitModuleContext.h"
#include "LLVMJITPrivate.h"
#include "WAVM/IR/Module.h"
#include "WAVM/IR/Operators.h"
#include "WAVM/IR/Types.h"
#include "WAVM/Inline/Assert.h"

PUSH_DISABLE_WARNINGS_FOR_LLVM_HEADERS
#include <llvm/IR/Constant.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/Type.h>
#include <llvm/IR/Value.h>
POP_DISABLE_WARNINGS_FOR_LLVM_HEADERS

using namespace WAVM;
using namespace WAVM::IR;
using namespace WAVM::LLVMJIT;

//
// Local variables
//

void EmitFunctionContext::local_get(GetOrSetVariableImm<false> imm)
{
	WAVM_ASSERT(imm.variableIndex < localPointers.size());
	push(irBuilder.CreateLoad(
		localPointerElementTypes[imm.variableIndex],
		localPointers[imm.variableIndex]));
}
void EmitFunctionContext::local_set(GetOrSetVariableImm<false> imm)
{
	WAVM_ASSERT(imm.variableIndex < localPointers.size());
	auto value = irBuilder.CreateBitCast(
		pop(), localPointerElementTypes[imm.variableIndex]);
	irBuilder.CreateStore(value, localPointers[imm.variableIndex]);
}
void EmitFunctionContext::local_tee(GetOrSetVariableImm<false> imm)
{
	WAVM_ASSERT(imm.variableIndex < localPointers.size());
	auto value = irBuilder.CreateBitCast(
		getValueFromTop(), localPointerElementTypes[imm.variableIndex]);
	irBuilder.CreateStore(value, localPointers[imm.variableIndex]);
}

//
// Global variables
//

static llvm::Value* getImportedImmutableGlobalValue(EmitFunctionContext& functionContext,
													Uptr importedGlobalIndex,
													ValueType valueType)
{
	// The symbol for an imported global will point to the global's immutable value.
	return functionContext.loadFromUntypedPointer(
		functionContext.moduleContext.globals[importedGlobalIndex],
		asLLVMType(functionContext.llvmContext, valueType),
		getTypeByteWidth(valueType));
}

void EmitFunctionContext::global_get(GetOrSetVariableImm<true> imm)
{
	WAVM_ASSERT(imm.variableIndex < irModule.globals.size());
	GlobalType globalType = irModule.globals.getType(imm.variableIndex);

	llvm::Value* value = nullptr;
	if(globalType.isMutable)
	{
		// If the global is mutable, the symbol will be bound to an offset into the
		// ContextRuntimeData::globalData that its value is stored at.
		llvm::Value* globalDataOffset = irBuilder.CreatePtrToInt(
			moduleContext.globals[imm.variableIndex], moduleContext.iptrType);
		llvm::Value* globalPointer = irBuilder.CreateInBoundsGEP(
			llvmContext.i8Type, irBuilder.CreateLoad(llvmContext.i8PtrType, contextPointerVariable), {globalDataOffset});
		value = loadFromUntypedPointer(globalPointer,
									   asLLVMType(llvmContext, globalType.valueType),
									   getTypeByteWidth(globalType.valueType));
	}
	else if(!irModule.globals.isDef(imm.variableIndex))
	{
		value = getImportedImmutableGlobalValue(*this, imm.variableIndex, globalType.valueType);
	}
	else
	{
		// If the value is an immutable global definition, emit its literal value.
		const IR::GlobalDef& globalDef = irModule.globals.getDef(imm.variableIndex);

		switch(globalDef.initializer.type)
		{
		case InitializerExpression::Type::i32_const:
			value = emitLiteral(llvmContext, globalDef.initializer.i32);
			break;
		case InitializerExpression::Type::i64_const:
			value = emitLiteral(llvmContext, globalDef.initializer.i64);
			break;
		case InitializerExpression::Type::f32_const:
			value = emitLiteral(llvmContext, globalDef.initializer.f32);
			break;
		case InitializerExpression::Type::f64_const:
			value = emitLiteral(llvmContext, globalDef.initializer.f64);
			break;
		case InitializerExpression::Type::v128_const:
			value = emitLiteral(llvmContext, globalDef.initializer.v128);
			break;
		case InitializerExpression::Type::global_get: {
			const Uptr importedGlobalIndex = globalDef.initializer.ref;
			WAVM_ASSERT(!irModule.globals.isDef(importedGlobalIndex));
			WAVM_ASSERT(!irModule.globals.getType(importedGlobalIndex).isMutable);
			value
				= getImportedImmutableGlobalValue(*this, importedGlobalIndex, globalType.valueType);
			break;
		}
		case InitializerExpression::Type::ref_null:
			value = llvm::Constant::getNullValue(llvmContext.externrefType);
			break;
		case InitializerExpression::Type::ref_func: {
			llvm::Value* referencedFunction = moduleContext.functions[globalDef.initializer.ref];
			llvm::Value* codeAddress
				= irBuilder.CreatePtrToInt(referencedFunction, moduleContext.iptrType);
			llvm::Value* functionAddress = irBuilder.CreateSub(
				codeAddress,
				emitLiteralIptr(offsetof(Runtime::Function, code), moduleContext.iptrType));
			llvm::Value* externref
				= irBuilder.CreateIntToPtr(functionAddress, llvmContext.externrefType);
			value = externref;
			break;
		}

		case InitializerExpression::Type::invalid:
		default: WAVM_UNREACHABLE();
		};
	}

	push(value);
}
void EmitFunctionContext::global_set(GetOrSetVariableImm<true> imm)
{
	WAVM_ASSERT(imm.variableIndex < irModule.globals.size());
	GlobalType globalType = irModule.globals.getType(imm.variableIndex);
	WAVM_ASSERT(globalType.isMutable);
	llvm::Type* llvmValueType = asLLVMType(llvmContext, globalType.valueType);

	llvm::Value* value = irBuilder.CreateBitCast(pop(), llvmValueType);

	// If the global is mutable, the symbol will be bound to an offset into the
	// ContextRuntimeData::globalData that its value is stored at.
	llvm::Value* globalDataOffset = irBuilder.CreatePtrToInt(
		moduleContext.globals[imm.variableIndex], moduleContext.iptrType);
	llvm::Value* globalPointer = irBuilder.CreateInBoundsGEP(
		llvmContext.i8Type, irBuilder.CreateLoad(llvmContext.i8PtrType, contextPointerVariable), {globalDataOffset});
	storeToUntypedPointer(value, globalPointer);
}