Implement rr::Print support for Subzero
Factored out most of the rr::Print code in LLVMReactor.cpp to
Reactor.cpp, and rewritten in terms of Nucleus. Added a couple of new
Nucleus functions to support this.
Bug: b/149477527
Change-Id: I0a28626f1aa6133a37f9e75abc08544f3de15a45
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/41188
Presubmit-Ready: Antonio Maiorano <amaiorano@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index aaf2be0..4451f44 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -543,9 +543,8 @@
endif()
endif()
-if((${REACTOR_BACKEND} STREQUAL "Subzero") AND (REACTOR_ENABLE_PRINT OR REACTOR_EMIT_PRINT_LOCATION OR REACTOR_EMIT_DEBUG_INFO))
+if((${REACTOR_BACKEND} STREQUAL "Subzero") AND (REACTOR_EMIT_PRINT_LOCATION OR REACTOR_EMIT_DEBUG_INFO))
message(WARNING "REACTOR_ENABLE_PRINT, REACTOR_EMIT_PRINT_LOCATION, and REACTOR_EMIT_DEBUG_INFO are not supported by Subzero, disabling.")
- set(REACTOR_ENABLE_PRINT "Off")
set(REACTOR_EMIT_PRINT_LOCATION "Off")
set(REACTOR_EMIT_DEBUG_INFO "Off")
endif()
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index c14012d..7f780a6 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -77,19 +77,6 @@
return config;
}
-#ifdef ENABLE_RR_PRINT
-std::string replace(std::string str, const std::string &substr, const std::string &replacement)
-{
- size_t pos = 0;
- while((pos = str.find(substr, pos)) != std::string::npos)
- {
- str.replace(pos, substr.length(), replacement);
- pos += replacement.length();
- }
- return str;
-}
-#endif // ENABLE_RR_PRINT
-
llvm::Value *lowerPAVG(llvm::Value *x, llvm::Value *y)
{
llvm::VectorType *ty = llvm::cast<llvm::VectorType>(x->getType());
@@ -1567,11 +1554,42 @@
jit->builder->CreateUnreachable();
}
+Type *Nucleus::getType(Value *value)
+{
+ return T(V(value)->getType());
+}
+
+Type *Nucleus::getContainedType(Type *vectorType)
+{
+ return T(T(vectorType)->getContainedType(0));
+}
+
Type *Nucleus::getPointerType(Type *ElementType)
{
return T(llvm::PointerType::get(T(ElementType), 0));
}
+static ::llvm::Type *getNaturalIntType()
+{
+ return ::llvm::Type::getIntNTy(jit->context, sizeof(int) * 8);
+}
+
+Type *Nucleus::getPrintfStorageType(Type *valueType)
+{
+ llvm::Type *valueTy = T(valueType);
+ if(valueTy->isIntegerTy())
+ {
+ return T(getNaturalIntType());
+ }
+ if(valueTy->isFloatTy())
+ {
+ return T(llvm::Type::getDoubleTy(jit->context));
+ }
+
+ UNIMPLEMENTED_NO_BUG("getPrintfStorageType: add more cases as needed");
+ return {};
+}
+
Value *Nucleus::createNullValue(Type *Ty)
{
RR_DEBUG_INFO_UPDATE_LOC();
@@ -1670,6 +1688,12 @@
return V(llvm::ConstantVector::get(llvm::ArrayRef<llvm::Constant *>(constantVector, numElements)));
}
+Value *Nucleus::createConstantString(const char *v)
+{
+ auto ptr = jit->builder->CreateGlobalStringPtr(v);
+ return V(ptr);
+}
+
Type *Void::getType()
{
return T(llvm::Type::getVoidTy(jit->context));
@@ -3827,189 +3851,13 @@
#endif // defined(__i386__) || defined(__x86_64__)
#ifdef ENABLE_RR_PRINT
-// extractAll returns a vector containing the extracted n scalar value of
-// the vector vec.
-static std::vector<Value *> extractAll(Value *vec, int n)
+void VPrintf(const std::vector<Value *> &vals)
{
- std::vector<Value *> elements;
- elements.reserve(n);
- for(int i = 0; i < n; i++)
- {
- auto el = V(jit->builder->CreateExtractElement(V(vec), i));
- elements.push_back(el);
- }
- return elements;
-}
-
-// toInt returns all the integer values in vals extended to a native width
-// integer.
-static std::vector<Value *> toInt(const std::vector<Value *> &vals, bool isSigned)
-{
- auto intTy = ::llvm::Type::getIntNTy(jit->context, sizeof(int) * 8); // Natural integer width.
- std::vector<Value *> elements;
- elements.reserve(vals.size());
- for(auto v : vals)
- {
- if(isSigned)
- {
- elements.push_back(V(jit->builder->CreateSExt(V(v), intTy)));
- }
- else
- {
- elements.push_back(V(jit->builder->CreateZExt(V(v), intTy)));
- }
- }
- return elements;
-}
-
-// toDouble returns all the float values in vals extended to doubles.
-static std::vector<Value *> toDouble(const std::vector<Value *> &vals)
-{
- auto doubleTy = ::llvm::Type::getDoubleTy(jit->context);
- std::vector<Value *> elements;
- elements.reserve(vals.size());
- for(auto v : vals)
- {
- elements.push_back(V(jit->builder->CreateFPExt(V(v), doubleTy)));
- }
- return elements;
-}
-
-std::vector<Value *> PrintValue::Ty<Bool>::val(const RValue<Bool> &v)
-{
- auto t = jit->builder->CreateGlobalStringPtr("true");
- auto f = jit->builder->CreateGlobalStringPtr("false");
- return { V(jit->builder->CreateSelect(V(v.value), t, f)) };
-}
-
-std::vector<Value *> PrintValue::Ty<Byte>::val(const RValue<Byte> &v)
-{
- return toInt({ v.value }, false);
-}
-
-std::vector<Value *> PrintValue::Ty<Byte4>::val(const RValue<Byte4> &v)
-{
- return toInt(extractAll(v.value, 4), false);
-}
-
-std::vector<Value *> PrintValue::Ty<Int>::val(const RValue<Int> &v)
-{
- return toInt({ v.value }, true);
-}
-
-std::vector<Value *> PrintValue::Ty<Int2>::val(const RValue<Int2> &v)
-{
- return toInt(extractAll(v.value, 2), true);
-}
-
-std::vector<Value *> PrintValue::Ty<Int4>::val(const RValue<Int4> &v)
-{
- return toInt(extractAll(v.value, 4), true);
-}
-
-std::vector<Value *> PrintValue::Ty<UInt>::val(const RValue<UInt> &v)
-{
- return toInt({ v.value }, false);
-}
-
-std::vector<Value *> PrintValue::Ty<UInt2>::val(const RValue<UInt2> &v)
-{
- return toInt(extractAll(v.value, 2), false);
-}
-
-std::vector<Value *> PrintValue::Ty<UInt4>::val(const RValue<UInt4> &v)
-{
- return toInt(extractAll(v.value, 4), false);
-}
-
-std::vector<Value *> PrintValue::Ty<Short>::val(const RValue<Short> &v)
-{
- return toInt({ v.value }, true);
-}
-
-std::vector<Value *> PrintValue::Ty<Short4>::val(const RValue<Short4> &v)
-{
- return toInt(extractAll(v.value, 4), true);
-}
-
-std::vector<Value *> PrintValue::Ty<UShort>::val(const RValue<UShort> &v)
-{
- return toInt({ v.value }, false);
-}
-
-std::vector<Value *> PrintValue::Ty<UShort4>::val(const RValue<UShort4> &v)
-{
- return toInt(extractAll(v.value, 4), false);
-}
-
-std::vector<Value *> PrintValue::Ty<Float>::val(const RValue<Float> &v)
-{
- return toDouble({ v.value });
-}
-
-std::vector<Value *> PrintValue::Ty<Float4>::val(const RValue<Float4> &v)
-{
- return toDouble(extractAll(v.value, 4));
-}
-
-std::vector<Value *> PrintValue::Ty<const char *>::val(const char *v)
-{
- return { V(jit->builder->CreateGlobalStringPtr(v)) };
-}
-
-void Printv(const char *function, const char *file, int line, const char *fmt, std::initializer_list<PrintValue> args)
-{
- // LLVM types used below.
auto i32Ty = ::llvm::Type::getInt32Ty(jit->context);
- auto intTy = ::llvm::Type::getIntNTy(jit->context, sizeof(int) * 8); // Natural integer width.
auto i8PtrTy = ::llvm::Type::getInt8PtrTy(jit->context);
auto funcTy = ::llvm::FunctionType::get(i32Ty, { i8PtrTy }, true);
-
auto func = jit->module->getOrInsertFunction("printf", funcTy);
-
- // Build the printf format message string.
- std::string str;
- if(file != nullptr) { str += (line > 0) ? "%s:%d " : "%s "; }
- if(function != nullptr) { str += "%s "; }
- str += fmt;
-
- // Perform substitution on all '{n}' bracketed indices in the format
- // message.
- int i = 0;
- for(const PrintValue &arg : args)
- {
- str = replace(str, "{" + std::to_string(i++) + "}", arg.format);
- }
-
- ::llvm::SmallVector<::llvm::Value *, 8> vals;
-
- // The format message is always the first argument.
- vals.push_back(jit->builder->CreateGlobalStringPtr(str));
-
- // Add optional file, line and function info if provided.
- if(file != nullptr)
- {
- vals.push_back(jit->builder->CreateGlobalStringPtr(file));
- if(line > 0)
- {
- vals.push_back(::llvm::ConstantInt::get(intTy, line));
- }
- }
- if(function != nullptr)
- {
- vals.push_back(jit->builder->CreateGlobalStringPtr(function));
- }
-
- // Add all format arguments.
- for(const PrintValue &arg : args)
- {
- for(auto val : arg.values)
- {
- vals.push_back(V(val));
- }
- }
-
- jit->builder->CreateCall(func, vals);
+ jit->builder->CreateCall(func, V(vals));
}
#endif // ENABLE_RR_PRINT
diff --git a/src/Reactor/LLVMReactor.hpp b/src/Reactor/LLVMReactor.hpp
index db7df10..fc3f1a2 100644
--- a/src/Reactor/LLVMReactor.hpp
+++ b/src/Reactor/LLVMReactor.hpp
@@ -65,6 +65,17 @@
return reinterpret_cast<Value *>(t);
}
+inline std::vector<llvm::Value *> V(const std::vector<Value *> &values)
+{
+ std::vector<llvm::Value *> result;
+ result.reserve(values.size());
+ for(auto &v : values)
+ {
+ result.push_back(V(v));
+ }
+ return result;
+}
+
// Emits a no-op instruction that will not be optimized away.
// Useful for emitting something that can have a source location without
// effect.
diff --git a/src/Reactor/Nucleus.hpp b/src/Reactor/Nucleus.hpp
index 513f4fb..4c08ddd 100644
--- a/src/Reactor/Nucleus.hpp
+++ b/src/Reactor/Nucleus.hpp
@@ -21,6 +21,7 @@
#include <cstdint>
#include <functional>
#include <memory>
+#include <string>
#include <vector>
#ifdef None
@@ -326,8 +327,13 @@
static Value *createNullPointer(Type *type);
static Value *createConstantVector(const int64_t *constants, Type *type);
static Value *createConstantVector(const double *constants, Type *type);
+ static Value *createConstantString(const char *v);
+ static Value *createConstantString(const std::string &v) { return createConstantString(v.c_str()); }
+ static Type *getType(Value *value);
+ static Type *getContainedType(Type *vectorType);
static Type *getPointerType(Type *elementType);
+ static Type *getPrintfStorageType(Type *valueType);
};
} // namespace rr
diff --git a/src/Reactor/Print.hpp b/src/Reactor/Print.hpp
index a5bde3e..ca70465 100644
--- a/src/Reactor/Print.hpp
+++ b/src/Reactor/Print.hpp
@@ -337,6 +337,10 @@
static std::vector<Value *> val(const RValue<T> &v) { return PrintValue::Ty<T>::val(v); }
};
+// VPrintf emits a call to printf() using vals[0] as the format string,
+// and vals[1..n] as the args.
+void VPrintf(const std::vector<Value *> &vals);
+
// Printv emits a call to printf() using the function, file and line,
// message and optional values.
// See Printv below.
diff --git a/src/Reactor/Reactor.cpp b/src/Reactor/Reactor.cpp
index 8801f2a..abe4882 100644
--- a/src/Reactor/Reactor.cpp
+++ b/src/Reactor/Reactor.cpp
@@ -14,6 +14,7 @@
#include "Reactor.hpp"
#include "Debug.hpp"
+#include "Print.hpp"
#include <cmath>
@@ -4596,4 +4597,197 @@
// TODO: Long has no constructor that takes a uint64_t
// Long CToReactor<uint64_t>::cast(uint64_t v) { return type(v); }
+#ifdef ENABLE_RR_PRINT
+static std::string replaceAll(std::string str, const std::string &substr, const std::string &replacement)
+{
+ size_t pos = 0;
+ while((pos = str.find(substr, pos)) != std::string::npos)
+ {
+ str.replace(pos, substr.length(), replacement);
+ pos += replacement.length();
+ }
+ return str;
+}
+
+// extractAll returns a vector containing the extracted n scalar value of
+// the vector vec.
+// TODO: Move to Reactor.cpp (LLVMReactor can use this too)
+static std::vector<Value *> extractAll(Value *vec, int n)
+{
+ Type *elemTy = Nucleus::getContainedType(Nucleus::getType(vec));
+ std::vector<Value *> elements;
+ elements.reserve(n);
+ for(int i = 0; i < n; i++)
+ {
+ auto el = Nucleus::createExtractElement(vec, elemTy, i);
+ elements.push_back(el);
+ }
+ return elements;
+}
+
+// toInt returns all the integer values in vals extended to a printf-required storage value
+static std::vector<Value *> toInt(const std::vector<Value *> &vals, bool isSigned)
+{
+ auto storageTy = Nucleus::getPrintfStorageType(Int::getType());
+ std::vector<Value *> elements;
+ elements.reserve(vals.size());
+ for(auto v : vals)
+ {
+ if(isSigned)
+ {
+ elements.push_back(Nucleus::createSExt(v, storageTy));
+ }
+ else
+ {
+ elements.push_back(Nucleus::createZExt(v, storageTy));
+ }
+ }
+ return elements;
+}
+
+// toFloat returns all the float values in vals extended to extended to a printf-required storage value
+static std::vector<Value *> toFloat(const std::vector<Value *> &vals)
+{
+ auto storageTy = Nucleus::getPrintfStorageType(Float::getType());
+ std::vector<Value *> elements;
+ elements.reserve(vals.size());
+ for(auto v : vals)
+ {
+ elements.push_back(Nucleus::createFPExt(v, storageTy));
+ }
+ return elements;
+}
+
+std::vector<Value *> PrintValue::Ty<Bool>::val(const RValue<Bool> &v)
+{
+ auto t = Nucleus::createConstantString("true");
+ auto f = Nucleus::createConstantString("false");
+ return { Nucleus::createSelect(v.value, t, f) };
+}
+
+std::vector<Value *> PrintValue::Ty<Byte>::val(const RValue<Byte> &v)
+{
+ return toInt({ v.value }, false);
+}
+
+std::vector<Value *> PrintValue::Ty<Byte4>::val(const RValue<Byte4> &v)
+{
+ return toInt(extractAll(v.value, 4), false);
+}
+
+std::vector<Value *> PrintValue::Ty<Int>::val(const RValue<Int> &v)
+{
+ return toInt({ v.value }, true);
+}
+
+std::vector<Value *> PrintValue::Ty<Int2>::val(const RValue<Int2> &v)
+{
+ return toInt(extractAll(v.value, 2), true);
+}
+
+std::vector<Value *> PrintValue::Ty<Int4>::val(const RValue<Int4> &v)
+{
+ return toInt(extractAll(v.value, 4), true);
+}
+
+std::vector<Value *> PrintValue::Ty<UInt>::val(const RValue<UInt> &v)
+{
+ return toInt({ v.value }, false);
+}
+
+std::vector<Value *> PrintValue::Ty<UInt2>::val(const RValue<UInt2> &v)
+{
+ return toInt(extractAll(v.value, 2), false);
+}
+
+std::vector<Value *> PrintValue::Ty<UInt4>::val(const RValue<UInt4> &v)
+{
+ return toInt(extractAll(v.value, 4), false);
+}
+
+std::vector<Value *> PrintValue::Ty<Short>::val(const RValue<Short> &v)
+{
+ return toInt({ v.value }, true);
+}
+
+std::vector<Value *> PrintValue::Ty<Short4>::val(const RValue<Short4> &v)
+{
+ return toInt(extractAll(v.value, 4), true);
+}
+
+std::vector<Value *> PrintValue::Ty<UShort>::val(const RValue<UShort> &v)
+{
+ return toInt({ v.value }, false);
+}
+
+std::vector<Value *> PrintValue::Ty<UShort4>::val(const RValue<UShort4> &v)
+{
+ return toInt(extractAll(v.value, 4), false);
+}
+
+std::vector<Value *> PrintValue::Ty<Float>::val(const RValue<Float> &v)
+{
+ return toFloat({ v.value });
+}
+
+std::vector<Value *> PrintValue::Ty<Float4>::val(const RValue<Float4> &v)
+{
+ return toFloat(extractAll(v.value, 4));
+}
+
+std::vector<Value *> PrintValue::Ty<const char *>::val(const char *v)
+{
+ return { Nucleus::createConstantString(v) };
+}
+
+void Printv(const char *function, const char *file, int line, const char *fmt, std::initializer_list<PrintValue> args)
+{
+ // Build the printf format message string.
+ std::string str;
+ if(file != nullptr) { str += (line > 0) ? "%s:%d " : "%s "; }
+ if(function != nullptr) { str += "%s "; }
+ str += fmt;
+
+ // Perform substitution on all '{n}' bracketed indices in the format
+ // message.
+ int i = 0;
+ for(const PrintValue &arg : args)
+ {
+ str = replaceAll(str, "{" + std::to_string(i++) + "}", arg.format);
+ }
+
+ std::vector<Value *> vals;
+ vals.reserve(8);
+
+ // The format message is always the first argument.
+ vals.push_back(Nucleus::createConstantString(str));
+
+ // Add optional file, line and function info if provided.
+ if(file != nullptr)
+ {
+ vals.push_back(Nucleus::createConstantString(file));
+ if(line > 0)
+ {
+ vals.push_back(Nucleus::createConstantInt(line));
+ }
+ }
+ if(function != nullptr)
+ {
+ vals.push_back(Nucleus::createConstantString(function));
+ }
+
+ // Add all format arguments.
+ for(const PrintValue &arg : args)
+ {
+ for(auto val : arg.values)
+ {
+ vals.push_back(val);
+ }
+ }
+
+ // This call is implemented by each backend
+ VPrintf(vals);
+}
+#endif // ENABLE_RR_PRINT
+
} // namespace rr
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index f2dbdef..29aa1c8 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -14,6 +14,7 @@
#include "Debug.hpp"
#include "EmulatedReactor.hpp"
+#include "Print.hpp"
#include "Reactor.hpp"
#include "ExecutableMemory.hpp"
@@ -143,11 +144,8 @@
}
// Wrapper for calls on C functions with Ice types
-template<typename Return, typename... CArgs, typename... RArgs>
-Ice::Variable *Call(Ice::Cfg *function, Ice::CfgNode *basicBlock, Return(fptr)(CArgs...), RArgs &&... args)
+Ice::Variable *Call(Ice::Cfg *function, Ice::CfgNode *basicBlock, Ice::Type retTy, void const *fptr, const std::vector<Ice::Operand *> &iceArgs)
{
- Ice::Type retTy = T(rr::CToReactorT<Return>::getType());
-
// Subzero doesn't support boolean return values. Replace with an i32.
if(retTy == Ice::IceType_i1)
{
@@ -160,9 +158,7 @@
ret = function->makeVariable(retTy);
}
- std::array<Ice::Variable *, sizeof...(args)> iceArgs{ { std::forward<RArgs>(args)... } };
-
- auto call = Ice::InstCall::create(function, iceArgs.size(), ret, getConstantPointer(function->getContext(), reinterpret_cast<void const *>(fptr)), false);
+ auto call = Ice::InstCall::create(function, iceArgs.size(), ret, getConstantPointer(function->getContext(), fptr), false);
for(auto arg : iceArgs)
{
call->addArg(arg);
@@ -172,6 +168,15 @@
return ret;
}
+// Wrapper for calls on C functions with Ice types
+template<typename Return, typename... CArgs, typename... RArgs>
+Ice::Variable *Call(Ice::Cfg *function, Ice::CfgNode *basicBlock, Return(fptr)(CArgs...), RArgs &&... args)
+{
+ Ice::Type retTy = T(rr::CToReactorT<Return>::getType());
+ std::vector<Ice::Operand *> iceArgs{ std::forward<RArgs>(args)... };
+ return Call(function, basicBlock, retTy, reinterpret_cast<void const *>(fptr), iceArgs);
+}
+
// Returns a non-const variable copy of const v
Ice::Variable *createUnconstCast(Ice::Cfg *function, Ice::CfgNode *basicBlock, Ice::Constant *v)
{
@@ -414,6 +419,17 @@
return reinterpret_cast<Ice::Operand *>(v);
}
+std::vector<Ice::Operand *> V(const std::vector<Value *> &values)
+{
+ std::vector<Ice::Operand *> result;
+ result.reserve(values.size());
+ for(auto &v : values)
+ {
+ result.push_back(V(v));
+ }
+ return result;
+}
+
BasicBlock *B(Ice::CfgNode *b)
{
return reinterpret_cast<BasicBlock *>(b);
@@ -798,6 +814,13 @@
std::vector<std::unique_ptr<uint8_t[]>> constantData;
};
+#ifdef ENABLE_RR_PRINT
+void VPrintf(const std::vector<Value *> &vals)
+{
+ sz::Call(::function, ::basicBlock, Ice::IceType_i32, reinterpret_cast<const void *>(::printf), V(vals));
+}
+#endif // ENABLE_RR_PRINT
+
Nucleus::Nucleus()
{
::codegenMutex.lock(); // Reactor is currently not thread safe
@@ -1701,7 +1724,7 @@
Value *Nucleus::createExtractElement(Value *vector, Type *type, int index)
{
auto result = ::function->makeVariable(T(type));
- auto extract = Ice::InstExtractElement::create(::function, result, vector, ::context->getConstantInt32(index));
+ auto extract = Ice::InstExtractElement::create(::function, result, V(vector), ::context->getConstantInt32(index));
::basicBlock->appendInst(extract);
return V(result);
@@ -1764,11 +1787,58 @@
::basicBlock->appendInst(unreachable);
}
+Type *Nucleus::getType(Value *value)
+{
+ return T(V(value)->getType());
+}
+
+Type *Nucleus::getContainedType(Type *vectorType)
+{
+ Ice::Type vecTy = T(vectorType);
+ switch(vecTy)
+ {
+ case Ice::IceType_v4i1: return T(Ice::IceType_i1);
+ case Ice::IceType_v8i1: return T(Ice::IceType_i1);
+ case Ice::IceType_v16i1: return T(Ice::IceType_i1);
+ case Ice::IceType_v16i8: return T(Ice::IceType_i8);
+ case Ice::IceType_v8i16: return T(Ice::IceType_i16);
+ case Ice::IceType_v4i32: return T(Ice::IceType_i32);
+ case Ice::IceType_v4f32: return T(Ice::IceType_f32);
+ default:
+ ASSERT_MSG(false, "getContainedType: input type is not a vector type");
+ return {};
+ }
+}
+
Type *Nucleus::getPointerType(Type *ElementType)
{
return T(sz::getPointerType(T(ElementType)));
}
+static constexpr Ice::Type getNaturalIntType()
+{
+ constexpr size_t intSize = sizeof(int);
+ static_assert(intSize == 4 || intSize == 8, "");
+ return intSize == 4 ? Ice::IceType_i32 : Ice::IceType_i64;
+}
+
+Type *Nucleus::getPrintfStorageType(Type *valueType)
+{
+ Ice::Type valueTy = T(valueType);
+ switch(valueTy)
+ {
+ case Ice::IceType_i32:
+ return T(getNaturalIntType());
+
+ case Ice::IceType_f32:
+ return T(Ice::IceType_f64);
+
+ default:
+ UNIMPLEMENTED_NO_BUG("getPrintfStorageType: add more cases as needed");
+ return {};
+ }
+}
+
Value *Nucleus::createNullValue(Type *Ty)
{
if(Ice::isVectorType(T(Ty)))
@@ -1933,6 +2003,11 @@
return createConstantVector((const int64_t *)constants, type);
}
+Value *Nucleus::createConstantString(const char *v)
+{
+ return V(IceConstantData(v, strlen(v) + 1));
+}
+
Type *Void::getType()
{
return T(Ice::IceType_void);