HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Android 10
|
10.0.0_r6
下载
查看原文件
收藏
根目录
external
swiftshader
src
Reactor
SubzeroReactor.cpp
// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "Reactor.hpp" #include "Optimizer.hpp" #include "ExecutableMemory.hpp" #include "src/IceTypes.h" #include "src/IceCfg.h" #include "src/IceELFStreamer.h" #include "src/IceGlobalContext.h" #include "src/IceCfgNode.h" #include "src/IceELFObjectWriter.h" #include "src/IceGlobalInits.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_os_ostream.h" #include "llvm/Support/Compiler.h" #if __has_feature(memory_sanitizer) #include
#endif #if defined(_WIN32) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif // !WIN32_LEAN_AND_MEAN #ifndef NOMINMAX #define NOMINMAX #endif // !NOMINMAX #include
#else #include
#if !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif #endif #include
#include
#include
#include
namespace { Ice::GlobalContext *context = nullptr; Ice::Cfg *function = nullptr; Ice::CfgNode *basicBlock = nullptr; Ice::CfgLocalAllocatorScope *allocator = nullptr; rr::Routine *routine = nullptr; std::mutex codegenMutex; Ice::ELFFileStreamer *elfFile = nullptr; Ice::Fdstream *out = nullptr; } namespace { #if !defined(__i386__) && defined(_M_IX86) #define __i386__ 1 #endif #if !defined(__x86_64__) && (defined(_M_AMD64) || defined (_M_X64)) #define __x86_64__ 1 #endif class CPUID { public: const static bool ARM; const static bool SSE4_1; private: static void cpuid(int registers[4], int info) { #if defined(__i386__) || defined(__x86_64__) #if defined(_WIN32) __cpuid(registers, info); #else __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info)); #endif #else registers[0] = 0; registers[1] = 0; registers[2] = 0; registers[3] = 0; #endif } static bool detectARM() { #if defined(__arm__) || defined(__aarch64__) return true; #elif defined(__i386__) || defined(__x86_64__) return false; #elif defined(__mips__) return false; #else #error "Unknown architecture" #endif } static bool detectSSE4_1() { #if defined(__i386__) || defined(__x86_64__) int registers[4]; cpuid(registers, 1); return (registers[2] & 0x00080000) != 0; #else return false; #endif } }; const bool CPUID::ARM = CPUID::detectARM(); const bool CPUID::SSE4_1 = CPUID::detectSSE4_1(); const bool emulateIntrinsics = false; const bool emulateMismatchedBitCast = CPUID::ARM; } namespace rr { enum EmulatedType { EmulatedShift = 16, EmulatedV2 = 2 << EmulatedShift, EmulatedV4 = 4 << EmulatedShift, EmulatedV8 = 8 << EmulatedShift, EmulatedBits = EmulatedV2 | EmulatedV4 | EmulatedV8, Type_v2i32 = Ice::IceType_v4i32 | EmulatedV2, Type_v4i16 = Ice::IceType_v8i16 | EmulatedV4, Type_v2i16 = Ice::IceType_v8i16 | EmulatedV2, Type_v8i8 = Ice::IceType_v16i8 | EmulatedV8, Type_v4i8 = Ice::IceType_v16i8 | EmulatedV4, Type_v2f32 = Ice::IceType_v4f32 | EmulatedV2, }; class Value : public Ice::Operand {}; class SwitchCases : public Ice::InstSwitch {}; class BasicBlock : public Ice::CfgNode {}; Ice::Type T(Type *t) { static_assert(static_cast
(Ice::IceType_NUM) < static_cast
(EmulatedBits), "Ice::Type overlaps with our emulated types!"); return (Ice::Type)(reinterpret_cast
(t) & ~EmulatedBits); } Type *T(Ice::Type t) { return reinterpret_cast
(t); } Type *T(EmulatedType t) { return reinterpret_cast
(t); } Value *V(Ice::Operand *v) { return reinterpret_cast
(v); } BasicBlock *B(Ice::CfgNode *b) { return reinterpret_cast
(b); } static size_t typeSize(Type *type) { if(reinterpret_cast
(type) & EmulatedBits) { switch(reinterpret_cast
(type)) { case Type_v2i32: return 8; case Type_v4i16: return 8; case Type_v2i16: return 4; case Type_v8i8: return 8; case Type_v4i8: return 4; case Type_v2f32: return 8; default: assert(false); } } return Ice::typeWidthInBytes(T(type)); } Optimization optimization[10] = {InstructionCombining, Disabled}; using ElfHeader = std::conditional
::type; using SectionHeader = std::conditional
::type; inline const SectionHeader *sectionHeader(const ElfHeader *elfHeader) { return reinterpret_cast
((intptr_t)elfHeader + elfHeader->e_shoff); } inline const SectionHeader *elfSection(const ElfHeader *elfHeader, int index) { return §ionHeader(elfHeader)[index]; } static void *relocateSymbol(const ElfHeader *elfHeader, const Elf32_Rel &relocation, const SectionHeader &relocationTable) { const SectionHeader *target = elfSection(elfHeader, relocationTable.sh_info); uint32_t index = relocation.getSymbol(); int table = relocationTable.sh_link; void *symbolValue = nullptr; if(index != SHN_UNDEF) { if(table == SHN_UNDEF) return nullptr; const SectionHeader *symbolTable = elfSection(elfHeader, table); uint32_t symtab_entries = symbolTable->sh_size / symbolTable->sh_entsize; if(index >= symtab_entries) { assert(index < symtab_entries && "Symbol Index out of range"); return nullptr; } intptr_t symbolAddress = (intptr_t)elfHeader + symbolTable->sh_offset; Elf32_Sym &symbol = ((Elf32_Sym*)symbolAddress)[index]; uint16_t section = symbol.st_shndx; if(section != SHN_UNDEF && section < SHN_LORESERVE) { const SectionHeader *target = elfSection(elfHeader, symbol.st_shndx); symbolValue = reinterpret_cast
((intptr_t)elfHeader + symbol.st_value + target->sh_offset); } else { return nullptr; } } intptr_t address = (intptr_t)elfHeader + target->sh_offset; unaligned_ptr
patchSite = (int32_t*)(address + relocation.r_offset); if(CPUID::ARM) { switch(relocation.getType()) { case R_ARM_NONE: // No relocation break; case R_ARM_MOVW_ABS_NC: { uint32_t thumb = 0; // Calls to Thumb code not supported. uint32_t lo = (uint32_t)(intptr_t)symbolValue | thumb; *patchSite = (*patchSite & 0xFFF0F000) | ((lo & 0xF000) << 4) | (lo & 0x0FFF); } break; case R_ARM_MOVT_ABS: { uint32_t hi = (uint32_t)(intptr_t)(symbolValue) >> 16; *patchSite = (*patchSite & 0xFFF0F000) | ((hi & 0xF000) << 4) | (hi & 0x0FFF); } break; default: assert(false && "Unsupported relocation type"); return nullptr; } } else { switch(relocation.getType()) { case R_386_NONE: // No relocation break; case R_386_32: *patchSite = (int32_t)((intptr_t)symbolValue + *patchSite); break; // case R_386_PC32: // *patchSite = (int32_t)((intptr_t)symbolValue + *patchSite - (intptr_t)patchSite); // break; default: assert(false && "Unsupported relocation type"); return nullptr; } } return symbolValue; } static void *relocateSymbol(const ElfHeader *elfHeader, const Elf64_Rela &relocation, const SectionHeader &relocationTable) { const SectionHeader *target = elfSection(elfHeader, relocationTable.sh_info); uint32_t index = relocation.getSymbol(); int table = relocationTable.sh_link; void *symbolValue = nullptr; if(index != SHN_UNDEF) { if(table == SHN_UNDEF) return nullptr; const SectionHeader *symbolTable = elfSection(elfHeader, table); uint32_t symtab_entries = symbolTable->sh_size / symbolTable->sh_entsize; if(index >= symtab_entries) { assert(index < symtab_entries && "Symbol Index out of range"); return nullptr; } intptr_t symbolAddress = (intptr_t)elfHeader + symbolTable->sh_offset; Elf64_Sym &symbol = ((Elf64_Sym*)symbolAddress)[index]; uint16_t section = symbol.st_shndx; if(section != SHN_UNDEF && section < SHN_LORESERVE) { const SectionHeader *target = elfSection(elfHeader, symbol.st_shndx); symbolValue = reinterpret_cast
((intptr_t)elfHeader + symbol.st_value + target->sh_offset); } else { return nullptr; } } intptr_t address = (intptr_t)elfHeader + target->sh_offset; unaligned_ptr
patchSite32 = (int32_t*)(address + relocation.r_offset); unaligned_ptr
patchSite64 = (int64_t*)(address + relocation.r_offset); switch(relocation.getType()) { case R_X86_64_NONE: // No relocation break; case R_X86_64_64: *patchSite64 = (int64_t)((intptr_t)symbolValue + *patchSite64 + relocation.r_addend); break; case R_X86_64_PC32: *patchSite32 = (int32_t)((intptr_t)symbolValue + *patchSite32 - (intptr_t)patchSite32 + relocation.r_addend); break; case R_X86_64_32S: *patchSite32 = (int32_t)((intptr_t)symbolValue + *patchSite32 + relocation.r_addend); break; default: assert(false && "Unsupported relocation type"); return nullptr; } return symbolValue; } void *loadImage(uint8_t *const elfImage, size_t &codeSize) { ElfHeader *elfHeader = (ElfHeader*)elfImage; if(!elfHeader->checkMagic()) { return nullptr; } // Expect ELF bitness to match platform assert(sizeof(void*) == 8 ? elfHeader->getFileClass() == ELFCLASS64 : elfHeader->getFileClass() == ELFCLASS32); #if defined(__i386__) assert(sizeof(void*) == 4 && elfHeader->e_machine == EM_386); #elif defined(__x86_64__) assert(sizeof(void*) == 8 && elfHeader->e_machine == EM_X86_64); #elif defined(__arm__) assert(sizeof(void*) == 4 && elfHeader->e_machine == EM_ARM); #elif defined(__aarch64__) assert(sizeof(void*) == 8 && elfHeader->e_machine == EM_AARCH64); #elif defined(__mips__) assert(sizeof(void*) == 4 && elfHeader->e_machine == EM_MIPS); #else #error "Unsupported platform" #endif SectionHeader *sectionHeader = (SectionHeader*)(elfImage + elfHeader->e_shoff); void *entry = nullptr; for(int i = 0; i < elfHeader->e_shnum; i++) { if(sectionHeader[i].sh_type == SHT_PROGBITS) { if(sectionHeader[i].sh_flags & SHF_EXECINSTR) { entry = elfImage + sectionHeader[i].sh_offset; codeSize = sectionHeader[i].sh_size; } } else if(sectionHeader[i].sh_type == SHT_REL) { 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++) { const Elf32_Rel &relocation = ((const Elf32_Rel*)(elfImage + sectionHeader[i].sh_offset))[index]; relocateSymbol(elfHeader, relocation, sectionHeader[i]); } } else if(sectionHeader[i].sh_type == SHT_RELA) { 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++) { const Elf64_Rela &relocation = ((const Elf64_Rela*)(elfImage + sectionHeader[i].sh_offset))[index]; relocateSymbol(elfHeader, relocation, sectionHeader[i]); } } } return entry; } template
struct ExecutableAllocator { ExecutableAllocator() {}; template
ExecutableAllocator(const ExecutableAllocator
&other) {}; using value_type = T; using size_type = std::size_t; T *allocate(size_type n) { return (T*)allocateExecutable(sizeof(T) * n); } void deallocate(T *p, size_type n) { deallocateExecutable(p, sizeof(T) * n); } }; class ELFMemoryStreamer : public Ice::ELFStreamer, public Routine { ELFMemoryStreamer(const ELFMemoryStreamer &) = delete; ELFMemoryStreamer &operator=(const ELFMemoryStreamer &) = delete; public: ELFMemoryStreamer() : Routine(), entry(nullptr) { position = 0; buffer.reserve(0x1000); } ~ELFMemoryStreamer() override { #if defined(_WIN32) if(buffer.size() != 0) { DWORD exeProtection; VirtualProtect(&buffer[0], buffer.size(), oldProtection, &exeProtection); } #endif } void write8(uint8_t Value) override { if(position == (uint64_t)buffer.size()) { buffer.push_back(Value); position++; } else if(position < (uint64_t)buffer.size()) { buffer[position] = Value; position++; } else assert(false && "UNIMPLEMENTED"); } void writeBytes(llvm::StringRef Bytes) override { std::size_t oldSize = buffer.size(); buffer.resize(oldSize + Bytes.size()); memcpy(&buffer[oldSize], Bytes.begin(), Bytes.size()); position += Bytes.size(); } uint64_t tell() const override { return position; } void seek(uint64_t Off) override { position = Off; } const void *getEntry() override { if(!entry) { position = std::numeric_limits
::max(); // Can't stream more data after this size_t codeSize = 0; entry = loadImage(&buffer[0], codeSize); #if defined(_WIN32) VirtualProtect(&buffer[0], buffer.size(), PAGE_EXECUTE_READ, &oldProtection); FlushInstructionCache(GetCurrentProcess(), NULL, 0); #else mprotect(&buffer[0], buffer.size(), PROT_READ | PROT_EXEC); __builtin___clear_cache((char*)entry, (char*)entry + codeSize); #endif } return entry; } private: void *entry; std::vector
> buffer; std::size_t position; #if defined(_WIN32) DWORD oldProtection; #endif }; Nucleus::Nucleus() { ::codegenMutex.lock(); // Reactor is currently not thread safe Ice::ClFlags &Flags = Ice::ClFlags::Flags; Ice::ClFlags::getParsedClFlags(Flags); #if defined(__arm__) Flags.setTargetArch(Ice::Target_ARM32); Flags.setTargetInstructionSet(Ice::ARM32InstructionSet_HWDivArm); #elif defined(__mips__) Flags.setTargetArch(Ice::Target_MIPS32); Flags.setTargetInstructionSet(Ice::BaseInstructionSet); #else // x86 Flags.setTargetArch(sizeof(void*) == 8 ? Ice::Target_X8664 : Ice::Target_X8632); Flags.setTargetInstructionSet(CPUID::SSE4_1 ? Ice::X86InstructionSet_SSE4_1 : Ice::X86InstructionSet_SSE2); #endif Flags.setOutFileType(Ice::FT_Elf); Flags.setOptLevel(Ice::Opt_2); Flags.setApplicationBinaryInterface(Ice::ABI_Platform); Flags.setVerbose(false ? Ice::IceV_Most : Ice::IceV_None); Flags.setDisableHybridAssembly(true); static llvm::raw_os_ostream cout(std::cout); static llvm::raw_os_ostream cerr(std::cerr); if(false) // Write out to a file { std::error_code errorCode; ::out = new Ice::Fdstream("out.o", errorCode, llvm::sys::fs::F_None); ::elfFile = new Ice::ELFFileStreamer(*out); ::context = new Ice::GlobalContext(&cout, &cout, &cerr, elfFile); } else { ELFMemoryStreamer *elfMemory = new ELFMemoryStreamer(); ::context = new Ice::GlobalContext(&cout, &cout, &cerr, elfMemory); ::routine = elfMemory; } } Nucleus::~Nucleus() { delete ::routine; delete ::allocator; delete ::function; delete ::context; delete ::elfFile; delete ::out; ::codegenMutex.unlock(); } Routine *Nucleus::acquireRoutine(const char *name, bool runOptimizations) { if(basicBlock->getInsts().empty() || basicBlock->getInsts().back().getKind() != Ice::Inst::Ret) { createRetVoid(); } ::function->setFunctionName(Ice::GlobalString::createWithString(::context, name)); optimize(); ::function->translate(); assert(!::function->hasError()); auto globals = ::function->getGlobalInits(); if(globals && !globals->empty()) { ::context->getGlobals()->merge(globals.get()); } ::context->emitFileHeader(); ::function->emitIAS(); auto assembler = ::function->releaseAssembler(); auto objectWriter = ::context->getObjectWriter(); assembler->alignFunction(); objectWriter->writeFunctionCode(::function->getFunctionName(), false, assembler.get()); ::context->lowerGlobals("last"); ::context->lowerConstants(); ::context->lowerJumpTables(); objectWriter->setUndefinedSyms(::context->getConstantExternSyms()); objectWriter->writeNonUserSections(); Routine *handoffRoutine = ::routine; ::routine = nullptr; return handoffRoutine; } void Nucleus::optimize() { rr::optimize(::function); } Value *Nucleus::allocateStackVariable(Type *t, int arraySize) { Ice::Type type = T(t); int typeSize = Ice::typeWidthInBytes(type); int totalSize = typeSize * (arraySize ? arraySize : 1); auto bytes = Ice::ConstantInteger32::create(::context, type, totalSize); auto address = ::function->makeVariable(T(getPointerType(t))); auto alloca = Ice::InstAlloca::create(::function, address, bytes, typeSize); ::function->getEntryNode()->getInsts().push_front(alloca); return V(address); } BasicBlock *Nucleus::createBasicBlock() { return B(::function->makeNode()); } BasicBlock *Nucleus::getInsertBlock() { return B(::basicBlock); } void Nucleus::setInsertBlock(BasicBlock *basicBlock) { // assert(::basicBlock->getInsts().back().getTerminatorEdges().size() >= 0 && "Previous basic block must have a terminator"); ::basicBlock = basicBlock; } void Nucleus::createFunction(Type *ReturnType, std::vector
&Params) { uint32_t sequenceNumber = 0; ::function = Ice::Cfg::create(::context, sequenceNumber).release(); ::allocator = new Ice::CfgLocalAllocatorScope(::function); for(Type *type : Params) { Ice::Variable *arg = ::function->makeVariable(T(type)); ::function->addArg(arg); } Ice::CfgNode *node = ::function->makeNode(); ::function->setEntryNode(node); ::basicBlock = node; } Value *Nucleus::getArgument(unsigned int index) { return V(::function->getArgs()[index]); } void Nucleus::createRetVoid() { Ice::InstRet *ret = Ice::InstRet::create(::function); ::basicBlock->appendInst(ret); } void Nucleus::createRet(Value *v) { Ice::InstRet *ret = Ice::InstRet::create(::function, v); ::basicBlock->appendInst(ret); } void Nucleus::createBr(BasicBlock *dest) { auto br = Ice::InstBr::create(::function, dest); ::basicBlock->appendInst(br); } void Nucleus::createCondBr(Value *cond, BasicBlock *ifTrue, BasicBlock *ifFalse) { auto br = Ice::InstBr::create(::function, cond, ifTrue, ifFalse); ::basicBlock->appendInst(br); } static bool isCommutative(Ice::InstArithmetic::OpKind op) { switch(op) { case Ice::InstArithmetic::Add: case Ice::InstArithmetic::Fadd: case Ice::InstArithmetic::Mul: case Ice::InstArithmetic::Fmul: case Ice::InstArithmetic::And: case Ice::InstArithmetic::Or: case Ice::InstArithmetic::Xor: return true; default: return false; } } static Value *createArithmetic(Ice::InstArithmetic::OpKind op, Value *lhs, Value *rhs) { assert(lhs->getType() == rhs->getType() || llvm::isa
(rhs)); bool swapOperands = llvm::isa
(lhs) && isCommutative(op); Ice::Variable *result = ::function->makeVariable(lhs->getType()); Ice::InstArithmetic *arithmetic = Ice::InstArithmetic::create(::function, op, result, swapOperands ? rhs : lhs, swapOperands ? lhs : rhs); ::basicBlock->appendInst(arithmetic); return V(result); } Value *Nucleus::createAdd(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Add, lhs, rhs); } Value *Nucleus::createSub(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Sub, lhs, rhs); } Value *Nucleus::createMul(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Mul, lhs, rhs); } Value *Nucleus::createUDiv(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Udiv, lhs, rhs); } Value *Nucleus::createSDiv(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Sdiv, lhs, rhs); } Value *Nucleus::createFAdd(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Fadd, lhs, rhs); } Value *Nucleus::createFSub(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Fsub, lhs, rhs); } Value *Nucleus::createFMul(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Fmul, lhs, rhs); } Value *Nucleus::createFDiv(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Fdiv, lhs, rhs); } Value *Nucleus::createURem(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Urem, lhs, rhs); } Value *Nucleus::createSRem(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Srem, lhs, rhs); } Value *Nucleus::createFRem(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Frem, lhs, rhs); } Value *Nucleus::createShl(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Shl, lhs, rhs); } Value *Nucleus::createLShr(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Lshr, lhs, rhs); } Value *Nucleus::createAShr(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Ashr, lhs, rhs); } Value *Nucleus::createAnd(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::And, lhs, rhs); } Value *Nucleus::createOr(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Or, lhs, rhs); } Value *Nucleus::createXor(Value *lhs, Value *rhs) { return createArithmetic(Ice::InstArithmetic::Xor, lhs, rhs); } Value *Nucleus::createNeg(Value *v) { return createSub(createNullValue(T(v->getType())), v); } Value *Nucleus::createFNeg(Value *v) { double c[4] = {-0.0, -0.0, -0.0, -0.0}; Value *negativeZero = Ice::isVectorType(v->getType()) ? createConstantVector(c, T(v->getType())) : V(::context->getConstantFloat(-0.0f)); return createFSub(negativeZero, v); } Value *Nucleus::createNot(Value *v) { if(Ice::isScalarIntegerType(v->getType())) { return createXor(v, V(::context->getConstantInt(v->getType(), -1))); } else // Vector { int64_t c[16] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; return createXor(v, createConstantVector(c, T(v->getType()))); } } Value *Nucleus::createLoad(Value *ptr, Type *type, bool isVolatile, unsigned int align) { int valueType = (int)reinterpret_cast
(type); Ice::Variable *result = ::function->makeVariable(T(type)); if((valueType & EmulatedBits) && (align != 0)) // Narrow vector not stored on stack. { if(emulateIntrinsics) { if(typeSize(type) == 4) { auto pointer = RValue
>(ptr); Int x = *Pointer
(pointer); Int4 vector; vector = Insert(vector, x, 0); auto bitcast = Ice::InstCast::create(::function, Ice::InstCast::Bitcast, result, vector.loadValue()); ::basicBlock->appendInst(bitcast); } else if(typeSize(type) == 8) { auto pointer = RValue
>(ptr); Int x = *Pointer
(pointer); Int y = *Pointer
(pointer + 4); Int4 vector; vector = Insert(vector, x, 0); vector = Insert(vector, y, 1); auto bitcast = Ice::InstCast::create(::function, Ice::InstCast::Bitcast, result, vector.loadValue()); ::basicBlock->appendInst(bitcast); } else assert(false); } else { const Ice::Intrinsics::IntrinsicInfo intrinsic = {Ice::Intrinsics::LoadSubVector, Ice::Intrinsics::SideEffects_F, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F}; auto target = ::context->getConstantUndef(Ice::IceType_i32); auto load = Ice::InstIntrinsicCall::create(::function, 2, result, target, intrinsic); load->addArg(ptr); load->addArg(::context->getConstantInt32(typeSize(type))); ::basicBlock->appendInst(load); } } else { auto load = Ice::InstLoad::create(::function, result, ptr, align); ::basicBlock->appendInst(load); } return V(result); } Value *Nucleus::createStore(Value *value, Value *ptr, Type *type, bool isVolatile, unsigned int align) { #if __has_feature(memory_sanitizer) // Mark all (non-stack) memory writes as initialized by calling __msan_unpoison if(align != 0) { auto call = Ice::InstCall::create(::function, 2, nullptr, ::context->getConstantInt64(reinterpret_cast
(__msan_unpoison)), false); call->addArg(ptr); call->addArg(::context->getConstantInt64(typeSize(type))); ::basicBlock->appendInst(call); } #endif int valueType = (int)reinterpret_cast
(type); if((valueType & EmulatedBits) && (align != 0)) // Narrow vector not stored on stack. { if(emulateIntrinsics) { if(typeSize(type) == 4) { Ice::Variable *vector = ::function->makeVariable(Ice::IceType_v4i32); auto bitcast = Ice::InstCast::create(::function, Ice::InstCast::Bitcast, vector, value); ::basicBlock->appendInst(bitcast); RValue
v(V(vector)); auto pointer = RValue
>(ptr); Int x = Extract(v, 0); *Pointer
(pointer) = x; } else if(typeSize(type) == 8) { Ice::Variable *vector = ::function->makeVariable(Ice::IceType_v4i32); auto bitcast = Ice::InstCast::create(::function, Ice::InstCast::Bitcast, vector, value); ::basicBlock->appendInst(bitcast); RValue
v(V(vector)); auto pointer = RValue
>(ptr); Int x = Extract(v, 0); *Pointer
(pointer) = x; Int y = Extract(v, 1); *Pointer
(pointer + 4) = y; } else assert(false); } else { const Ice::Intrinsics::IntrinsicInfo intrinsic = {Ice::Intrinsics::StoreSubVector, Ice::Intrinsics::SideEffects_T, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_T}; auto target = ::context->getConstantUndef(Ice::IceType_i32); auto store = Ice::InstIntrinsicCall::create(::function, 3, nullptr, target, intrinsic); store->addArg(value); store->addArg(ptr); store->addArg(::context->getConstantInt32(typeSize(type))); ::basicBlock->appendInst(store); } } else { assert(value->getType() == T(type)); auto store = Ice::InstStore::create(::function, value, ptr, align); ::basicBlock->appendInst(store); } return value; } Value *Nucleus::createGEP(Value *ptr, Type *type, Value *index, bool unsignedIndex) { assert(index->getType() == Ice::IceType_i32); if(auto *constant = llvm::dyn_cast
(index)) { int32_t offset = constant->getValue() * (int)typeSize(type); if(offset == 0) { return ptr; } return createAdd(ptr, createConstantInt(offset)); } if(!Ice::isByteSizedType(T(type))) { index = createMul(index, createConstantInt((int)typeSize(type))); } if(sizeof(void*) == 8) { if(unsignedIndex) { index = createZExt(index, T(Ice::IceType_i64)); } else { index = createSExt(index, T(Ice::IceType_i64)); } } return createAdd(ptr, index); } Value *Nucleus::createAtomicAdd(Value *ptr, Value *value) { assert(false && "UNIMPLEMENTED"); return nullptr; } static Value *createCast(Ice::InstCast::OpKind op, Value *v, Type *destType) { if(v->getType() == T(destType)) { return v; } Ice::Variable *result = ::function->makeVariable(T(destType)); Ice::InstCast *cast = Ice::InstCast::create(::function, op, result, v); ::basicBlock->appendInst(cast); return V(result); } Value *Nucleus::createTrunc(Value *v, Type *destType) { return createCast(Ice::InstCast::Trunc, v, destType); } Value *Nucleus::createZExt(Value *v, Type *destType) { return createCast(Ice::InstCast::Zext, v, destType); } Value *Nucleus::createSExt(Value *v, Type *destType) { return createCast(Ice::InstCast::Sext, v, destType); } Value *Nucleus::createFPToSI(Value *v, Type *destType) { return createCast(Ice::InstCast::Fptosi, v, destType); } Value *Nucleus::createSIToFP(Value *v, Type *destType) { return createCast(Ice::InstCast::Sitofp, v, destType); } Value *Nucleus::createFPTrunc(Value *v, Type *destType) { return createCast(Ice::InstCast::Fptrunc, v, destType); } Value *Nucleus::createFPExt(Value *v, Type *destType) { return createCast(Ice::InstCast::Fpext, v, destType); } Value *Nucleus::createBitCast(Value *v, Type *destType) { // Bitcasts must be between types of the same logical size. But with emulated narrow vectors we need // support for casting between scalars and wide vectors. For platforms where this is not supported, // emulate them by writing to the stack and reading back as the destination type. if(emulateMismatchedBitCast) { if(!Ice::isVectorType(v->getType()) && Ice::isVectorType(T(destType))) { Value *address = allocateStackVariable(destType); createStore(v, address, T(v->getType())); return createLoad(address, destType); } else if(Ice::isVectorType(v->getType()) && !Ice::isVectorType(T(destType))) { Value *address = allocateStackVariable(T(v->getType())); createStore(v, address, T(v->getType())); return createLoad(address, destType); } } return createCast(Ice::InstCast::Bitcast, v, destType); } static Value *createIntCompare(Ice::InstIcmp::ICond condition, Value *lhs, Value *rhs) { 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); ::basicBlock->appendInst(cmp); return V(result); } Value *Nucleus::createICmpEQ(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Eq, lhs, rhs); } Value *Nucleus::createICmpNE(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Ne, lhs, rhs); } Value *Nucleus::createICmpUGT(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Ugt, lhs, rhs); } Value *Nucleus::createICmpUGE(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Uge, lhs, rhs); } Value *Nucleus::createICmpULT(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Ult, lhs, rhs); } Value *Nucleus::createICmpULE(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Ule, lhs, rhs); } Value *Nucleus::createICmpSGT(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Sgt, lhs, rhs); } Value *Nucleus::createICmpSGE(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Sge, lhs, rhs); } Value *Nucleus::createICmpSLT(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Slt, lhs, rhs); } Value *Nucleus::createICmpSLE(Value *lhs, Value *rhs) { return createIntCompare(Ice::InstIcmp::Sle, lhs, rhs); } 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); auto result = ::function->makeVariable(Ice::isScalarFloatingType(lhs->getType()) ? Ice::IceType_i1 : Ice::IceType_v4i32); auto cmp = Ice::InstFcmp::create(::function, condition, result, lhs, rhs); ::basicBlock->appendInst(cmp); return V(result); } Value *Nucleus::createFCmpOEQ(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Oeq, lhs, rhs); } Value *Nucleus::createFCmpOGT(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Ogt, lhs, rhs); } Value *Nucleus::createFCmpOGE(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Oge, lhs, rhs); } Value *Nucleus::createFCmpOLT(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Olt, lhs, rhs); } Value *Nucleus::createFCmpOLE(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Ole, lhs, rhs); } Value *Nucleus::createFCmpONE(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::One, lhs, rhs); } Value *Nucleus::createFCmpORD(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Ord, lhs, rhs); } Value *Nucleus::createFCmpUNO(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Uno, lhs, rhs); } Value *Nucleus::createFCmpUEQ(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Ueq, lhs, rhs); } Value *Nucleus::createFCmpUGT(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Ugt, lhs, rhs); } Value *Nucleus::createFCmpUGE(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Uge, lhs, rhs); } Value *Nucleus::createFCmpULT(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Ult, lhs, rhs); } Value *Nucleus::createFCmpULE(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Ule, lhs, rhs); } Value *Nucleus::createFCmpUNE(Value *lhs, Value *rhs) { return createFloatCompare(Ice::InstFcmp::Une, lhs, rhs); } 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)); ::basicBlock->appendInst(extract); return V(result); } Value *Nucleus::createInsertElement(Value *vector, Value *element, int index) { auto result = ::function->makeVariable(vector->getType()); auto insert = Ice::InstInsertElement::create(::function, result, vector, element, ::context->getConstantInt32(index)); ::basicBlock->appendInst(insert); return V(result); } Value *Nucleus::createShuffleVector(Value *V1, Value *V2, const int *select) { assert(V1->getType() == V2->getType()); int size = Ice::typeNumElements(V1->getType()); auto result = ::function->makeVariable(V1->getType()); auto shuffle = Ice::InstShuffleVector::create(::function, result, V1, V2); for(int i = 0; i < size; i++) { shuffle->addIndex(llvm::cast
(::context->getConstantInt32(select[i]))); } ::basicBlock->appendInst(shuffle); return V(result); } Value *Nucleus::createSelect(Value *C, Value *ifTrue, Value *ifFalse) { assert(ifTrue->getType() == ifFalse->getType()); auto result = ::function->makeVariable(ifTrue->getType()); auto *select = Ice::InstSelect::create(::function, result, C, ifTrue, ifFalse); ::basicBlock->appendInst(select); return V(result); } SwitchCases *Nucleus::createSwitch(Value *control, BasicBlock *defaultBranch, unsigned numCases) { auto switchInst = Ice::InstSwitch::create(::function, numCases, control, defaultBranch); ::basicBlock->appendInst(switchInst); return reinterpret_cast
(switchInst); } void Nucleus::addSwitchCase(SwitchCases *switchCases, int label, BasicBlock *branch) { switchCases->addBranch(label, label, branch); } void Nucleus::createUnreachable() { Ice::InstUnreachable *unreachable = Ice::InstUnreachable::create(::function); ::basicBlock->appendInst(unreachable); } static Value *createSwizzle4(Value *val, unsigned char select) { int swizzle[4] = { (select >> 0) & 0x03, (select >> 2) & 0x03, (select >> 4) & 0x03, (select >> 6) & 0x03, }; return Nucleus::createShuffleVector(val, val, swizzle); } static Value *createMask4(Value *lhs, Value *rhs, unsigned char select) { int64_t mask[4] = {0, 0, 0, 0}; mask[(select >> 0) & 0x03] = -1; mask[(select >> 2) & 0x03] = -1; mask[(select >> 4) & 0x03] = -1; mask[(select >> 6) & 0x03] = -1; Value *condition = Nucleus::createConstantVector(mask, T(Ice::IceType_v4i1)); Value *result = Nucleus::createSelect(condition, rhs, lhs); return result; } Type *Nucleus::getPointerType(Type *ElementType) { if(sizeof(void*) == 8) { return T(Ice::IceType_i64); } else { return T(Ice::IceType_i32); } } Value *Nucleus::createNullValue(Type *Ty) { if(Ice::isVectorType(T(Ty))) { 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); } else { return V(::context->getConstantZero(T(Ty))); } } Value *Nucleus::createConstantLong(int64_t i) { return V(::context->getConstantInt64(i)); } Value *Nucleus::createConstantInt(int i) { return V(::context->getConstantInt32(i)); } Value *Nucleus::createConstantInt(unsigned int i) { return V(::context->getConstantInt32(i)); } Value *Nucleus::createConstantBool(bool b) { return V(::context->getConstantInt1(b)); } Value *Nucleus::createConstantByte(signed char i) { return V(::context->getConstantInt8(i)); } Value *Nucleus::createConstantByte(unsigned char i) { return V(::context->getConstantInt8(i)); } Value *Nucleus::createConstantShort(short i) { return V(::context->getConstantInt16(i)); } Value *Nucleus::createConstantShort(unsigned short i) { return V(::context->getConstantInt16(i)); } Value *Nucleus::createConstantFloat(float x) { return V(::context->getConstantFloat(x)); } Value *Nucleus::createNullPointer(Type *Ty) { return createNullValue(T(sizeof(void*) == 8 ? Ice::IceType_i64 : Ice::IceType_i32)); } Value *Nucleus::createConstantVector(const int64_t *constants, Type *type) { const int vectorSize = 16; assert(Ice::typeWidthInBytes(T(type)) == vectorSize); const int alignment = vectorSize; auto globalPool = ::function->getGlobalPool(); const int64_t *i = constants; const double *f = reinterpret_cast
(constants); Ice::VariableDeclaration::DataInitializer *dataInitializer = nullptr; switch((int)reinterpret_cast
(type)) { case Ice::IceType_v4i32: case Ice::IceType_v4i1: { const int initializer[4] = {(int)i[0], (int)i[1], (int)i[2], (int)i[3]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; case Ice::IceType_v4f32: { const float initializer[4] = {(float)f[0], (float)f[1], (float)f[2], (float)f[3]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; case Ice::IceType_v8i16: case Ice::IceType_v8i1: { const short initializer[8] = {(short)i[0], (short)i[1], (short)i[2], (short)i[3], (short)i[4], (short)i[5], (short)i[6], (short)i[7]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; case Ice::IceType_v16i8: case Ice::IceType_v16i1: { const char initializer[16] = {(char)i[0], (char)i[1], (char)i[2], (char)i[3], (char)i[4], (char)i[5], (char)i[6], (char)i[7], (char)i[8], (char)i[9], (char)i[10], (char)i[11], (char)i[12], (char)i[13], (char)i[14], (char)i[15]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; case Type_v2i32: { const int initializer[4] = {(int)i[0], (int)i[1], (int)i[0], (int)i[1]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; case Type_v2f32: { const float initializer[4] = {(float)f[0], (float)f[1], (float)f[0], (float)f[1]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; case Type_v4i16: { const short initializer[8] = {(short)i[0], (short)i[1], (short)i[2], (short)i[3], (short)i[0], (short)i[1], (short)i[2], (short)i[3]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; case Type_v8i8: { const char initializer[16] = {(char)i[0], (char)i[1], (char)i[2], (char)i[3], (char)i[4], (char)i[5], (char)i[6], (char)i[7], (char)i[0], (char)i[1], (char)i[2], (char)i[3], (char)i[4], (char)i[5], (char)i[6], (char)i[7]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; case Type_v4i8: { const char initializer[16] = {(char)i[0], (char)i[1], (char)i[2], (char)i[3], (char)i[0], (char)i[1], (char)i[2], (char)i[3], (char)i[0], (char)i[1], (char)i[2], (char)i[3], (char)i[0], (char)i[1], (char)i[2], (char)i[3]}; static_assert(sizeof(initializer) == vectorSize, "!"); dataInitializer = Ice::VariableDeclaration::DataInitializer::create(globalPool, (const char*)initializer, vectorSize); } break; default: assert(false && "Unknown constant vector type" && type); } auto name = Ice::GlobalString::createWithoutString(::context); auto *variableDeclaration = Ice::VariableDeclaration::create(globalPool); variableDeclaration->setName(name); variableDeclaration->setAlignment(alignment); variableDeclaration->setIsConstant(true); variableDeclaration->addInitializer(dataInitializer); ::function->addGlobal(variableDeclaration); constexpr int32_t offset = 0; Ice::Operand *ptr = ::context->getConstantSym(offset, name); Ice::Variable *result = ::function->makeVariable(T(type)); auto load = Ice::InstLoad::create(::function, result, ptr, alignment); ::basicBlock->appendInst(load); return V(result); } Value *Nucleus::createConstantVector(const double *constants, Type *type) { return createConstantVector((const int64_t*)constants, type); } Type *Void::getType() { return T(Ice::IceType_void); } Bool::Bool(Argument
argument) { storeValue(argument.value); } Bool::Bool(bool x) { storeValue(Nucleus::createConstantBool(x)); } Bool::Bool(RValue
rhs) { storeValue(rhs.value); } Bool::Bool(const Bool &rhs) { Value *value = rhs.loadValue(); storeValue(value); } Bool::Bool(const Reference
&rhs) { Value *value = rhs.loadValue(); storeValue(value); } RValue
Bool::operator=(RValue
rhs) { storeValue(rhs.value); return rhs; } RValue
Bool::operator=(const Bool &rhs) { Value *value = rhs.loadValue(); storeValue(value); return RValue
(value); } RValue
Bool::operator=(const Reference
&rhs) { Value *value = rhs.loadValue(); storeValue(value); return RValue
(value); } RValue
operator!(RValue
val) { return RValue
(Nucleus::createNot(val.value)); } RValue
operator&&(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createAnd(lhs.value, rhs.value)); } RValue
operator||(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createOr(lhs.value, rhs.value)); } Type *Bool::getType() { return T(Ice::IceType_i1); } Byte::Byte(Argument
argument) { storeValue(argument.value); } Byte::Byte(RValue
cast) { Value *integer = Nucleus::createTrunc(cast.value, Byte::getType()); storeValue(integer); } Byte::Byte(RValue
cast) { Value *integer = Nucleus::createTrunc(cast.value, Byte::getType()); storeValue(integer); } Byte::Byte(RValue
cast) { Value *integer = Nucleus::createTrunc(cast.value, Byte::getType()); storeValue(integer); } Byte::Byte(int x) { storeValue(Nucleus::createConstantByte((unsigned char)x)); } Byte::Byte(unsigned char x) { storeValue(Nucleus::createConstantByte(x)); } Byte::Byte(RValue
rhs) { storeValue(rhs.value); } Byte::Byte(const Byte &rhs) { Value *value = rhs.loadValue(); storeValue(value); } Byte::Byte(const Reference
&rhs) { Value *value = rhs.loadValue(); storeValue(value); } RValue
Byte::operator=(RValue
rhs) { storeValue(rhs.value); return rhs; } RValue
Byte::operator=(const Byte &rhs) { Value *value = rhs.loadValue(); storeValue(value); return RValue
(value); } RValue
Byte::operator=(const Reference
&rhs) { Value *value = rhs.loadValue(); storeValue(value); return RValue
(value); } RValue
operator+(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createAdd(lhs.value, rhs.value)); } RValue
operator-(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createSub(lhs.value, rhs.value)); } RValue
operator*(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createMul(lhs.value, rhs.value)); } RValue
operator/(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createUDiv(lhs.value, rhs.value)); } RValue
operator%(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createURem(lhs.value, rhs.value)); } RValue
operator&(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createAnd(lhs.value, rhs.value)); } RValue
operator|(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createOr(lhs.value, rhs.value)); } RValue
operator^(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createXor(lhs.value, rhs.value)); } RValue
operator<<(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createShl(lhs.value, rhs.value)); } RValue
operator>>(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createLShr(lhs.value, rhs.value)); } RValue
operator+=(Byte &lhs, RValue
rhs) { return lhs = lhs + rhs; } RValue
operator-=(Byte &lhs, RValue
rhs) { return lhs = lhs - rhs; } RValue
operator*=(Byte &lhs, RValue
rhs) { return lhs = lhs * rhs; } RValue
operator/=(Byte &lhs, RValue
rhs) { return lhs = lhs / rhs; } RValue
operator%=(Byte &lhs, RValue
rhs) { return lhs = lhs % rhs; } RValue
operator&=(Byte &lhs, RValue
rhs) { return lhs = lhs & rhs; } RValue
operator|=(Byte &lhs, RValue
rhs) { return lhs = lhs | rhs; } RValue
operator^=(Byte &lhs, RValue
rhs) { return lhs = lhs ^ rhs; } RValue
operator<<=(Byte &lhs, RValue
rhs) { return lhs = lhs << rhs; } RValue
operator>>=(Byte &lhs, RValue
rhs) { return lhs = lhs >> rhs; } RValue
operator+(RValue
val) { return val; } RValue
operator-(RValue
val) { return RValue
(Nucleus::createNeg(val.value)); } RValue
operator~(RValue
val) { return RValue
(Nucleus::createNot(val.value)); } RValue
operator++(Byte &val, int) // Post-increment { RValue
res = val; val += Byte(1); return res; } const Byte &operator++(Byte &val) // Pre-increment { val += Byte(1); return val; } RValue
operator--(Byte &val, int) // Post-decrement { RValue
res = val; val -= Byte(1); return res; } const Byte &operator--(Byte &val) // Pre-decrement { val -= Byte(1); return val; } RValue
operator<(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createICmpULT(lhs.value, rhs.value)); } RValue
operator<=(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createICmpULE(lhs.value, rhs.value)); } RValue
operator>(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createICmpUGT(lhs.value, rhs.value)); } RValue
operator>=(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createICmpUGE(lhs.value, rhs.value)); } RValue
operator!=(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createICmpNE(lhs.value, rhs.value)); } RValue
operator==(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createICmpEQ(lhs.value, rhs.value)); } Type *Byte::getType() { return T(Ice::IceType_i8); } SByte::SByte(Argument
argument) { storeValue(argument.value); } SByte::SByte(RValue
cast) { Value *integer = Nucleus::createTrunc(cast.value, SByte::getType()); storeValue(integer); } SByte::SByte(RValue
cast) { Value *integer = Nucleus::createTrunc(cast.value, SByte::getType()); storeValue(integer); } SByte::SByte(signed char x) { storeValue(Nucleus::createConstantByte(x)); } SByte::SByte(RValue
rhs) { storeValue(rhs.value); } SByte::SByte(const SByte &rhs) { Value *value = rhs.loadValue(); storeValue(value); } SByte::SByte(const Reference
&rhs) { Value *value = rhs.loadValue(); storeValue(value); } RValue
SByte::operator=(RValue
rhs) { storeValue(rhs.value); return rhs; } RValue
SByte::operator=(const SByte &rhs) { Value *value = rhs.loadValue(); storeValue(value); return RValue
(value); } RValue
SByte::operator=(const Reference
&rhs) { Value *value = rhs.loadValue(); storeValue(value); return RValue
(value); } RValue
operator+(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createAdd(lhs.value, rhs.value)); } RValue
operator-(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createSub(lhs.value, rhs.value)); } RValue
operator*(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createMul(lhs.value, rhs.value)); } RValue
operator/(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createSDiv(lhs.value, rhs.value)); } RValue
operator%(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createSRem(lhs.value, rhs.value)); } RValue
operator&(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createAnd(lhs.value, rhs.value)); } RValue
operator|(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createOr(lhs.value, rhs.value)); } RValue
operator^(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createXor(lhs.value, rhs.value)); } RValue
operator<<(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createShl(lhs.value, rhs.value)); } RValue
operator>>(RValue
lhs, RValue
rhs) { return RValue
(Nucleus::createAShr(lhs.value, rhs.value)); } RValue
operator+=(SByte &lhs, RValue
rhs) { return lhs = lhs + rhs; } RValue
operator-=(SByte &lhs, RValue
rhs) { return lhs = lhs - rhs; } RValue
operator*=(SByte &lhs, RValue
rhs) { return lhs = lhs * rhs; } RValue
operator/=(SByte &lhs, RValue
rhs) { return lhs = lhs / rhs; } RValue
operator%=(SByte &lhs, RValue
rhs) { return lhs = lhs % rhs; } RValue
operator&=(SByte &lhs, RValue
rhs) { return lhs = lhs & rhs; } RValue
operator|=(SByte &lhs, RValue
rhs) { return lhs = lhs | rhs; } RValue
operator^=(SByte &lhs, RValue
rhs) { return lhs = lhs ^ rhs; } RValue
operator<<=(SByte &lhs, RValue
rhs) { return lhs = lhs << rhs; } RValue
operator>>=(SByte &lhs, RValue