Reactor: Copy new debug macros to Reactor.

Fix up all calls to `assert()` in [LLVM,Subzero]Reactor.cpp with an appropriate call to one of these macros.

Bug: b/127433389
Change-Id: I188add3929c46932b8de5acf2ac4b2ac83b0768b
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29055
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Reactor/Debug.cpp b/src/Reactor/Debug.cpp
index adfcabd..7f0d2cd 100644
--- a/src/Reactor/Debug.cpp
+++ b/src/Reactor/Debug.cpp
@@ -14,26 +14,61 @@
 
 #include "Debug.hpp"
 
-#include <stdio.h>
+#include <string>
 #include <stdarg.h>
 
 namespace rr
 {
-void trace(const char *format, ...)
+
+void tracev(const char *format, va_list args)
 {
+#ifndef RR_DISABLE_TRACE
 	if(false)
 	{
-		FILE *file = fopen("debug.txt", "a");
+		FILE *file = fopen(TRACE_OUTPUT_FILE, "a");
 
 		if(file)
 		{
-			va_list vararg;
-			va_start(vararg, format);
-			vfprintf(file, format, vararg);
-			va_end(vararg);
-
+			vfprintf(file, format, args);
 			fclose(file);
 		}
 	}
+#endif
 }
-}
\ No newline at end of file
+
+void trace(const char *format, ...)
+{
+	va_list vararg;
+	va_start(vararg, format);
+	tracev(format, vararg);
+	va_end(vararg);
+}
+
+void warn(const char *format, ...)
+{
+	va_list vararg;
+	va_start(vararg, format);
+	tracev(format, vararg);
+	va_end(vararg);
+
+	va_start(vararg, format);
+	vfprintf(stderr, format, vararg);
+	va_end(vararg);
+}
+
+void abort(const char *format, ...)
+{
+	va_list vararg;
+
+	va_start(vararg, format);
+	tracev(format, vararg);
+	va_end(vararg);
+
+	va_start(vararg, format);
+	vfprintf(stderr, format, vararg);
+	va_end(vararg);
+
+	::abort();
+}
+
+} // namespace rr
diff --git a/src/Reactor/Debug.hpp b/src/Reactor/Debug.hpp
index 9df0b38..d2b3a1f 100644
--- a/src/Reactor/Debug.hpp
+++ b/src/Reactor/Debug.hpp
@@ -12,41 +12,100 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef Debug_hpp
-#define Debug_hpp
+// debug.h: Debugging utilities.
 
-#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
-#include "DebugAndroid.hpp"
-#else
+#ifndef rr_DEBUG_H_
+#define rr_DEBUG_H_
 
+#include <stdlib.h>
 #include <assert.h>
 #include <stdio.h>
 
-#undef min
-#undef max
+#if !defined(TRACE_OUTPUT_FILE)
+#define TRACE_OUTPUT_FILE "debug.txt"
+#endif
 
 namespace rr
 {
-void trace(const char *format, ...);
+	// Outputs text to the debugging log
+	void trace(const char *format, ...);
+	inline void trace() {}
 
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-	#define TRACE(format, ...) trace("[0x%0.8X]%s(" format ")\n", this, __FUNCTION__, ##__VA_ARGS__)
-#else
-	#define TRACE(...) ((void)0)
-#endif
+	// Outputs text to the debugging log and prints to stderr.
+	void warn(const char *format, ...);
+	inline void warn() {}
 
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-	#define UNIMPLEMENTED() {trace("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); ASSERT(false);}
-#else
-	#define UNIMPLEMENTED() ((void)0)
-#endif
-
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-	#define ASSERT(expression) {if(!(expression)) trace("\t! Assert failed in %s(%d): " #expression "\n", __FUNCTION__, __LINE__); assert(expression);}
-#else
-	#define ASSERT assert
-#endif
+	// Outputs the message to the debugging log and stderr, and calls abort().
+	void abort(const char *format, ...);
 }
 
-#endif   // __ANDROID__
-#endif   // Debug_hpp
+// A macro to output a trace of a function call and its arguments to the
+// debugging log. Disabled if RR_DISABLE_TRACE is defined.
+#if defined(RR_DISABLE_TRACE)
+#define TRACE(message, ...) (void(0))
+#else
+#define TRACE(message, ...) rr::trace("%s:%d TRACE: " message "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+#endif
+
+// A macro to print a warning message to the debugging log and stderr to denote
+// an issue that needs fixing.
+#define FIXME(message, ...) rr::warn("%s:%d FIXME: " message "\n", __FILE__, __LINE__, ##__VA_ARGS__);
+
+// A macro to print a warning message to the debugging log and stderr.
+#define WARN(message, ...) rr::warn("%s:%d WARNING: " message "\n", __FILE__, __LINE__, ##__VA_ARGS__);
+
+// A macro that prints the message to the debugging log and stderr and
+// immediately aborts execution of the application.
+//
+// Note: This will terminate the application regardless of build flags!
+//       Use with extreme caution!
+#undef ABORT
+#define ABORT(message, ...) rr::abort("%s:%d ABORT: " message "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+
+// A macro that delegates to:
+//   ABORT() in debug builds (!NDEBUG || DCHECK_ALWAYS_ON)
+// or
+//   WARN() in release builds (NDEBUG && !DCHECK_ALWAYS_ON)
+#undef DABORT
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define DABORT(message, ...) ABORT(message, ##__VA_ARGS__)
+#else
+#define DABORT(message, ...) WARN(message, ##__VA_ARGS__)
+#endif
+
+// A macro asserting a condition.
+// If the condition fails, the condition and message is passed to DABORT().
+#undef ASSERT_MSG
+#define ASSERT_MSG(expression, format, ...) do { \
+	if(!(expression)) { \
+		DABORT("ASSERT(%s): " format "\n", #expression, ##__VA_ARGS__); \
+	} } while(0)
+
+// A macro asserting a condition.
+// If the condition fails, the condition is passed to DABORT().
+#undef ASSERT
+#define ASSERT(expression) do { \
+	if(!(expression)) { \
+		DABORT("ASSERT(%s)\n", #expression); \
+	} } while(0)
+
+// A macro to indicate unimplemented functionality.
+#undef UNIMPLEMENTED
+#define UNIMPLEMENTED(format, ...) DABORT("UNIMPLEMENTED: " format, ##__VA_ARGS__)
+
+// A macro for code which is not expected to be reached under valid assumptions.
+#undef UNREACHABLE
+#define UNREACHABLE(format, ...) DABORT("UNREACHABLE: " format, ##__VA_ARGS__)
+
+// A macro asserting a condition and performing a return.
+#undef ASSERT_OR_RETURN
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define ASSERT_OR_RETURN(expression) ASSERT(expression)
+#else
+#define ASSERT_OR_RETURN(expression) do { \
+	if(!(expression)) { \
+		return; \
+	} } while(0)
+#endif
+
+#endif   // rr_DEBUG_H_
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 418e66d..2069a77 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "Reactor.hpp"
+#include "Debug.hpp"
 
 #include "x86.hpp"
 #include "CPUID.hpp"
@@ -92,7 +93,7 @@
 #if defined(__x86_64__) && defined(_WIN32)
 extern "C" void X86CompilationCallback()
 {
-	assert(false);   // UNIMPLEMENTED
+	UNIMPLEMENTED("X86CompilationCallback");
 }
 #endif
 
@@ -235,7 +236,7 @@
 		}
 		else
 		{
-			assert(numBits <= 64);
+			ASSERT_MSG(numBits <= 64, "numBits: %d", int(numBits));
 			uint64_t maxVal = (numBits == 64) ? ~0ULL : (1ULL << numBits) - 1;
 			max = llvm::ConstantInt::get(extTy, maxVal, false);
 			min = llvm::ConstantInt::get(extTy, 0, false);
@@ -361,7 +362,7 @@
 			llvm::cast<llvm::IntegerType>(dstTy->getElementType());
 
 		uint64_t truncNumBits = dstElemTy->getIntegerBitWidth();
-		assert(truncNumBits < 64 && "shift 64 must be handled separately");
+		ASSERT_MSG(truncNumBits < 64, "shift 64 must be handled separately. truncNumBits: %d", int(truncNumBits));
 		llvm::Constant *max, *min;
 		if (isSigned)
 		{
@@ -530,7 +531,7 @@
 					case SCCP:                 passManager->add(llvm::createSCCPPass());                 break;
 					case ScalarReplAggregates: passManager->add(llvm::createScalarReplAggregatesPass()); break;
 					default:
-						assert(false);
+						UNREACHABLE("optimization[pass]: %d, pass: %d", int(optimization[pass]), int(pass));
 					}
 				}
 			}
@@ -588,7 +589,8 @@
 			while (trimmed[0] == '_') { trimmed++; }
 
 			FunctionMap::const_iterator it = func_.find(trimmed);
-			assert(it != func_.end()); // Missing functions will likely make the module fail in exciting non-obvious ways.
+			// Missing functions will likely make the module fail in exciting non-obvious ways.
+			ASSERT_MSG(it != func_.end(), "Missing external function: '%s'", name.c_str());
 			return it->second;
 		}
 	};
@@ -713,7 +715,7 @@
 				case SCCP:                 passManager->add(llvm::createSCCPPass());                 break;
 				case ScalarReplAggregates: passManager->add(llvm::createSROAPass());                 break;
 				default:
-				                           assert(false);
+					UNREACHABLE("optimization[pass]: %d, pass: %d", int(optimization[pass]), int(pass));
 				}
 			}
 
@@ -773,7 +775,9 @@
 		case Type_v4i8:  return T(Byte16::getType());
 		case Type_v2f32: return T(Float4::getType());
 		case Type_LLVM:  return reinterpret_cast<llvm::Type*>(t);
-		default: assert(false); return nullptr;
+		default:
+			UNREACHABLE("asInternalType(t): %d", int(asInternalType(t)));
+			return nullptr;
 		}
 	}
 
@@ -833,7 +837,7 @@
 
 				// At this point we should only have LLVM 'primitive' types.
 				unsigned int bits = t->getPrimitiveSizeInBits();
-				assert(bits != 0);
+				ASSERT_MSG(bits != 0, "bits: %d", int(bits));
 
 				// TODO(capn): Booleans are 1 bit integers in LLVM's SSA type system,
 				// but are typically stored as one byte. The DataLayout structure should
@@ -842,7 +846,7 @@
 			}
 			break;
 		default:
-			assert(false);
+			UNREACHABLE("asInternalType(type): %d", int(asInternalType(type)));
 			return 0;
 		}
 	}
@@ -858,7 +862,9 @@
 		case Type_v4i8:  return 4;
 		case Type_v2f32: return 2;
 		case Type_LLVM:  return llvm::cast<llvm::VectorType>(T(type))->getNumElements();
-		default: assert(false); return 0;
+		default:
+			UNREACHABLE("asInternalType(type): %d", int(asInternalType(type)));
+			return 0;
 		}
 	}
 
@@ -881,7 +887,9 @@
 		case std::memory_order_release: return llvm::AtomicOrdering::Release;
 		case std::memory_order_acq_rel: return llvm::AtomicOrdering::AcquireRelease;
 		case std::memory_order_seq_cst: return llvm::AtomicOrdering::SequentiallyConsistent;
-		default: assert(false);         return llvm::AtomicOrdering::AcquireRelease;
+		default:
+			UNREACHABLE("memoryOrder: %d", int(memoryOrder));
+			return llvm::AtomicOrdering::AcquireRelease;
 		}
 	}
 
@@ -1281,14 +1289,15 @@
 			// Fallthrough to non-emulated case.
 		case Type_LLVM:
 			{
-				assert(V(ptr)->getType()->getContainedType(0) == T(type));
+				ASSERT(V(ptr)->getType()->getContainedType(0) == T(type));
 				auto load = new llvm::LoadInst(V(ptr), "", isVolatile, alignment);
 				load->setAtomic(atomicOrdering(atomic, memoryOrder));
 
 				return V(::builder->Insert(load));
 			}
 		default:
-			assert(false); return nullptr;
+			UNREACHABLE("asInternalType(type): %d", int(asInternalType(type)));
+			return nullptr;
 		}
 	}
 
@@ -1319,20 +1328,21 @@
 			// Fallthrough to non-emulated case.
 		case Type_LLVM:
 			{
-				assert(V(ptr)->getType()->getContainedType(0) == T(type));
+				ASSERT(V(ptr)->getType()->getContainedType(0) == T(type));
 				auto store = ::builder->Insert(new llvm::StoreInst(V(value), V(ptr), isVolatile, alignment));
 				store->setAtomic(atomicOrdering(atomic, memoryOrder));
 
 				return value;
 			}
 		default:
-			assert(false); return nullptr;
+			UNREACHABLE("asInternalType(type): %d", int(asInternalType(type)));
+			return nullptr;
 		}
 	}
 
 	Value *Nucleus::createGEP(Value *ptr, Type *type, Value *index, bool unsignedIndex)
 	{
-		assert(V(ptr)->getType()->getContainedType(0) == T(type));
+		ASSERT(V(ptr)->getType()->getContainedType(0) == T(type));
 
 		if(sizeof(void*) == 8)
 		{
@@ -1559,7 +1569,7 @@
 
 	Value *Nucleus::createExtractElement(Value *vector, Type *type, int index)
 	{
-		assert(V(vector)->getType()->getContainedType(0) == T(type));
+		ASSERT(V(vector)->getType()->getContainedType(0) == T(type));
 		return V(::builder->CreateExtractElement(V(vector), V(createConstantInt(index))));
 	}
 
@@ -1573,7 +1583,7 @@
 		int size = llvm::cast<llvm::VectorType>(V(v1)->getType())->getNumElements();
 		const int maxSize = 16;
 		llvm::Constant *swizzle[maxSize];
-		assert(size <= maxSize);
+		ASSERT(size <= maxSize);
 
 		for(int i = 0; i < size; i++)
 		{
@@ -1668,10 +1678,10 @@
 
 	Value *Nucleus::createConstantVector(const int64_t *constants, Type *type)
 	{
-		assert(llvm::isa<llvm::VectorType>(T(type)));
+		ASSERT(llvm::isa<llvm::VectorType>(T(type)));
 		const int numConstants = elementCount(type);                                       // Number of provided constants for the (emulated) type.
 		const int numElements = llvm::cast<llvm::VectorType>(T(type))->getNumElements();   // Number of elements of the underlying vector type.
-		assert(numElements <= 16 && numConstants <= numElements);
+		ASSERT(numElements <= 16 && numConstants <= numElements);
 		llvm::Constant *constantVector[16];
 
 		for(int i = 0; i < numElements; i++)
@@ -1684,10 +1694,10 @@
 
 	Value *Nucleus::createConstantVector(const double *constants, Type *type)
 	{
-		assert(llvm::isa<llvm::VectorType>(T(type)));
+		ASSERT(llvm::isa<llvm::VectorType>(T(type)));
 		const int numConstants = elementCount(type);                                       // Number of provided constants for the (emulated) type.
 		const int numElements = llvm::cast<llvm::VectorType>(T(type))->getNumElements();   // Number of elements of the underlying vector type.
-		assert(numElements <= 8 && numConstants <= numElements);
+		ASSERT(numElements <= 8 && numConstants <= numElements);
 		llvm::Constant *constantVector[8];
 
 		for(int i = 0; i < numElements; i++)
@@ -3217,7 +3227,7 @@
 	RValue<UInt4> Ctlz(RValue<UInt4> v, bool isZeroUndef)
 	{
 #if REACTOR_LLVM_VERSION < 7
-		assert(false); // TODO: LLVM 3 does not support ctlz in a vector form.
+		UNIMPLEMENTED("LLVM 3 does not support ctlz in a vector form");
 #endif
 		::llvm::SmallVector<::llvm::Type*, 2> paramTys;
 		paramTys.push_back(T(UInt4::getType()));
@@ -3232,7 +3242,7 @@
 	RValue<UInt4> Cttz(RValue<UInt4> v, bool isZeroUndef)
 	{
 #if REACTOR_LLVM_VERSION < 7
-		assert(false); // TODO: LLVM 3 does not support cttz in a vector form.
+		UNIMPLEMENTED("LLVM 3 does not support cttz in a vector form");
 #endif
 		::llvm::SmallVector<::llvm::Type*, 2> paramTys;
 		paramTys.push_back(T(UInt4::getType()));
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 27604a8..63d7bd6 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "Reactor.hpp"
+#include "Debug.hpp"
 
 #include "Optimizer.hpp"
 #include "ExecutableMemory.hpp"
@@ -51,7 +52,6 @@
 #include <mutex>
 #include <limits>
 #include <iostream>
-#include <cassert>
 
 namespace
 {
@@ -191,7 +191,7 @@
 			case Type_v8i8:  return 8;
 			case Type_v4i8:  return 4;
 			case Type_v2f32: return 8;
-			default: assert(false);
+			default: ASSERT(false);
 			}
 		}
 
@@ -229,7 +229,7 @@
 			uint32_t symtab_entries = symbolTable->sh_size / symbolTable->sh_entsize;
 			if(index >= symtab_entries)
 			{
-				assert(index < symtab_entries && "Symbol Index out of range");
+				ASSERT(index < symtab_entries && "Symbol Index out of range");
 				return nullptr;
 			}
 
@@ -272,7 +272,7 @@
 				}
 				break;
 			default:
-				assert(false && "Unsupported relocation type");
+				ASSERT(false && "Unsupported relocation type");
 				return nullptr;
 			}
 		}
@@ -290,7 +290,7 @@
 		//		*patchSite = (int32_t)((intptr_t)symbolValue + *patchSite - (intptr_t)patchSite);
 		//		break;
 			default:
-				assert(false && "Unsupported relocation type");
+				ASSERT(false && "Unsupported relocation type");
 				return nullptr;
 			}
 		}
@@ -314,7 +314,7 @@
 			uint32_t symtab_entries = symbolTable->sh_size / symbolTable->sh_entsize;
 			if(index >= symtab_entries)
 			{
-				assert(index < symtab_entries && "Symbol Index out of range");
+				ASSERT(index < symtab_entries && "Symbol Index out of range");
 				return nullptr;
 			}
 
@@ -352,7 +352,7 @@
 			*patchSite32 = (int32_t)((intptr_t)symbolValue + *patchSite32 + relocation.r_addend);
 			break;
 		default:
-			assert(false && "Unsupported relocation type");
+			ASSERT(false && "Unsupported relocation type");
 			return nullptr;
 		}
 
@@ -369,17 +369,17 @@
 		}
 
 		// Expect ELF bitness to match platform
-		assert(sizeof(void*) == 8 ? elfHeader->getFileClass() == ELFCLASS64 : elfHeader->getFileClass() == ELFCLASS32);
+		ASSERT(sizeof(void*) == 8 ? elfHeader->getFileClass() == ELFCLASS64 : elfHeader->getFileClass() == ELFCLASS32);
 		#if defined(__i386__)
-			assert(sizeof(void*) == 4 && elfHeader->e_machine == EM_386);
+			ASSERT(sizeof(void*) == 4 && elfHeader->e_machine == EM_386);
 		#elif defined(__x86_64__)
-			assert(sizeof(void*) == 8 && elfHeader->e_machine == EM_X86_64);
+			ASSERT(sizeof(void*) == 8 && elfHeader->e_machine == EM_X86_64);
 		#elif defined(__arm__)
-			assert(sizeof(void*) == 4 && elfHeader->e_machine == EM_ARM);
+			ASSERT(sizeof(void*) == 4 && elfHeader->e_machine == EM_ARM);
 		#elif defined(__aarch64__)
-			assert(sizeof(void*) == 8 && elfHeader->e_machine == EM_AARCH64);
+			ASSERT(sizeof(void*) == 8 && elfHeader->e_machine == EM_AARCH64);
 		#elif defined(__mips__)
-			assert(sizeof(void*) == 4 && elfHeader->e_machine == EM_MIPS);
+			ASSERT(sizeof(void*) == 4 && elfHeader->e_machine == EM_MIPS);
 		#else
 			#error "Unsupported platform"
 		#endif
@@ -399,7 +399,7 @@
 			}
 			else if(sectionHeader[i].sh_type == SHT_REL)
 			{
-				assert(sizeof(void*) == 4 && "UNIMPLEMENTED");   // Only expected/implemented for 32-bit code
+				ASSERT(sizeof(void*) == 4 && "UNIMPLEMENTED");   // Only expected/implemented for 32-bit code
 
 				for(Elf32_Word index = 0; index < sectionHeader[i].sh_size / sectionHeader[i].sh_entsize; index++)
 				{
@@ -409,7 +409,7 @@
 			}
 			else if(sectionHeader[i].sh_type == SHT_RELA)
 			{
-				assert(sizeof(void*) == 8 && "UNIMPLEMENTED");   // Only expected/implemented for 64-bit code
+				ASSERT(sizeof(void*) == 8 && "UNIMPLEMENTED");   // Only expected/implemented for 64-bit code
 
 				for(Elf32_Word index = 0; index < sectionHeader[i].sh_size / sectionHeader[i].sh_entsize; index++)
 				{
@@ -477,7 +477,7 @@
 				buffer[position] = Value;
 				position++;
 			}
-			else assert(false && "UNIMPLEMENTED");
+			else ASSERT(false && "UNIMPLEMENTED");
 		}
 
 		void writeBytes(llvm::StringRef Bytes) override
@@ -590,7 +590,7 @@
 		optimize();
 
 		::function->translate();
-		assert(!::function->hasError());
+		ASSERT(!::function->hasError());
 
 		auto globals = ::function->getGlobalInits();
 
@@ -648,7 +648,7 @@
 
 	void Nucleus::setInsertBlock(BasicBlock *basicBlock)
 	{
-	//	assert(::basicBlock->getInsts().back().getTerminatorEdges().size() >= 0 && "Previous basic block must have a terminator");
+	//	ASSERT(::basicBlock->getInsts().back().getTerminatorEdges().size() >= 0 && "Previous basic block must have a terminator");
 
 		Variable::materializeAll();
 
@@ -734,7 +734,7 @@
 
 	static Value *createArithmetic(Ice::InstArithmetic::OpKind op, Value *lhs, Value *rhs)
 	{
-		assert(lhs->getType() == rhs->getType() || llvm::isa<Ice::Constant>(rhs));
+		ASSERT(lhs->getType() == rhs->getType() || llvm::isa<Ice::Constant>(rhs));
 
 		bool swapOperands = llvm::isa<Ice::Constant>(lhs) && isCommutative(op);
 
@@ -865,8 +865,8 @@
 
 	Value *Nucleus::createLoad(Value *ptr, Type *type, bool isVolatile, unsigned int align, bool atomic, std::memory_order memoryOrder)
 	{
-		assert(!atomic);  // Unimplemented
-		assert(memoryOrder == std::memory_order_relaxed);  // Unimplemented
+		ASSERT(!atomic);  // Unimplemented
+		ASSERT(memoryOrder == std::memory_order_relaxed);  // Unimplemented
 
 		int valueType = (int)reinterpret_cast<intptr_t>(type);
 		Ice::Variable *result = ::function->makeVariable(T(type));
@@ -899,7 +899,7 @@
 					auto bitcast = Ice::InstCast::create(::function, Ice::InstCast::Bitcast, result, vector.loadValue());
 					::basicBlock->appendInst(bitcast);
 				}
-				else assert(false);
+				else UNREACHABLE("typeSize(type): %d", int(typeSize(type)));
 			}
 			else
 			{
@@ -922,8 +922,8 @@
 
 	Value *Nucleus::createStore(Value *value, Value *ptr, Type *type, bool isVolatile, unsigned int align, bool atomic, std::memory_order memoryOrder)
 	{
-		assert(!atomic);  // Unimplemented
-		assert(memoryOrder == std::memory_order_relaxed);  // Unimplemented
+		ASSERT(!atomic);  // Unimplemented
+		ASSERT(memoryOrder == std::memory_order_relaxed);  // Unimplemented
 
 		#if __has_feature(memory_sanitizer)
 			// Mark all (non-stack) memory writes as initialized by calling __msan_unpoison
@@ -968,7 +968,7 @@
 					Int y = Extract(v, 1);
 					*Pointer<Int>(pointer + 4) = y;
 				}
-				else assert(false);
+				else UNREACHABLE("typeSize(type): %d", int(typeSize(type)));
 			}
 			else
 			{
@@ -983,7 +983,7 @@
 		}
 		else
 		{
-			assert(value->getType() == T(type));
+			ASSERT(value->getType() == T(type));
 
 			auto store = Ice::InstStore::create(::function, value, ptr, align);
 			::basicBlock->appendInst(store);
@@ -994,7 +994,7 @@
 
 	Value *Nucleus::createGEP(Value *ptr, Type *type, Value *index, bool unsignedIndex)
 	{
-		assert(index->getType() == Ice::IceType_i32);
+		ASSERT(index->getType() == Ice::IceType_i32);
 
 		if(auto *constant = llvm::dyn_cast<Ice::ConstantInteger32>(index))
 		{
@@ -1030,7 +1030,8 @@
 
 	Value *Nucleus::createAtomicAdd(Value *ptr, Value *value)
 	{
-		assert(false && "UNIMPLEMENTED"); return nullptr;
+		UNIMPLEMENTED("createAtomicAdd");
+		return nullptr;
 	}
 
 	static Value *createCast(Ice::InstCast::OpKind op, Value *v, Type *destType)
@@ -1108,7 +1109,7 @@
 
 	static Value *createIntCompare(Ice::InstIcmp::ICond condition, Value *lhs, Value *rhs)
 	{
-		assert(lhs->getType() == rhs->getType());
+		ASSERT(lhs->getType() == rhs->getType());
 
 		auto result = ::function->makeVariable(Ice::isScalarIntegerType(lhs->getType()) ? Ice::IceType_i1 : lhs->getType());
 		auto cmp = Ice::InstIcmp::create(::function, condition, result, lhs, rhs);
@@ -1169,8 +1170,8 @@
 
 	static Value *createFloatCompare(Ice::InstFcmp::FCond condition, Value *lhs, Value *rhs)
 	{
-		assert(lhs->getType() == rhs->getType());
-		assert(Ice::isScalarFloatingType(lhs->getType()) || lhs->getType() == Ice::IceType_v4f32);
+		ASSERT(lhs->getType() == rhs->getType());
+		ASSERT(Ice::isScalarFloatingType(lhs->getType()) || lhs->getType() == Ice::IceType_v4f32);
 
 		auto result = ::function->makeVariable(Ice::isScalarFloatingType(lhs->getType()) ? Ice::IceType_i1 : Ice::IceType_v4i32);
 		auto cmp = Ice::InstFcmp::create(::function, condition, result, lhs, rhs);
@@ -1269,7 +1270,7 @@
 
 	Value *Nucleus::createShuffleVector(Value *V1, Value *V2, const int *select)
 	{
-		assert(V1->getType() == V2->getType());
+		ASSERT(V1->getType() == V2->getType());
 
 		int size = Ice::typeNumElements(V1->getType());
 		auto result = ::function->makeVariable(V1->getType());
@@ -1287,7 +1288,7 @@
 
 	Value *Nucleus::createSelect(Value *C, Value *ifTrue, Value *ifFalse)
 	{
-		assert(ifTrue->getType() == ifFalse->getType());
+		ASSERT(ifTrue->getType() == ifFalse->getType());
 
 		auto result = ::function->makeVariable(ifTrue->getType());
 		auto *select = Ice::InstSelect::create(::function, result, C, ifTrue, ifFalse);
@@ -1331,7 +1332,7 @@
 	{
 		if(Ice::isVectorType(T(Ty)))
 		{
-			assert(Ice::typeNumElements(T(Ty)) <= 16);
+			ASSERT(Ice::typeNumElements(T(Ty)) <= 16);
 			int64_t c[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 			return createConstantVector(c, Ty);
 		}
@@ -1394,7 +1395,7 @@
 	Value *Nucleus::createConstantVector(const int64_t *constants, Type *type)
 	{
 		const int vectorSize = 16;
-		assert(Ice::typeWidthInBytes(T(type)) == vectorSize);
+		ASSERT(Ice::typeWidthInBytes(T(type)) == vectorSize);
 		const int alignment = vectorSize;
 		auto globalPool = ::function->getGlobalPool();
 
@@ -1471,7 +1472,7 @@
 			}
 			break;
 		default:
-			assert(false && "Unknown constant vector type" && type);
+			UNREACHABLE("Unknown constant vector type: %d", (int)reinterpret_cast<intptr_t>(type));
 		}
 
 		auto name = Ice::GlobalString::createWithoutString(::context);
@@ -1839,7 +1840,7 @@
 
 	Short4::Short4(RValue<Float4> cast)
 	{
-		assert(false && "UNIMPLEMENTED");
+		UNIMPLEMENTED("Short4::Short4(RValue<Float4> cast)");
 	}
 
 	RValue<Short4> operator<<(RValue<Short4> lhs, unsigned char rhs)
@@ -2317,7 +2318,8 @@
 
 	RValue<UShort4> Average(RValue<UShort4> x, RValue<UShort4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<UShort4>(V(nullptr));
+		UNIMPLEMENTED("RValue<UShort4> Average(RValue<UShort4> x, RValue<UShort4> y)");
+		return UShort4(0);
 	}
 
 	Type *UShort4::getType()
@@ -2381,12 +2383,14 @@
 
 	RValue<Int4> MulAdd(RValue<Short8> x, RValue<Short8> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Int4>(V(nullptr));
+		UNIMPLEMENTED("RValue<Int4> MulAdd(RValue<Short8> x, RValue<Short8> y)");
+		return Int4(0);
 	}
 
 	RValue<Short8> MulHigh(RValue<Short8> x, RValue<Short8> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Short8>(V(nullptr));
+		UNIMPLEMENTED("RValue<Short8> MulHigh(RValue<Short8> x, RValue<Short8> y)");
+		return Short8(0);
 	}
 
 	Type *Short8::getType()
@@ -2450,18 +2454,20 @@
 
 	RValue<UShort8> Swizzle(RValue<UShort8> x, char select0, char select1, char select2, char select3, char select4, char select5, char select6, char select7)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<UShort8>(V(nullptr));
+		UNIMPLEMENTED("RValue<UShort8> Swizzle(RValue<UShort8> x, char select0, char select1, char select2, char select3, char select4, char select5, char select6, char select7)");
+		return UShort8(0);
 	}
 
 	RValue<UShort8> MulHigh(RValue<UShort8> x, RValue<UShort8> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<UShort8>(V(nullptr));
+		UNIMPLEMENTED("RValue<UShort8> MulHigh(RValue<UShort8> x, RValue<UShort8> y)");
+		return UShort8(0);
 	}
 
 	// FIXME: Implement as Shuffle(x, y, Select(i0, ..., i16)) and Shuffle(x, y, SELECT_PACK_REPEAT(element))
 //	RValue<UShort8> PackRepeat(RValue<Byte16> x, RValue<Byte16> y, int element)
 //	{
-//		assert(false && "UNIMPLEMENTED"); return RValue<UShort8>(V(nullptr));
+//		ASSERT(false && "UNIMPLEMENTED"); return RValue<UShort8>(V(nullptr));
 //	}
 
 	Type *UShort8::getType()
@@ -2569,7 +2575,7 @@
 
 //	RValue<UInt> RoundUInt(RValue<Float> cast)
 //	{
-//		assert(false && "UNIMPLEMENTED"); return RValue<UInt>(V(nullptr));
+//		ASSERT(false && "UNIMPLEMENTED"); return RValue<UInt>(V(nullptr));
 //	}
 
 	Type *UInt::getType()
@@ -3366,16 +3372,12 @@
 
 	RValue<Long> Ticks()
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Long>(V(nullptr));
+		UNIMPLEMENTED("RValue<Long> Ticks()");
+		return Long(Int(0));
 	}
 
 	// Below are functions currently unimplemented for the Subzero backend.
 	// They are stubbed to satisfy the linker.
-	#ifdef UNIMPLEMENTED
-	#undef UNIMPLEMENTED
-	#endif
-	#define UNIMPLEMENTED(msg) assert(((void)(msg), false))
-
 	RValue<Float4> Sin(RValue<Float4> x) { UNIMPLEMENTED("Subzero Sin()"); return Float4(0); }
 	RValue<Float4> Cos(RValue<Float4> x) { UNIMPLEMENTED("Subzero Cos()"); return Float4(0); }
 	RValue<Float4> Tan(RValue<Float4> x) { UNIMPLEMENTED("Subzero Tan()"); return Float4(0); }