Browse code

Support building w/o atomic builtins for i386 (bb #1781).

Wrap all LLVM API calls with a single mutex when LLVM doesn't have multithreaded
mode.
Also fallback to interpreter mode on i386 and i486.

Török Edvin authored on 2010/01/26 19:40:18
Showing 1 changed files
... ...
@@ -45,6 +45,7 @@
45 45
 #include "llvm/Support/IRBuilder.h"
46 46
 #include "llvm/Support/PrettyStackTrace.h"
47 47
 #include "llvm/System/DataTypes.h"
48
+#include "llvm/System/Host.h"
48 49
 #include "llvm/System/Mutex.h"
49 50
 #include "llvm/System/Signals.h"
50 51
 #include "llvm/System/Threading.h"
... ...
@@ -60,8 +61,8 @@
60 60
 #include <new>
61 61
 
62 62
 #include "llvm/Config/config.h"
63
-#if !defined(LLVM_MULTITHREADED) || !LLVM_MULTITHREADED
64
-#error "Multithreading support must be available to LLVM!"
63
+#if !ENABLE_THREADS
64
+#error "Thread support was explicitly disabled. Cannot continue"
65 65
 #endif
66 66
 
67 67
 #ifdef HAVE_CONFIG_H
... ...
@@ -1211,11 +1212,33 @@ public:
1211 1211
 	return true;
1212 1212
     }
1213 1213
 };
1214
+
1215
+static sys::Mutex llvm_api_lock;
1216
+
1217
+// This class automatically acquires the lock when instantiated,
1218
+// and releases the lock when leaving scope.
1219
+class LLVMApiScopedLock {
1220
+    public:
1221
+	// when multithreaded mode is false (no atomics available),
1222
+	// we need to wrap all LLVM API calls with a giant mutex lock, but
1223
+	// only then.
1224
+	LLVMApiScopedLock() {
1225
+	    if (!llvm_is_multithreaded())
1226
+		llvm_api_lock.acquire();
1227
+	}
1228
+	~LLVMApiScopedLock() {
1229
+	    if (!llvm_is_multithreaded())
1230
+		llvm_api_lock.release();
1231
+	}
1232
+};
1233
+
1214 1234
 }
1215 1235
 
1216 1236
 int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx,
1217 1237
 		       const struct cli_bc_func *func)
1218 1238
 {
1239
+    // no locks needed here, since LLVM automatically acquires a JIT lock
1240
+    // if needed.
1219 1241
     jmp_buf env;
1220 1242
     void *code = bcs->engine->compiledFunctions[func];
1221 1243
     if (!code) {
... ...
@@ -1259,6 +1282,7 @@ int cli_bytecode_prepare_jit(struct cli_all_bc *bcs)
1259 1259
   if (!bcs->engine)
1260 1260
       return CL_EBYTECODE;
1261 1261
   jmp_buf env;
1262
+  LLVMApiScopedLock scopedLock;
1262 1263
   // setup exception handler to longjmp back here
1263 1264
   ExceptionReturn.set((const jmp_buf*)&env);
1264 1265
   if (setjmp(env) != 0) {
... ...
@@ -1386,8 +1410,10 @@ int cli_bytecode_prepare_jit(struct cli_all_bc *bcs)
1386 1386
 int bytecode_init(void)
1387 1387
 {
1388 1388
     // If already initialized return
1389
-    if (llvm_is_multithreaded())
1390
-	return 0;
1389
+    if (llvm_is_multithreaded()) {
1390
+	errs() << "bytecode_init: already initialized";
1391
+	return CL_EARG;
1392
+    }
1391 1393
     llvm_install_error_handler(llvm_error_handler);
1392 1394
 #ifdef CL_DEBUG
1393 1395
     sys::PrintStackTraceOnErrorSignal();
... ...
@@ -1407,13 +1433,28 @@ int bytecode_init(void)
1407 1407
     // If we have a native target, initialize it to ensure it is linked in and
1408 1408
     // usable by the JIT.
1409 1409
     InitializeNativeTarget();
1410
+
1411
+    if (!llvm_is_multithreaded()) {
1412
+	//TODO:cli_dbgmsg
1413
+	DEBUG(errs() << "WARNING: ClamAV JIT built w/o atomic builtins\n"
1414
+	      << "On x86 for best performance ClamAV should be built for i686, not i386!\n");
1415
+    }
1410 1416
     return 0;
1411 1417
 }
1412 1418
 
1413 1419
 // Called once when loading a new set of BC files
1414 1420
 int cli_bytecode_init_jit(struct cli_all_bc *bcs)
1415 1421
 {
1416
-    //TODO: if !llvm_is_multi...
1422
+    LLVMApiScopedLock scopedLock;
1423
+    std::string cpu = sys::getHostCPUName();
1424
+    DEBUG(errs() << "host cpu is: " << cpu << "\n");
1425
+    if (!cpu.compare("i386") ||
1426
+	!cpu.compare("i486")) {
1427
+	bcs->engine = 0;
1428
+	DEBUG(errs() << "i[34]86 detected, falling back to interpreter (JIT needs pentium or better\n");
1429
+	/* i386 and i486 has to fallback to interpreter */
1430
+	return 0;
1431
+    }
1417 1432
     bcs->engine = new(std::nothrow) cli_bcengine;
1418 1433
     if (!bcs->engine)
1419 1434
 	return CL_EMEM;
... ...
@@ -1423,6 +1464,7 @@ int cli_bytecode_init_jit(struct cli_all_bc *bcs)
1423 1423
 
1424 1424
 int cli_bytecode_done_jit(struct cli_all_bc *bcs)
1425 1425
 {
1426
+    LLVMApiScopedLock scopedLock;
1426 1427
     if (bcs->engine) {
1427 1428
 	if (bcs->engine->EE)
1428 1429
 	    delete bcs->engine->EE;