diff --git a/src/alloy/alloy-private.h b/src/alloy/alloy-private.h index 213b4bfad..a22be71c4 100644 --- a/src/alloy/alloy-private.h +++ b/src/alloy/alloy-private.h @@ -18,6 +18,8 @@ DECLARE_bool(debug); DECLARE_bool(always_disasm); +DECLARE_bool(validate_hir); + DECLARE_uint64(break_on_instruction); DECLARE_uint64(break_on_memory); diff --git a/src/alloy/alloy.cc b/src/alloy/alloy.cc index 714036f71..bae955976 100644 --- a/src/alloy/alloy.cc +++ b/src/alloy/alloy.cc @@ -21,10 +21,12 @@ using namespace alloy; DEFINE_bool(debug, DEFAULT_DEBUG_FLAG, "Allow debugging and retain debug information."); - DEFINE_bool(always_disasm, false, "Always add debug info to functions, even when no debugger is attached."); +DEFINE_bool(validate_hir, false, + "Perform validation checks on the HIR during compilation."); + // Breakpoints: DEFINE_uint64(break_on_instruction, 0, "int3 before the given guest address is executed."); diff --git a/src/alloy/backend/ivm/ivm_assembler.cc b/src/alloy/backend/ivm/ivm_assembler.cc index d2b08b964..b869d41ef 100644 --- a/src/alloy/backend/ivm/ivm_assembler.cc +++ b/src/alloy/backend/ivm/ivm_assembler.cc @@ -74,6 +74,15 @@ int IVMAssembler::Assemble( builder->ResetLabelTags(); // Function prologue. + size_t stack_size = 0; + auto locals = builder->locals(); + for (auto it = locals.begin(); it != locals.end(); ++it) { + auto slot = *it; + size_t stack_offset = stack_size; + slot->set_constant(stack_offset); + stack_size += GetTypeSize(slot->type); + } + ctx.stack_size = stack_size; auto block = builder->first_block(); while (block) { diff --git a/src/alloy/backend/ivm/ivm_function.cc b/src/alloy/backend/ivm/ivm_function.cc index 335dc7c87..701cbac1c 100644 --- a/src/alloy/backend/ivm/ivm_function.cc +++ b/src/alloy/backend/ivm/ivm_function.cc @@ -33,6 +33,7 @@ IVMFunction::~IVMFunction() { void IVMFunction::Setup(TranslationContext& ctx) { register_count_ = ctx.register_count; + stack_size_ = ctx.stack_size; intcode_count_ = ctx.intcode_count; intcodes_ = (IntCode*)ctx.intcode_arena->CloneContents(); source_map_count_ = ctx.source_map_count; @@ -108,11 +109,13 @@ int IVMFunction::CallImpl(ThreadState* thread_state) { // Setup register file on stack. auto stack = (IVMStack*)thread_state->backend_data(); auto register_file = (Register*)stack->Alloc(register_count_); + auto local_stack = (uint8_t*)alloca(stack_size_); Memory* memory = thread_state->memory(); IntCodeState ics; ics.rf = register_file; + ics.locals = local_stack; ics.context = (uint8_t*)thread_state->raw_context(); ics.membase = memory->membase(); ics.did_carry = 0; diff --git a/src/alloy/backend/ivm/ivm_function.h b/src/alloy/backend/ivm/ivm_function.h index c7da76f89..7ee24cddf 100644 --- a/src/alloy/backend/ivm/ivm_function.h +++ b/src/alloy/backend/ivm/ivm_function.h @@ -38,9 +38,10 @@ private: void OnBreakpointHit(runtime::ThreadState* thread_state, IntCode* i); private: - size_t register_count_; - size_t intcode_count_; - IntCode* intcodes_; + size_t register_count_; + size_t stack_size_; + size_t intcode_count_; + IntCode* intcodes_; size_t source_map_count_; SourceMapEntry* source_map_; }; diff --git a/src/alloy/backend/ivm/ivm_intcode.cc b/src/alloy/backend/ivm/ivm_intcode.cc index be1c9c206..f1460e2c9 100644 --- a/src/alloy/backend/ivm/ivm_intcode.cc +++ b/src/alloy/backend/ivm/ivm_intcode.cc @@ -1342,6 +1342,88 @@ int Translate_LOAD_CLOCK(TranslationContext& ctx, Instr* i) { return DispatchToC(ctx, i, IntCode_LOAD_CLOCK); } +uint32_t IntCode_LOAD_LOCAL_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = *((int8_t*)(ics.locals + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_LOCAL_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = *((int16_t*)(ics.locals + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_LOCAL_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = *((int32_t*)(ics.locals + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_LOCAL_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = *((int64_t*)(ics.locals + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_LOCAL_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = *((float*)(ics.locals + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_LOCAL_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = *((double*)(ics.locals + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_LOCAL_V128(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].v128 = *((vec128_t*)(ics.locals + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +int Translate_LOAD_LOCAL(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_LOAD_LOCAL_I8, + IntCode_LOAD_LOCAL_I16, + IntCode_LOAD_LOCAL_I32, + IntCode_LOAD_LOCAL_I64, + IntCode_LOAD_LOCAL_F32, + IntCode_LOAD_LOCAL_F64, + IntCode_LOAD_LOCAL_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_STORE_LOCAL_I8(IntCodeState& ics, const IntCode* i) { + *((int8_t*)(ics.locals + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_STORE_LOCAL_I16(IntCodeState& ics, const IntCode* i) { + *((int16_t*)(ics.locals + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_STORE_LOCAL_I32(IntCodeState& ics, const IntCode* i) { + *((int32_t*)(ics.locals + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_STORE_LOCAL_I64(IntCodeState& ics, const IntCode* i) { + *((int64_t*)(ics.locals + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_STORE_LOCAL_F32(IntCodeState& ics, const IntCode* i) { + *((float*)(ics.locals + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_STORE_LOCAL_F64(IntCodeState& ics, const IntCode* i) { + *((double*)(ics.locals + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_STORE_LOCAL_V128(IntCodeState& ics, const IntCode* i) { + *((vec128_t*)(ics.locals + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].v128; + return IA_NEXT; +} +int Translate_STORE_LOCAL(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_STORE_LOCAL_I8, + IntCode_STORE_LOCAL_I16, + IntCode_STORE_LOCAL_I32, + IntCode_STORE_LOCAL_I64, + IntCode_STORE_LOCAL_F32, + IntCode_STORE_LOCAL_F64, + IntCode_STORE_LOCAL_V128, + }; + return DispatchToC(ctx, i, fns[i->src2.value->type]); +} + uint32_t IntCode_LOAD_CONTEXT_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = *((int8_t*)(ics.context + ics.rf[i->src1_reg].u64)); DPRINT("%d (%X) = ctx i8 +%d\n", ics.rf[i->dest_reg].i8, ics.rf[i->dest_reg].u8, ics.rf[i->src1_reg].u64); @@ -4039,6 +4121,9 @@ static const TranslateFn dispatch_table[] = { Translate_LOAD_CLOCK, + Translate_LOAD_LOCAL, + Translate_STORE_LOCAL, + Translate_LOAD_CONTEXT, Translate_STORE_CONTEXT, diff --git a/src/alloy/backend/ivm/ivm_intcode.h b/src/alloy/backend/ivm/ivm_intcode.h index d5ba5cfec..dcb59c106 100644 --- a/src/alloy/backend/ivm/ivm_intcode.h +++ b/src/alloy/backend/ivm/ivm_intcode.h @@ -41,6 +41,7 @@ typedef union { typedef struct { Register* rf; + uint8_t* locals; uint8_t* context; uint8_t* membase; int8_t did_carry; @@ -103,6 +104,7 @@ typedef struct { Arena* source_map_arena; Arena* scratch_arena; LabelRef* label_ref_head; + size_t stack_size; } TranslationContext; diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index c6f0c305f..d779d731c 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.cc @@ -815,6 +815,117 @@ table->AddSequence(OPCODE_LOAD_CLOCK, [](X64Emitter& e, Instr*& i) { return true; }); +// -------------------------------------------------------------------------- +// Stack Locals +// -------------------------------------------------------------------------- + +table->AddSequence(OPCODE_LOAD_LOCAL, [](X64Emitter& e, Instr*& i) { + auto addr = e.rsp + i->src1.value->AsUint32(); + if (i->Match(SIG_TYPE_I8, SIG_TYPE_IGNORE)) { + Reg8 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.byte[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_IGNORE)) { + Reg16 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.word[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_IGNORE)) { + Reg32 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.dword[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_IGNORE)) { + Reg64 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.qword[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_F32, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.movss(dest, e.dword[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_F64, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.movsd(dest, e.qword[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_V128, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + // NOTE: we always know we are aligned. + e.movaps(dest, e.ptr[addr]); + e.EndOp(dest); + } else { + ASSERT_INVALID_TYPE(); + } + i = e.Advance(i); + return true; +}); + +table->AddSequence(OPCODE_STORE_LOCAL, [](X64Emitter& e, Instr*& i) { + auto addr = e.rsp + i->src1.value->AsUint32(); + if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I8)) { + Reg8 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.byte[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I8C)) { + e.mov(e.byte[addr], i->src2.value->constant.i8); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I16)) { + Reg16 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.word[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I16C)) { + e.mov(e.word[addr], i->src2.value->constant.i16); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I32)) { + Reg32 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.dword[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I32C)) { + e.mov(e.dword[addr], i->src2.value->constant.i32); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I64)) { + Reg64 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.qword[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I64C)) { + MovMem64(e, addr, i->src2.value->constant.i64); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F32)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + e.movss(e.dword[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F32C)) { + e.mov(e.dword[addr], i->src2.value->constant.i32); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F64)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + e.movsd(e.qword[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F64C)) { + MovMem64(e, addr, i->src2.value->constant.i64); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_V128)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + // NOTE: we always know we are aligned. + e.movaps(e.ptr[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_V128C)) { + // TODO(benvanik): check zero + // TODO(benvanik): correct order? + MovMem64(e, addr, i->src2.value->constant.v128.low); + MovMem64(e, addr + 8, i->src2.value->constant.v128.high); + } else { + ASSERT_INVALID_TYPE(); + } + i = e.Advance(i); + return true; +}); + // -------------------------------------------------------------------------- // Context // -------------------------------------------------------------------------- @@ -2892,6 +3003,7 @@ table->AddSequence(OPCODE_ATOMIC_EXCHANGE, [](X64Emitter& e, Instr*& i) { i->src1.value, src1, 0, i->src2.value, src2, 0); e.mov(dest, src2); + e.lock(); e.xchg(e.dword[src1], dest); e.EndOp(dest, src1, src2); } else { diff --git a/src/alloy/backend/x64/x64_emitter.cc b/src/alloy/backend/x64/x64_emitter.cc index 1e938b084..4d441673f 100644 --- a/src/alloy/backend/x64/x64_emitter.cc +++ b/src/alloy/backend/x64/x64_emitter.cc @@ -97,6 +97,8 @@ void* X64Emitter::Emplace(size_t stack_size) { return new_address; } +#define XEALIGN(value, align) ((value + align - 1) & ~(align - 1)) + int X64Emitter::Emit(HIRBuilder* builder) { // These are the registers we will not be using. All others are fare game. const uint32_t reserved_regs = @@ -120,6 +122,19 @@ int X64Emitter::Emit(HIRBuilder* builder) { GetRegBit(xmm4) | GetRegBit(xmm5); + // Calculate stack size. We need to align things to their natural sizes. + // This could be much better (sort by type/etc). + auto locals = builder->locals(); + size_t stack_offset = 0; + for (auto it = locals.begin(); it != locals.end(); ++it) { + auto slot = *it; + size_t type_size = GetTypeSize(slot->type); + // Align to natural size. + stack_offset = XEALIGN(stack_offset, type_size); + slot->set_constant(stack_offset); + stack_offset += type_size; + } + // Function prolog. // Must be 16b aligned. // Windows is very strict about the form of this and the epilog: diff --git a/src/alloy/compiler/compiler_passes.h b/src/alloy/compiler/compiler_passes.h index 200159ac2..ca074e221 100644 --- a/src/alloy/compiler/compiler_passes.h +++ b/src/alloy/compiler/compiler_passes.h @@ -11,11 +11,14 @@ #define ALLOY_COMPILER_COMPILER_PASSES_H_ #include +#include #include +#include #include #include //#include #include +#include #include // TODO: diff --git a/src/alloy/compiler/passes/control_flow_analysis_pass.cc b/src/alloy/compiler/passes/control_flow_analysis_pass.cc new file mode 100644 index 000000000..5e73bd502 --- /dev/null +++ b/src/alloy/compiler/passes/control_flow_analysis_pass.cc @@ -0,0 +1,72 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable : 4244) +#pragma warning(disable : 4267) +#include +#pragma warning(pop) + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::compiler; +using namespace alloy::compiler::passes; +using namespace alloy::frontend; +using namespace alloy::hir; +using namespace alloy::runtime; + + +ControlFlowAnalysisPass::ControlFlowAnalysisPass() : + CompilerPass() { +} + +ControlFlowAnalysisPass::~ControlFlowAnalysisPass() { +} + +int ControlFlowAnalysisPass::Run(HIRBuilder* builder) { + // TODO(benvanik): reset edges for all blocks? Needed to be re-runnable. + + // Add edges. + auto block = builder->first_block(); + while (block) { + auto instr = block->instr_head; + while (instr) { + if (instr->opcode->flags & OPCODE_FLAG_BRANCH) { + if (instr->opcode == &OPCODE_BRANCH_info) { + auto label = instr->src1.label; + builder->AddEdge(block, label->block, Edge::UNCONDITIONAL); + } else if (instr->opcode == &OPCODE_BRANCH_TRUE_info || + instr->opcode == &OPCODE_BRANCH_FALSE_info) { + auto label = instr->src2.label; + builder->AddEdge(block, label->block, 0); + } + } + instr = instr->next; + } + block = block->next; + } + + // Mark dominators. + block = builder->first_block(); + while (block) { + if (block->incoming_edge_head && + !block->incoming_edge_head->incoming_next) { + block->incoming_edge_head->flags |= Edge::DOMINATES; + } + block = block->next; + } + + return 0; +} diff --git a/src/alloy/compiler/passes/control_flow_analysis_pass.h b/src/alloy/compiler/passes/control_flow_analysis_pass.h new file mode 100644 index 000000000..c639db5cb --- /dev/null +++ b/src/alloy/compiler/passes/control_flow_analysis_pass.h @@ -0,0 +1,37 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_COMPILER_PASSES_CONTROL_FLOW_ANALYSIS_PASS_H_ +#define ALLOY_COMPILER_PASSES_CONTROL_FLOW_ANALYSIS_PASS_H_ + +#include + + +namespace alloy { +namespace compiler { +namespace passes { + + +class ControlFlowAnalysisPass : public CompilerPass { +public: + ControlFlowAnalysisPass(); + virtual ~ControlFlowAnalysisPass(); + + virtual int Run(hir::HIRBuilder* builder); + +private: +}; + + +} // namespace passes +} // namespace compiler +} // namespace alloy + + +#endif // ALLOY_COMPILER_PASSES_CONTROL_FLOW_ANALYSIS_PASS_H_ diff --git a/src/alloy/compiler/passes/data_flow_analysis_pass.cc b/src/alloy/compiler/passes/data_flow_analysis_pass.cc new file mode 100644 index 000000000..8501d1675 --- /dev/null +++ b/src/alloy/compiler/passes/data_flow_analysis_pass.cc @@ -0,0 +1,203 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable : 4244) +#pragma warning(disable : 4267) +#include +#pragma warning(pop) + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::compiler; +using namespace alloy::compiler::passes; +using namespace alloy::frontend; +using namespace alloy::hir; +using namespace alloy::runtime; + + +DataFlowAnalysisPass::DataFlowAnalysisPass() : + CompilerPass() { +} + +DataFlowAnalysisPass::~DataFlowAnalysisPass() { +} + +int DataFlowAnalysisPass::Run(HIRBuilder* builder) { + auto arena = builder->arena(); + + // Linearize blocks so that we can detect cycles and propagate dependencies. + uint32_t block_count = LinearizeBlocks(builder); + + // Analyze value flow and add locals as needed. + AnalyzeFlow(builder, block_count); + + return 0; +} + +uint32_t DataFlowAnalysisPass::LinearizeBlocks(HIRBuilder* builder) { + // TODO(benvanik): actually do this - we cheat now knowing that they are in + // sequential order. + uint32_t block_ordinal = 0; + auto block = builder->first_block(); + while (block) { + block->ordinal = block_ordinal++; + block = block->next; + } + return block_ordinal; +} + +void DataFlowAnalysisPass::AnalyzeFlow(HIRBuilder* builder, + uint32_t block_count) { + uint32_t max_value_estimate = + builder->max_value_ordinal() + 1 + block_count * 4; + + // Stash for value map. We may want to maintain this during building. + auto arena = builder->arena(); + Value** value_map = (Value**)arena->Alloc( + sizeof(Value*) * max_value_estimate); + + // Allocate incoming bitvectors for use by blocks. We don't need outgoing + // because they are only used during the block iteration. + // Mapped by block ordinal. + // TODO(benvanik): cache this list, grow as needed, etc. + auto incoming_bitvectors = (llvm::BitVector**)arena->Alloc( + sizeof(llvm::BitVector*) * block_count); + for (auto n = 0u; n < block_count; n++) { + incoming_bitvectors[n] = new llvm::BitVector(max_value_estimate); + } + + // Walk blocks in reverse and calculate incoming/outgoing values. + auto block = builder->last_block(); + while (block) { + // allocate bitsets based on max value number + block->incoming_values = incoming_bitvectors[block->ordinal]; + auto& incoming_values = *block->incoming_values; + + // Walk instructions and gather up incoming values. + auto instr = block->instr_head; + while (instr) { + uint32_t signature = instr->opcode->signature; +#define SET_INCOMING_VALUE(v) \ + if (v->def && v->def->block != block) { \ + incoming_values.set(v->ordinal); \ + } \ + XEASSERT(v->ordinal < max_value_estimate); \ + value_map[v->ordinal] = v; + if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) { + SET_INCOMING_VALUE(instr->src1.value); + } + if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) { + SET_INCOMING_VALUE(instr->src2.value); + } + if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) { + SET_INCOMING_VALUE(instr->src3.value); + } +#undef SET_INCOMING_VALUE + instr = instr->next; + } + + // Add all successor incoming values to our outgoing, as we need to + // pass them through. + llvm::BitVector outgoing_values(max_value_estimate); + auto outgoing_edge = block->outgoing_edge_head; + while (outgoing_edge) { + if (outgoing_edge->dest->ordinal > block->ordinal) { + outgoing_values |= *outgoing_edge->dest->incoming_values; + } + outgoing_edge = outgoing_edge->outgoing_next; + } + incoming_values |= outgoing_values; + + // Add stores for all outgoing values. + auto outgoing_ordinal = outgoing_values.find_first(); + while (outgoing_ordinal != -1) { + Value* src_value = value_map[outgoing_ordinal]; + XEASSERTNOTNULL(src_value); + if (!src_value->local_slot) { + src_value->local_slot = builder->AllocLocal(src_value->type); + } + builder->StoreLocal(src_value->local_slot, src_value); + + // If we are in the block the value was defined in: + if (src_value->def->block == block) { + // Move the store to right after the def, or as soon after + // as we can (respecting PAIRED flags). + auto def_next = src_value->def->next; + while (def_next && def_next->opcode->flags & OPCODE_FLAG_PAIRED_PREV) { + def_next = def_next->next; + } + XEASSERTNOTNULL(def_next); + builder->last_instr()->MoveBefore(def_next); + + // We don't need it in the incoming list. + incoming_values.reset(outgoing_ordinal); + } else { + // Eh, just throw at the end, before the first branch. + auto tail = block->instr_tail; + while (tail && tail->opcode->flags & OPCODE_FLAG_BRANCH) { + tail = tail->prev; + } + XEASSERTNOTZERO(tail); + builder->last_instr()->MoveBefore(tail->next); + } + + outgoing_ordinal = outgoing_values.find_next(outgoing_ordinal); + } + + // Add loads for all incoming values and rename them in the block. + auto incoming_ordinal = incoming_values.find_first(); + while (incoming_ordinal != -1) { + Value* src_value = value_map[incoming_ordinal]; + XEASSERTNOTNULL(src_value); + if (!src_value->local_slot) { + src_value->local_slot = builder->AllocLocal(src_value->type); + } + Value* local_value = builder->LoadLocal(src_value->local_slot); + builder->last_instr()->MoveBefore(block->instr_head); + + // Swap uses of original value with the local value. + auto instr = block->instr_head; + while (instr) { + uint32_t signature = instr->opcode->signature; + if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) { + if (instr->src1.value == src_value) { + instr->set_src1(local_value); + } + } + if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) { + if (instr->src2.value == src_value) { + instr->set_src2(local_value); + } + } + if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) { + if (instr->src3.value == src_value) { + instr->set_src3(local_value); + } + } + instr = instr->next; + } + + incoming_ordinal = incoming_values.find_next(incoming_ordinal); + } + + block = block->prev; + } + + // Cleanup bitvectors. + for (auto n = 0u; n < block_count; n++) { + delete incoming_bitvectors[n]; + } +} diff --git a/src/alloy/compiler/passes/data_flow_analysis_pass.h b/src/alloy/compiler/passes/data_flow_analysis_pass.h new file mode 100644 index 000000000..d19dc6e1c --- /dev/null +++ b/src/alloy/compiler/passes/data_flow_analysis_pass.h @@ -0,0 +1,39 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_COMPILER_PASSES_DATA_FLOW_ANALYSIS_PASS_H_ +#define ALLOY_COMPILER_PASSES_DATA_FLOW_ANALYSIS_PASS_H_ + +#include + + +namespace alloy { +namespace compiler { +namespace passes { + + +class DataFlowAnalysisPass : public CompilerPass { +public: + DataFlowAnalysisPass(); + virtual ~DataFlowAnalysisPass(); + + virtual int Run(hir::HIRBuilder* builder); + +private: + uint32_t LinearizeBlocks(hir::HIRBuilder* builder); + void AnalyzeFlow(hir::HIRBuilder* builder, uint32_t block_count); +}; + + +} // namespace passes +} // namespace compiler +} // namespace alloy + + +#endif // ALLOY_COMPILER_PASSES_DATA_FLOW_ANALYSIS_PASS_H_ diff --git a/src/alloy/compiler/passes/dead_code_elimination_pass.cc b/src/alloy/compiler/passes/dead_code_elimination_pass.cc index a9b7c7bdb..d295cebec 100644 --- a/src/alloy/compiler/passes/dead_code_elimination_pass.cc +++ b/src/alloy/compiler/passes/dead_code_elimination_pass.cc @@ -59,20 +59,21 @@ int DeadCodeEliminationPass::Run(HIRBuilder* builder) { // all removed ops with NOP and then do a single pass that removes them // all. - bool any_removed = false; + bool any_instr_removed = false; + bool any_locals_removed = false; Block* block = builder->first_block(); while (block) { + // Walk instructions in reverse. Instr* i = block->instr_tail; while (i) { - Instr* prev = i->prev; + auto prev = i->prev; - const OpcodeInfo* opcode = i->opcode; - uint32_t signature = opcode->signature; + auto opcode = i->opcode; if (!(opcode->flags & OPCODE_FLAG_VOLATILE) && i->dest && !i->dest->use_head) { // Has no uses and is not volatile. This instruction can die! MakeNopRecursive(i); - any_removed = true; + any_instr_removed = true; } else if (opcode == &OPCODE_ASSIGN_info) { // Assignment. These are useless, so just try to remove by completely // replacing the value. @@ -82,11 +83,31 @@ int DeadCodeEliminationPass::Run(HIRBuilder* builder) { i = prev; } + // Walk instructions forward. + i = block->instr_head; + while (i) { + auto next = i->next; + + auto opcode = i->opcode; + if (opcode == &OPCODE_STORE_LOCAL_info) { + // Check to see if the store has any interceeding uses after the load. + // If not, it can be removed (as the local is just passing through the + // function). + // We do this after the previous pass so that removed code doesn't keep + // the local alive. + if (!CheckLocalUse(i)) { + any_locals_removed = true; + } + } + + i = next; + } + block = block->next; } // Remove all nops. - if (any_removed) { + if (any_instr_removed) { Block* block = builder->first_block(); while (block) { Instr* i = block->instr_head; @@ -102,6 +123,21 @@ int DeadCodeEliminationPass::Run(HIRBuilder* builder) { } } + // Remove any locals that no longer have uses. + if (any_locals_removed) { + // TODO(benvanik): local removal/dealloc. + auto locals = builder->locals(); + for (auto it = locals.begin(); it != locals.end();) { + auto next = ++it; + auto value = *it; + if (!value->use_head) { + // Unused, can be removed. + locals.erase(it); + } + it = next; + } + } + return 0; } @@ -150,3 +186,24 @@ void DeadCodeEliminationPass::ReplaceAssignment(Instr* i) { i->Remove(); } + +bool DeadCodeEliminationPass::CheckLocalUse(Instr* i) { + auto slot = i->src1.value; + auto src = i->src2.value; + + auto use = src->use_head; + if (use) { + auto use_instr = use->instr; + if (use_instr->opcode != &OPCODE_LOAD_LOCAL_info) { + // A valid use (probably). Keep it. + return true; + } + + // Load/store are paired. They can both be removed. + use_instr->Remove(); + } + + i->Remove(); + + return false; +} diff --git a/src/alloy/compiler/passes/dead_code_elimination_pass.h b/src/alloy/compiler/passes/dead_code_elimination_pass.h index 9a8cfc43a..9c3100f8c 100644 --- a/src/alloy/compiler/passes/dead_code_elimination_pass.h +++ b/src/alloy/compiler/passes/dead_code_elimination_pass.h @@ -28,6 +28,7 @@ public: private: void MakeNopRecursive(hir::Instr* i); void ReplaceAssignment(hir::Instr* i); + bool CheckLocalUse(hir::Instr* i); }; diff --git a/src/alloy/compiler/passes/sources.gypi b/src/alloy/compiler/passes/sources.gypi index 251e6350a..bd5559319 100644 --- a/src/alloy/compiler/passes/sources.gypi +++ b/src/alloy/compiler/passes/sources.gypi @@ -5,6 +5,10 @@ 'constant_propagation_pass.h', 'context_promotion_pass.cc', 'context_promotion_pass.h', + 'control_flow_analysis_pass.cc', + 'control_flow_analysis_pass.h', + 'data_flow_analysis_pass.cc', + 'data_flow_analysis_pass.h', 'dead_code_elimination_pass.cc', 'dead_code_elimination_pass.h', 'finalization_pass.cc', @@ -13,6 +17,8 @@ #'dead_store_elimination_pass.h', 'simplification_pass.cc', 'simplification_pass.h', + 'validation_pass.cc', + 'validation_pass.h', 'value_reduction_pass.cc', 'value_reduction_pass.h', ], diff --git a/src/alloy/compiler/passes/validation_pass.cc b/src/alloy/compiler/passes/validation_pass.cc new file mode 100644 index 000000000..15e89bd67 --- /dev/null +++ b/src/alloy/compiler/passes/validation_pass.cc @@ -0,0 +1,99 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::compiler; +using namespace alloy::compiler::passes; +using namespace alloy::frontend; +using namespace alloy::hir; +using namespace alloy::runtime; + + +ValidationPass::ValidationPass() : + CompilerPass() { +} + +ValidationPass::~ValidationPass() { +} + +int ValidationPass::Run(HIRBuilder* builder) { + StringBuffer str; + builder->Dump(&str); + printf(str.GetString()); + fflush(stdout); + str.Reset(); + + auto block = builder->first_block(); + while (block) { + auto label = block->label_head; + while (label) { + XEASSERT(label->block == block); + if (label->block != block) { + return 1; + } + label = label->next; + } + + auto instr = block->instr_head; + while (instr) { + if (ValidateInstruction(block, instr)) { + return 1; + } + instr = instr->next; + } + + block = block->next; + } + + return 0; +} + +int ValidationPass::ValidateInstruction(Block* block, Instr* instr) { + XEASSERT(instr->block == block); + if (instr->block != block) { + return 1; + } + + uint32_t signature = instr->opcode->signature; + if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) { + if (ValidateValue(block, instr, instr->src1.value)) { + return 1; + } + } + if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) { + if (ValidateValue(block, instr, instr->src2.value)) { + return 1; + } + } + if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) { + if (ValidateValue(block, instr, instr->src3.value)) { + return 1; + } + } + + return 0; +} + +int ValidationPass::ValidateValue(Block* block, Instr* instr, Value* value) { + if (value->def) { + /*auto def = value->def; + XEASSERT(def->block == block); + if (def->block != block) { + return 1; + }*/ + } + return 0; +} diff --git a/src/alloy/compiler/passes/validation_pass.h b/src/alloy/compiler/passes/validation_pass.h new file mode 100644 index 000000000..a9f0c8f9a --- /dev/null +++ b/src/alloy/compiler/passes/validation_pass.h @@ -0,0 +1,39 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_COMPILER_PASSES_VALIDATION_PASS_H_ +#define ALLOY_COMPILER_PASSES_VALIDATION_PASS_H_ + +#include + + +namespace alloy { +namespace compiler { +namespace passes { + + +class ValidationPass : public CompilerPass { +public: + ValidationPass(); + virtual ~ValidationPass(); + + virtual int Run(hir::HIRBuilder* builder); + +private: + int ValidateInstruction(hir::Block* block, hir::Instr* instr); + int ValidateValue(hir::Block* block, hir::Instr* instr, hir::Value* value); +}; + + +} // namespace passes +} // namespace compiler +} // namespace alloy + + +#endif // ALLOY_COMPILER_PASSES_VALIDATION_PASS_H_ diff --git a/src/alloy/compiler/passes/value_reduction_pass.cc b/src/alloy/compiler/passes/value_reduction_pass.cc index 42984e891..4eb61a38b 100644 --- a/src/alloy/compiler/passes/value_reduction_pass.cc +++ b/src/alloy/compiler/passes/value_reduction_pass.cc @@ -13,7 +13,11 @@ #include #include -#include +#pragma warning(push) +#pragma warning(disable : 4244) +#pragma warning(disable : 4267) +#include +#pragma warning(pop) using namespace alloy; using namespace alloy::backend; @@ -51,8 +55,7 @@ void ValueReductionPass::ComputeLastUse(Value* value) { int ValueReductionPass::Run(HIRBuilder* builder) { // Walk each block and reuse variable ordinals as much as possible. - // Let's hope this is enough. - std::bitset<1024> ordinals; + llvm::BitVector ordinals(builder->max_value_ordinal()); auto block = builder->first_block(); while (block) { @@ -82,7 +85,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) { if (v->last_use == instr) { // Available. if (!instr->src1.value->IsConstant()) { - ordinals.set(v->ordinal, false); + ordinals.reset(v->ordinal); } } } @@ -94,7 +97,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) { if (v->last_use == instr) { // Available. if (!instr->src2.value->IsConstant()) { - ordinals.set(v->ordinal, false); + ordinals.reset(v->ordinal); } } } @@ -106,7 +109,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) { if (v->last_use == instr) { // Available. if (!instr->src3.value->IsConstant()) { - ordinals.set(v->ordinal, false); + ordinals.reset(v->ordinal); } } } @@ -115,7 +118,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) { // source value ordinal. auto v = instr->dest; // Find a lower ordinal. - for (auto n = 0; n < ordinals.size(); n++) { + for (auto n = 0u; n < ordinals.size(); n++) { if (!ordinals.test(n)) { ordinals.set(n); v->ordinal = n; diff --git a/src/alloy/frontend/ppc/ppc_translator.cc b/src/alloy/frontend/ppc/ppc_translator.cc index 0cc601889..2431f1761 100644 --- a/src/alloy/frontend/ppc/ppc_translator.cc +++ b/src/alloy/frontend/ppc/ppc_translator.cc @@ -38,20 +38,40 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : assembler_ = backend->CreateAssembler(); assembler_->Initialize(); + bool validate = FLAGS_validate_hir; + + // Build the CFG first. + compiler_->AddPass(new passes::ControlFlowAnalysisPass()); + // Passes are executed in the order they are added. Multiple of the same // pass type may be used. + if (validate) compiler_->AddPass(new passes::ValidationPass()); //compiler_->AddPass(new passes::ContextPromotionPass()); + if (validate) compiler_->AddPass(new passes::ValidationPass()); compiler_->AddPass(new passes::SimplificationPass()); - // TODO(benvanik): run repeatedly? + if (validate) compiler_->AddPass(new passes::ValidationPass()); compiler_->AddPass(new passes::ConstantPropagationPass()); - //compiler_->AddPass(new passes::TypePropagationPass()); - //compiler_->AddPass(new passes::ByteSwapEliminationPass()); + if (validate) compiler_->AddPass(new passes::ValidationPass()); compiler_->AddPass(new passes::SimplificationPass()); + if (validate) compiler_->AddPass(new passes::ValidationPass()); //compiler_->AddPass(new passes::DeadStoreEliminationPass()); + //if (validate) compiler_->AddPass(new passes::ValidationPass()); compiler_->AddPass(new passes::DeadCodeEliminationPass()); + if (validate) compiler_->AddPass(new passes::ValidationPass()); + + // Adds local load/stores. + compiler_->AddPass(new passes::DataFlowAnalysisPass()); + if (validate) compiler_->AddPass(new passes::ValidationPass()); + compiler_->AddPass(new passes::SimplificationPass()); + if (validate) compiler_->AddPass(new passes::ValidationPass()); + + // Run DCE one more time to cleanup any local manipulation. + compiler_->AddPass(new passes::DeadCodeEliminationPass()); + if (validate) compiler_->AddPass(new passes::ValidationPass()); // Removes all unneeded variables. Try not to add new ones after this. compiler_->AddPass(new passes::ValueReductionPass()); + if (validate) compiler_->AddPass(new passes::ValidationPass()); // Must come last. The HIR is not really HIR after this. compiler_->AddPass(new passes::FinalizationPass()); diff --git a/src/alloy/hir/block.h b/src/alloy/hir/block.h index 1cb6d6414..1683b333c 100644 --- a/src/alloy/hir/block.h +++ b/src/alloy/hir/block.h @@ -12,15 +12,37 @@ #include +XEDECLARECLASS1(llvm, BitVector); + namespace alloy { namespace hir { +class Block; class HIRBuilder; class Instr; class Label; +class Edge { +public: + enum EdgeFlags { + UNCONDITIONAL = (1 << 0), + DOMINATES = (1 << 1), + }; +public: + Edge* outgoing_next; + Edge* outgoing_prev; + Edge* incoming_next; + Edge* incoming_prev; + + Block* src; + Block* dest; + + uint32_t flags; +}; + + class Block { public: Arena* arena; @@ -28,6 +50,10 @@ public: Block* next; Block* prev; + Edge* incoming_edge_head; + Edge* outgoing_edge_head; + llvm::BitVector* incoming_values; + Label* label_head; Label* label_tail; diff --git a/src/alloy/hir/hir_builder.cc b/src/alloy/hir/hir_builder.cc index efc12e723..44f1b758c 100644 --- a/src/alloy/hir/hir_builder.cc +++ b/src/alloy/hir/hir_builder.cc @@ -41,6 +41,7 @@ void HIRBuilder::Reset() { attributes_ = 0; next_label_id_ = 0; next_value_ordinal_ = 0; + locals_.clear(); block_head_ = block_tail_ = NULL; current_block_ = NULL; #if XE_DEBUG @@ -141,6 +142,13 @@ void HIRBuilder::Dump(StringBuffer* str) { str->Append("; attributes = %.8X\n", attributes_); } + for (auto it = locals_.begin(); it != locals_.end(); ++it) { + auto local = *it; + str->Append(" ; local "); + DumpValue(str, local); + str->Append("\n"); + } + uint32_t block_ordinal = 0; Block* block = block_head_; while (block) { @@ -161,6 +169,39 @@ void HIRBuilder::Dump(StringBuffer* str) { label = label->next; } + Edge* incoming_edge = block->incoming_edge_head; + while (incoming_edge) { + auto src_label = incoming_edge->src->label_head; + if (src_label && src_label->name) { + str->Append(" ; in: %s", src_label->name); + } else if (src_label) { + str->Append(" ; in: label%d", src_label->id); + } else { + str->Append(" ; in: ", + incoming_edge->src->ordinal); + } + str->Append(", dom:%d, uncond:%d\n", + (incoming_edge->flags & Edge::DOMINATES) ? 1 : 0, + (incoming_edge->flags & Edge::UNCONDITIONAL) ? 1 : 0); + incoming_edge = incoming_edge->incoming_next; + } + Edge* outgoing_edge = block->outgoing_edge_head; + while (outgoing_edge) { + auto dest_label = outgoing_edge->dest->label_head; + if (dest_label && dest_label->name) { + str->Append(" ; out: %s", dest_label->name); + } else if (dest_label) { + str->Append(" ; out: label%d", dest_label->id); + } else { + str->Append(" ; out: ", + outgoing_edge->dest->ordinal); + } + str->Append(", dom:%d, uncond:%d\n", + (outgoing_edge->flags & Edge::DOMINATES) ? 1 : 0, + (outgoing_edge->flags & Edge::UNCONDITIONAL) ? 1 : 0); + outgoing_edge = outgoing_edge->outgoing_next; + } + Instr* i = block->instr_head; while (i) { if (i->opcode->flags & OPCODE_FLAG_HIDE) { @@ -303,6 +344,7 @@ void HIRBuilder::InsertLabel(Label* label, Instr* prev_instr) { block_tail_ = new_block; } new_block->label_head = new_block->label_tail = label; + new_block->incoming_edge_head = new_block->outgoing_edge_head = NULL; label->block = new_block; label->prev = label->next = NULL; @@ -319,8 +361,7 @@ void HIRBuilder::InsertLabel(Label* label, Instr* prev_instr) { new_block->instr_tail = old_prev_tail; } - for (auto instr = new_block->instr_head; instr != new_block->instr_tail; - instr = instr->next) { + for (auto instr = new_block->instr_head; instr; instr = instr->next) { instr->block = new_block; } @@ -342,6 +383,19 @@ void HIRBuilder::ResetLabelTags() { } } +void HIRBuilder::AddEdge(Block* src, Block* dest, uint32_t flags) { + Edge* edge = arena_->Alloc(); + edge->src = src; + edge->dest = dest; + edge->flags = flags; + edge->outgoing_prev = NULL; + edge->outgoing_next = src->outgoing_edge_head; + src->outgoing_edge_head = edge; + edge->incoming_prev = NULL; + edge->incoming_next = dest->incoming_edge_head; + dest->incoming_edge_head = edge; +} + Block* HIRBuilder::AppendBlock() { Block* block = arena_->Alloc(); block->arena = arena_; @@ -356,6 +410,7 @@ Block* HIRBuilder::AppendBlock() { } current_block_ = block; block->label_head = block->label_tail = NULL; + block->incoming_edge_head = block->outgoing_edge_head = NULL; block->instr_head = block->instr_tail = NULL; return block; } @@ -420,6 +475,7 @@ Value* HIRBuilder::AllocValue(TypeName type) { value->def = NULL; value->use_head = NULL; value->last_use = NULL; + value->local_slot = NULL; value->tag = NULL; value->reg = -1; return value; @@ -434,6 +490,7 @@ Value* HIRBuilder::CloneValue(Value* source) { value->def = NULL; value->use_head = NULL; value->last_use = NULL; + value->local_slot = NULL; value->tag = NULL; value->reg = -1; return value; @@ -877,6 +934,28 @@ Value* HIRBuilder::LoadClock() { return i->dest; } +Value* HIRBuilder::AllocLocal(TypeName type) { + Value* slot = AllocValue(type); + locals_.push_back(slot); + return slot; +} + +Value* HIRBuilder::LoadLocal(Value* slot) { + Instr* i = AppendInstr( + OPCODE_LOAD_LOCAL_info, 0, + AllocValue(slot->type)); + i->set_src1(slot); + i->src2.value = i->src3.value = NULL; + return i->dest; +} + +void HIRBuilder::StoreLocal(Value* slot, Value* value) { + Instr* i = AppendInstr(OPCODE_STORE_LOCAL_info, 0); + i->set_src1(slot); + i->set_src2(value); + i->src3.value = NULL; +} + Value* HIRBuilder::LoadContext(size_t offset, TypeName type) { Instr* i = AppendInstr( OPCODE_LOAD_CONTEXT_info, 0, diff --git a/src/alloy/hir/hir_builder.h b/src/alloy/hir/hir_builder.h index e5a0aef07..542b1e7ae 100644 --- a/src/alloy/hir/hir_builder.h +++ b/src/alloy/hir/hir_builder.h @@ -41,7 +41,12 @@ public: uint32_t attributes() const { return attributes_; } void set_attributes(uint32_t value) { attributes_ = value; } + std::vector& locals() { return locals_; } + + uint32_t max_value_ordinal() const { return next_value_ordinal_; } + Block* first_block() const { return block_head_; } + Block* last_block() const { return block_tail_; } Block* current_block() const; Instr* last_instr() const; @@ -50,12 +55,11 @@ public: void InsertLabel(Label* label, Instr* prev_instr); void ResetLabelTags(); + void AddEdge(Block* src, Block* dest, uint32_t flags); + // static allocations: // Value* AllocStatic(size_t length); - // stack allocations: - // Value* AllocLocal(TypeName type); - void Comment(const char* format, ...); void Nop(); @@ -116,6 +120,10 @@ public: Value* LoadClock(); + Value* AllocLocal(TypeName type); + Value* LoadLocal(Value* slot); + void StoreLocal(Value* slot, Value* value); + Value* LoadContext(size_t offset, TypeName type); void StoreContext(size_t offset, Value* value); @@ -230,6 +238,8 @@ protected: uint32_t next_label_id_; uint32_t next_value_ordinal_; + std::vector locals_; + Block* block_head_; Block* block_tail_; Block* current_block_; diff --git a/src/alloy/hir/instr.cc b/src/alloy/hir/instr.cc index 35349f28e..51de2da2c 100644 --- a/src/alloy/hir/instr.cc +++ b/src/alloy/hir/instr.cc @@ -61,6 +61,36 @@ bool Instr::Match(SignatureType dest_req, ((src3_req == SIG_TYPE_IGNORE) || (src3_req == TO_SIG_TYPE(src3.value))); } +void Instr::MoveBefore(Instr* other) { + if (next == other) { + return; + } + + // Remove from current location. + if (prev) { + prev->next = next; + } else { + block->instr_head = next; + } + if (next) { + next->prev = prev; + } else { + block->instr_tail = prev; + } + + // Insert into new location. + block = other->block; + next = other; + prev = other->prev; + other->prev = this; + if (prev) { + prev->next = this; + } + if (other == block->instr_head) { + block->instr_head = this; + } +} + void Instr::Replace(const OpcodeInfo* opcode, uint16_t flags) { this->opcode = opcode; this->flags = flags; diff --git a/src/alloy/hir/instr.h b/src/alloy/hir/instr.h index 42b3c36bf..57effa650 100644 --- a/src/alloy/hir/instr.h +++ b/src/alloy/hir/instr.h @@ -79,6 +79,7 @@ public: SignatureType src2 = SIG_TYPE_X, SignatureType src3 = SIG_TYPE_X) const; + void MoveBefore(Instr* other); void Replace(const OpcodeInfo* opcode, uint16_t flags); void Remove(); }; diff --git a/src/alloy/hir/opcodes.h b/src/alloy/hir/opcodes.h index 2b8649afe..14e3d5d65 100644 --- a/src/alloy/hir/opcodes.h +++ b/src/alloy/hir/opcodes.h @@ -117,6 +117,9 @@ enum Opcode { OPCODE_LOAD_CLOCK, + OPCODE_LOAD_LOCAL, + OPCODE_STORE_LOCAL, + OPCODE_LOAD_CONTEXT, OPCODE_STORE_CONTEXT, @@ -202,6 +205,7 @@ enum OpcodeFlags { OPCODE_FLAG_VOLATILE = (1 << 4), OPCODE_FLAG_IGNORE = (1 << 5), OPCODE_FLAG_HIDE = (1 << 6), + OPCODE_FLAG_PAIRED_PREV = (1 << 7), }; enum OpcodeSignatureType { diff --git a/src/alloy/hir/opcodes.inl b/src/alloy/hir/opcodes.inl index 485fa529b..df1427db2 100644 --- a/src/alloy/hir/opcodes.inl +++ b/src/alloy/hir/opcodes.inl @@ -182,6 +182,18 @@ DEFINE_OPCODE( OPCODE_SIG_V, 0); +DEFINE_OPCODE( + OPCODE_LOAD_LOCAL, + "load_local", + OPCODE_SIG_V_V, + 0); + +DEFINE_OPCODE( + OPCODE_STORE_LOCAL, + "store_local", + OPCODE_SIG_X_V_V, + 0); + DEFINE_OPCODE( OPCODE_LOAD_CONTEXT, "load_context", @@ -297,17 +309,17 @@ DEFINE_OPCODE( OPCODE_DID_CARRY, "did_carry", OPCODE_SIG_V_V, - 0); + OPCODE_FLAG_PAIRED_PREV); DEFINE_OPCODE( OPCODE_DID_OVERFLOW, "did_overflow", OPCODE_SIG_V_V, - 0); + OPCODE_FLAG_PAIRED_PREV); DEFINE_OPCODE( OPCODE_DID_SATURATE, "did_saturate", OPCODE_SIG_V_V, - 0); + OPCODE_FLAG_PAIRED_PREV); DEFINE_OPCODE( OPCODE_VECTOR_COMPARE_EQ, diff --git a/src/alloy/hir/value.h b/src/alloy/hir/value.h index 6db5cc079..37a0a4a5a 100644 --- a/src/alloy/hir/value.h +++ b/src/alloy/hir/value.h @@ -42,6 +42,25 @@ static bool IsFloatType(TypeName type_name) { static bool IsVecType(TypeName type_name) { return type_name == VEC128_TYPE; } +static size_t GetTypeSize(TypeName type_name) { + switch (type_name) { + case INT8_TYPE: + return 1; + case INT16_TYPE: + return 2; + case INT32_TYPE: + return 4; + case INT64_TYPE: + return 8; + case FLOAT32_TYPE: + return 4; + case FLOAT64_TYPE: + return 8; + default: + case VEC128_TYPE: + return 16; + } +} enum ValueFlags { VALUE_IS_CONSTANT = (1 << 1), @@ -78,6 +97,7 @@ public: Use* use_head; // NOTE: for performance reasons this is not maintained during construction. Instr* last_use; + Value* local_slot; // TODO(benvanik): remove to shrink size. void* tag; diff --git a/third_party/llvm.gypi b/third_party/llvm.gypi new file mode 100644 index 000000000..3b8449729 --- /dev/null +++ b/third_party/llvm.gypi @@ -0,0 +1,35 @@ +# Copyright 2014 Ben Vanik. All Rights Reserved. +{ + 'targets': [ + { + 'target_name': 'llvm', + 'type': '<(library)', + + 'direct_dependent_settings': { + 'include_dirs': [ + 'llvm/include/', + ], + + 'defines': [ + ], + }, + + 'msvs_disabled_warnings': [4267], + + 'defines': [ + ], + + 'include_dirs': [ + 'llvm/include/', + ], + + 'sources': [ + 'llvm/dummy.cc', + 'llvm/include/llvm/ADT/BitVector.h', + 'llvm/include/llvm/Support/Compiler.h', + 'llvm/include/llvm/Support/MathExtras.h', + 'llvm/include/llvm/Support/type_traits.h', + ], + } + ] +} diff --git a/third_party/llvm/LICENSE.txt b/third_party/llvm/LICENSE.txt new file mode 100644 index 000000000..37d3c2552 --- /dev/null +++ b/third_party/llvm/LICENSE.txt @@ -0,0 +1,71 @@ +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2014 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +Autoconf llvm/autoconf + llvm/projects/ModuleMaker/autoconf + llvm/projects/sample/autoconf +Google Test llvm/utils/unittest/googletest +OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex} +pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT} +ARM contributions llvm/lib/Target/ARM/LICENSE.TXT +md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h diff --git a/third_party/llvm/dummy.cc b/third_party/llvm/dummy.cc new file mode 100644 index 000000000..ef866db23 --- /dev/null +++ b/third_party/llvm/dummy.cc @@ -0,0 +1 @@ +// here just to keep gyp happy diff --git a/third_party/llvm/include/llvm/ADT/BitVector.h b/third_party/llvm/include/llvm/ADT/BitVector.h new file mode 100644 index 000000000..90e6d3652 --- /dev/null +++ b/third_party/llvm/include/llvm/ADT/BitVector.h @@ -0,0 +1,602 @@ +//===- llvm/ADT/BitVector.h - Bit vectors -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the BitVector class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_BITVECTOR_H +#define LLVM_ADT_BITVECTOR_H + +#include "llvm/Support/Compiler.h" +#ifdef LLVM_IGNORE_XENIA +#include "llvm/Support/ErrorHandling.h" +#else +#define llvm_unreachable(msg) assert(false) +#endif // LLVM_IGNORE_XENIA +#include "llvm/Support/MathExtras.h" +#include +#include +#include +#include + +namespace llvm { + +class BitVector { + typedef unsigned long BitWord; + + enum { BITWORD_SIZE = (unsigned)sizeof(BitWord) * CHAR_BIT }; + + BitWord *Bits; // Actual bits. + unsigned Size; // Size of bitvector in bits. + unsigned Capacity; // Size of allocated memory in BitWord. + +public: + // Encapsulation of a single bit. + class reference { + friend class BitVector; + + BitWord *WordRef; + unsigned BitPos; + + reference(); // Undefined + + public: + reference(BitVector &b, unsigned Idx) { + WordRef = &b.Bits[Idx / BITWORD_SIZE]; + BitPos = Idx % BITWORD_SIZE; + } + + ~reference() {} + + reference &operator=(reference t) { + *this = bool(t); + return *this; + } + + reference& operator=(bool t) { + if (t) + *WordRef |= 1L << BitPos; + else + *WordRef &= ~(1L << BitPos); + return *this; + } + + operator bool() const { + return ((*WordRef) & (1L << BitPos)) ? true : false; + } + }; + + + /// BitVector default ctor - Creates an empty bitvector. + BitVector() : Size(0), Capacity(0) { + Bits = 0; + } + + /// BitVector ctor - Creates a bitvector of specified number of bits. All + /// bits are initialized to the specified value. + explicit BitVector(unsigned s, bool t = false) : Size(s) { + Capacity = NumBitWords(s); + Bits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); + init_words(Bits, Capacity, t); + if (t) + clear_unused_bits(); + } + + /// BitVector copy ctor. + BitVector(const BitVector &RHS) : Size(RHS.size()) { + if (Size == 0) { + Bits = 0; + Capacity = 0; + return; + } + + Capacity = NumBitWords(RHS.size()); + Bits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); + std::memcpy(Bits, RHS.Bits, Capacity * sizeof(BitWord)); + } + +#if LLVM_HAS_RVALUE_REFERENCES + BitVector(BitVector &&RHS) + : Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) { + RHS.Bits = 0; + } +#endif + + ~BitVector() { + std::free(Bits); + } + + /// empty - Tests whether there are no bits in this bitvector. + bool empty() const { return Size == 0; } + + /// size - Returns the number of bits in this bitvector. + unsigned size() const { return Size; } + + /// count - Returns the number of bits which are set. + unsigned count() const { + unsigned NumBits = 0; + for (unsigned i = 0; i < NumBitWords(size()); ++i) + if (sizeof(BitWord) == 4) + NumBits += CountPopulation_32((uint32_t)Bits[i]); + else if (sizeof(BitWord) == 8) + NumBits += CountPopulation_64(Bits[i]); + else + llvm_unreachable("Unsupported!"); + return NumBits; + } + + /// any - Returns true if any bit is set. + bool any() const { + for (unsigned i = 0; i < NumBitWords(size()); ++i) + if (Bits[i] != 0) + return true; + return false; + } + + /// all - Returns true if all bits are set. + bool all() const { + for (unsigned i = 0; i < Size / BITWORD_SIZE; ++i) + if (Bits[i] != ~0UL) + return false; + + // If bits remain check that they are ones. The unused bits are always zero. + if (unsigned Remainder = Size % BITWORD_SIZE) + return Bits[Size / BITWORD_SIZE] == (1UL << Remainder) - 1; + + return true; + } + + /// none - Returns true if none of the bits are set. + bool none() const { + return !any(); + } + + /// find_first - Returns the index of the first set bit, -1 if none + /// of the bits are set. + int find_first() const { + for (unsigned i = 0; i < NumBitWords(size()); ++i) + if (Bits[i] != 0) { + if (sizeof(BitWord) == 4) + return i * BITWORD_SIZE + countTrailingZeros((uint32_t)Bits[i]); + if (sizeof(BitWord) == 8) + return i * BITWORD_SIZE + countTrailingZeros(Bits[i]); + llvm_unreachable("Unsupported!"); + } + return -1; + } + + /// find_next - Returns the index of the next set bit following the + /// "Prev" bit. Returns -1 if the next set bit is not found. + int find_next(unsigned Prev) const { + ++Prev; + if (Prev >= Size) + return -1; + + unsigned WordPos = Prev / BITWORD_SIZE; + unsigned BitPos = Prev % BITWORD_SIZE; + BitWord Copy = Bits[WordPos]; + // Mask off previous bits. + Copy &= ~0UL << BitPos; + + if (Copy != 0) { + if (sizeof(BitWord) == 4) + return WordPos * BITWORD_SIZE + countTrailingZeros((uint32_t)Copy); + if (sizeof(BitWord) == 8) + return WordPos * BITWORD_SIZE + countTrailingZeros(Copy); + llvm_unreachable("Unsupported!"); + } + + // Check subsequent words. + for (unsigned i = WordPos+1; i < NumBitWords(size()); ++i) + if (Bits[i] != 0) { + if (sizeof(BitWord) == 4) + return i * BITWORD_SIZE + countTrailingZeros((uint32_t)Bits[i]); + if (sizeof(BitWord) == 8) + return i * BITWORD_SIZE + countTrailingZeros(Bits[i]); + llvm_unreachable("Unsupported!"); + } + return -1; + } + + /// clear - Clear all bits. + void clear() { + Size = 0; + } + + /// resize - Grow or shrink the bitvector. + void resize(unsigned N, bool t = false) { + if (N > Capacity * BITWORD_SIZE) { + unsigned OldCapacity = Capacity; + grow(N); + init_words(&Bits[OldCapacity], (Capacity-OldCapacity), t); + } + + // Set any old unused bits that are now included in the BitVector. This + // may set bits that are not included in the new vector, but we will clear + // them back out below. + if (N > Size) + set_unused_bits(t); + + // Update the size, and clear out any bits that are now unused + unsigned OldSize = Size; + Size = N; + if (t || N < OldSize) + clear_unused_bits(); + } + + void reserve(unsigned N) { + if (N > Capacity * BITWORD_SIZE) + grow(N); + } + + // Set, reset, flip + BitVector &set() { + init_words(Bits, Capacity, true); + clear_unused_bits(); + return *this; + } + + BitVector &set(unsigned Idx) { + Bits[Idx / BITWORD_SIZE] |= 1L << (Idx % BITWORD_SIZE); + return *this; + } + + /// set - Efficiently set a range of bits in [I, E) + BitVector &set(unsigned I, unsigned E) { + assert(I <= E && "Attempted to set backwards range!"); + assert(E <= size() && "Attempted to set out-of-bounds range!"); + + if (I == E) return *this; + + if (I / BITWORD_SIZE == E / BITWORD_SIZE) { + BitWord EMask = 1UL << (E % BITWORD_SIZE); + BitWord IMask = 1UL << (I % BITWORD_SIZE); + BitWord Mask = EMask - IMask; + Bits[I / BITWORD_SIZE] |= Mask; + return *this; + } + + BitWord PrefixMask = ~0UL << (I % BITWORD_SIZE); + Bits[I / BITWORD_SIZE] |= PrefixMask; + I = RoundUpToAlignment(I, BITWORD_SIZE); + + for (; I + BITWORD_SIZE <= E; I += BITWORD_SIZE) + Bits[I / BITWORD_SIZE] = ~0UL; + + BitWord PostfixMask = (1UL << (E % BITWORD_SIZE)) - 1; + if (I < E) + Bits[I / BITWORD_SIZE] |= PostfixMask; + + return *this; + } + + BitVector &reset() { + init_words(Bits, Capacity, false); + return *this; + } + + BitVector &reset(unsigned Idx) { + Bits[Idx / BITWORD_SIZE] &= ~(1L << (Idx % BITWORD_SIZE)); + return *this; + } + + /// reset - Efficiently reset a range of bits in [I, E) + BitVector &reset(unsigned I, unsigned E) { + assert(I <= E && "Attempted to reset backwards range!"); + assert(E <= size() && "Attempted to reset out-of-bounds range!"); + + if (I == E) return *this; + + if (I / BITWORD_SIZE == E / BITWORD_SIZE) { + BitWord EMask = 1UL << (E % BITWORD_SIZE); + BitWord IMask = 1UL << (I % BITWORD_SIZE); + BitWord Mask = EMask - IMask; + Bits[I / BITWORD_SIZE] &= ~Mask; + return *this; + } + + BitWord PrefixMask = ~0UL << (I % BITWORD_SIZE); + Bits[I / BITWORD_SIZE] &= ~PrefixMask; + I = RoundUpToAlignment(I, BITWORD_SIZE); + + for (; I + BITWORD_SIZE <= E; I += BITWORD_SIZE) + Bits[I / BITWORD_SIZE] = 0UL; + + BitWord PostfixMask = (1UL << (E % BITWORD_SIZE)) - 1; + if (I < E) + Bits[I / BITWORD_SIZE] &= ~PostfixMask; + + return *this; + } + + BitVector &flip() { + for (unsigned i = 0; i < NumBitWords(size()); ++i) + Bits[i] = ~Bits[i]; + clear_unused_bits(); + return *this; + } + + BitVector &flip(unsigned Idx) { + Bits[Idx / BITWORD_SIZE] ^= 1L << (Idx % BITWORD_SIZE); + return *this; + } + + // Indexing. + reference operator[](unsigned Idx) { + assert (Idx < Size && "Out-of-bounds Bit access."); + return reference(*this, Idx); + } + + bool operator[](unsigned Idx) const { + assert (Idx < Size && "Out-of-bounds Bit access."); + BitWord Mask = 1L << (Idx % BITWORD_SIZE); + return (Bits[Idx / BITWORD_SIZE] & Mask) != 0; + } + + bool test(unsigned Idx) const { + return (*this)[Idx]; + } + + /// Test if any common bits are set. + bool anyCommon(const BitVector &RHS) const { + unsigned ThisWords = NumBitWords(size()); + unsigned RHSWords = NumBitWords(RHS.size()); + for (unsigned i = 0, e = std::min(ThisWords, RHSWords); i != e; ++i) + if (Bits[i] & RHS.Bits[i]) + return true; + return false; + } + + // Comparison operators. + bool operator==(const BitVector &RHS) const { + unsigned ThisWords = NumBitWords(size()); + unsigned RHSWords = NumBitWords(RHS.size()); + unsigned i; + for (i = 0; i != std::min(ThisWords, RHSWords); ++i) + if (Bits[i] != RHS.Bits[i]) + return false; + + // Verify that any extra words are all zeros. + if (i != ThisWords) { + for (; i != ThisWords; ++i) + if (Bits[i]) + return false; + } else if (i != RHSWords) { + for (; i != RHSWords; ++i) + if (RHS.Bits[i]) + return false; + } + return true; + } + + bool operator!=(const BitVector &RHS) const { + return !(*this == RHS); + } + + /// Intersection, union, disjoint union. + BitVector &operator&=(const BitVector &RHS) { + unsigned ThisWords = NumBitWords(size()); + unsigned RHSWords = NumBitWords(RHS.size()); + unsigned i; + for (i = 0; i != std::min(ThisWords, RHSWords); ++i) + Bits[i] &= RHS.Bits[i]; + + // Any bits that are just in this bitvector become zero, because they aren't + // in the RHS bit vector. Any words only in RHS are ignored because they + // are already zero in the LHS. + for (; i != ThisWords; ++i) + Bits[i] = 0; + + return *this; + } + + /// reset - Reset bits that are set in RHS. Same as *this &= ~RHS. + BitVector &reset(const BitVector &RHS) { + unsigned ThisWords = NumBitWords(size()); + unsigned RHSWords = NumBitWords(RHS.size()); + unsigned i; + for (i = 0; i != std::min(ThisWords, RHSWords); ++i) + Bits[i] &= ~RHS.Bits[i]; + return *this; + } + + /// test - Check if (This - RHS) is zero. + /// This is the same as reset(RHS) and any(). + bool test(const BitVector &RHS) const { + unsigned ThisWords = NumBitWords(size()); + unsigned RHSWords = NumBitWords(RHS.size()); + unsigned i; + for (i = 0; i != std::min(ThisWords, RHSWords); ++i) + if ((Bits[i] & ~RHS.Bits[i]) != 0) + return true; + + for (; i != ThisWords ; ++i) + if (Bits[i] != 0) + return true; + + return false; + } + + BitVector &operator|=(const BitVector &RHS) { + if (size() < RHS.size()) + resize(RHS.size()); + for (size_t i = 0, e = NumBitWords(RHS.size()); i != e; ++i) + Bits[i] |= RHS.Bits[i]; + return *this; + } + + BitVector &operator^=(const BitVector &RHS) { + if (size() < RHS.size()) + resize(RHS.size()); + for (size_t i = 0, e = NumBitWords(RHS.size()); i != e; ++i) + Bits[i] ^= RHS.Bits[i]; + return *this; + } + + // Assignment operator. + const BitVector &operator=(const BitVector &RHS) { + if (this == &RHS) return *this; + + Size = RHS.size(); + unsigned RHSWords = NumBitWords(Size); + if (Size <= Capacity * BITWORD_SIZE) { + if (Size) + std::memcpy(Bits, RHS.Bits, RHSWords * sizeof(BitWord)); + clear_unused_bits(); + return *this; + } + + // Grow the bitvector to have enough elements. + Capacity = RHSWords; + BitWord *NewBits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); + std::memcpy(NewBits, RHS.Bits, Capacity * sizeof(BitWord)); + + // Destroy the old bits. + std::free(Bits); + Bits = NewBits; + + return *this; + } + +#if LLVM_HAS_RVALUE_REFERENCES + const BitVector &operator=(BitVector &&RHS) { + if (this == &RHS) return *this; + + std::free(Bits); + Bits = RHS.Bits; + Size = RHS.Size; + Capacity = RHS.Capacity; + + RHS.Bits = 0; + + return *this; + } +#endif + + void swap(BitVector &RHS) { + std::swap(Bits, RHS.Bits); + std::swap(Size, RHS.Size); + std::swap(Capacity, RHS.Capacity); + } + + //===--------------------------------------------------------------------===// + // Portable bit mask operations. + //===--------------------------------------------------------------------===// + // + // These methods all operate on arrays of uint32_t, each holding 32 bits. The + // fixed word size makes it easier to work with literal bit vector constants + // in portable code. + // + // The LSB in each word is the lowest numbered bit. The size of a portable + // bit mask is always a whole multiple of 32 bits. If no bit mask size is + // given, the bit mask is assumed to cover the entire BitVector. + + /// setBitsInMask - Add '1' bits from Mask to this vector. Don't resize. + /// This computes "*this |= Mask". + void setBitsInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { + applyMask(Mask, MaskWords); + } + + /// clearBitsInMask - Clear any bits in this vector that are set in Mask. + /// Don't resize. This computes "*this &= ~Mask". + void clearBitsInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { + applyMask(Mask, MaskWords); + } + + /// setBitsNotInMask - Add a bit to this vector for every '0' bit in Mask. + /// Don't resize. This computes "*this |= ~Mask". + void setBitsNotInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { + applyMask(Mask, MaskWords); + } + + /// clearBitsNotInMask - Clear a bit in this vector for every '0' bit in Mask. + /// Don't resize. This computes "*this &= Mask". + void clearBitsNotInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { + applyMask(Mask, MaskWords); + } + +private: + unsigned NumBitWords(unsigned S) const { + return (S + BITWORD_SIZE-1) / BITWORD_SIZE; + } + + // Set the unused bits in the high words. + void set_unused_bits(bool t = true) { + // Set high words first. + unsigned UsedWords = NumBitWords(Size); + if (Capacity > UsedWords) + init_words(&Bits[UsedWords], (Capacity-UsedWords), t); + + // Then set any stray high bits of the last used word. + unsigned ExtraBits = Size % BITWORD_SIZE; + if (ExtraBits) { + BitWord ExtraBitMask = ~0UL << ExtraBits; + if (t) + Bits[UsedWords-1] |= ExtraBitMask; + else + Bits[UsedWords-1] &= ~ExtraBitMask; + } + } + + // Clear the unused bits in the high words. + void clear_unused_bits() { + set_unused_bits(false); + } + + void grow(unsigned NewSize) { + Capacity = std::max(NumBitWords(NewSize), Capacity * 2); + Bits = (BitWord *)std::realloc(Bits, Capacity * sizeof(BitWord)); + + clear_unused_bits(); + } + + void init_words(BitWord *B, unsigned NumWords, bool t) { + memset(B, 0 - (int)t, NumWords*sizeof(BitWord)); + } + + template + void applyMask(const uint32_t *Mask, unsigned MaskWords) { + assert(BITWORD_SIZE % 32 == 0 && "Unsupported BitWord size."); + MaskWords = std::min(MaskWords, (size() + 31) / 32); + const unsigned Scale = BITWORD_SIZE / 32; + unsigned i; + for (i = 0; MaskWords >= Scale; ++i, MaskWords -= Scale) { + BitWord BW = Bits[i]; + // This inner loop should unroll completely when BITWORD_SIZE > 32. + for (unsigned b = 0; b != BITWORD_SIZE; b += 32) { + uint32_t M = *Mask++; + if (InvertMask) M = ~M; + if (AddBits) BW |= BitWord(M) << b; + else BW &= ~(BitWord(M) << b); + } + Bits[i] = BW; + } + for (unsigned b = 0; MaskWords; b += 32, --MaskWords) { + uint32_t M = *Mask++; + if (InvertMask) M = ~M; + if (AddBits) Bits[i] |= BitWord(M) << b; + else Bits[i] &= ~(BitWord(M) << b); + } + if (AddBits) + clear_unused_bits(); + } +}; + +} // End llvm namespace + +namespace std { + /// Implement std::swap in terms of BitVector swap. + inline void + swap(llvm::BitVector &LHS, llvm::BitVector &RHS) { + LHS.swap(RHS); + } +} + +#endif diff --git a/third_party/llvm/include/llvm/Support/Compiler.h b/third_party/llvm/include/llvm/Support/Compiler.h new file mode 100644 index 000000000..806e75917 --- /dev/null +++ b/third_party/llvm/include/llvm/Support/Compiler.h @@ -0,0 +1,446 @@ +//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines several macros, based on the current compiler. This allows +// use of compiler-specific features in a way that remains portable. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_COMPILER_H +#define LLVM_SUPPORT_COMPILER_H + +//#include "llvm/Config/llvm-config.h" + +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +#ifndef __has_extension +# define __has_extension(x) 0 +#endif + +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/// \macro __GNUC_PREREQ +/// \brief Defines __GNUC_PREREQ if glibc's features.h isn't available. +#ifndef __GNUC_PREREQ +# if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +/// \macro LLVM_MSC_PREREQ +/// \brief Is the compiler MSVC of at least the specified version? +/// The common \param version values to check for are: +/// * 1600: Microsoft Visual Studio 2010 / 10.0 +/// * 1700: Microsoft Visual Studio 2012 / 11.0 +/// * 1800: Microsoft Visual Studio 2013 / 12.0 +#ifdef _MSC_VER +#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version)) +#else +#define LLVM_MSC_PREREQ(version) 0 +#endif + +/// \brief Does the compiler support r-value references? +/// This implies that provides the one-argument std::move; it +/// does not imply the existence of any other C++ library features. +#if __has_feature(cxx_rvalue_references) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1600) +#define LLVM_HAS_RVALUE_REFERENCES 1 +#else +#define LLVM_HAS_RVALUE_REFERENCES 0 +#endif + +/// \brief Does the compiler support r-value reference *this? +/// +/// Sadly, this is separate from just r-value reference support because GCC +/// implemented everything but this thus far. No release of GCC yet has support +/// for this feature so it is enabled with Clang only. +/// FIXME: This should change to a version check when GCC grows support for it. +#if __has_feature(cxx_rvalue_references) +#define LLVM_HAS_RVALUE_REFERENCE_THIS 1 +#else +#define LLVM_HAS_RVALUE_REFERENCE_THIS 0 +#endif + +/// \macro LLVM_HAS_CXX11_TYPETRAITS +/// \brief Does the compiler have the C++11 type traits. +/// +/// #include +/// +/// * enable_if +/// * {true,false}_type +/// * is_constructible +/// * etc... +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1700) +#define LLVM_HAS_CXX11_TYPETRAITS 1 +#else +#define LLVM_HAS_CXX11_TYPETRAITS 0 +#endif + +/// \macro LLVM_HAS_CXX11_STDLIB +/// \brief Does the compiler have the C++11 standard library. +/// +/// Implies LLVM_HAS_RVALUE_REFERENCES, LLVM_HAS_CXX11_TYPETRAITS +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1700) +#define LLVM_HAS_CXX11_STDLIB 1 +#else +#define LLVM_HAS_CXX11_STDLIB 0 +#endif + +/// \macro LLVM_HAS_VARIADIC_TEMPLATES +/// \brief Does this compiler support variadic templates. +/// +/// Implies LLVM_HAS_RVALUE_REFERENCES and the existence of std::forward. +#if __has_feature(cxx_variadic_templates) || LLVM_MSC_PREREQ(1800) +# define LLVM_HAS_VARIADIC_TEMPLATES 1 +#else +# define LLVM_HAS_VARIADIC_TEMPLATES 0 +#endif + +/// llvm_move - Expands to ::std::move if the compiler supports +/// r-value references; otherwise, expands to the argument. +#if LLVM_HAS_RVALUE_REFERENCES +#define llvm_move(value) (::std::move(value)) +#else +#define llvm_move(value) (value) +#endif + +/// Expands to '&' if r-value references are supported. +/// +/// This can be used to provide l-value/r-value overrides of member functions. +/// The r-value override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS +#if LLVM_HAS_RVALUE_REFERENCE_THIS +#define LLVM_LVALUE_FUNCTION & +#else +#define LLVM_LVALUE_FUNCTION +#endif + +/// LLVM_DELETED_FUNCTION - Expands to = delete if the compiler supports it. +/// Use to mark functions as uncallable. Member functions with this should +/// be declared private so that some behavior is kept in C++03 mode. +/// +/// class DontCopy { +/// private: +/// DontCopy(const DontCopy&) LLVM_DELETED_FUNCTION; +/// DontCopy &operator =(const DontCopy&) LLVM_DELETED_FUNCTION; +/// public: +/// ... +/// }; +#if __has_feature(cxx_deleted_functions) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1800) +#define LLVM_DELETED_FUNCTION = delete +#else +#define LLVM_DELETED_FUNCTION +#endif + +/// LLVM_FINAL - Expands to 'final' if the compiler supports it. +/// Use to mark classes or virtual methods as final. +#if __has_feature(cxx_override_control) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1700) +#define LLVM_FINAL final +#else +#define LLVM_FINAL +#endif + +/// LLVM_OVERRIDE - Expands to 'override' if the compiler supports it. +/// Use to mark virtual methods as overriding a base class method. +#if __has_feature(cxx_override_control) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1700) +#define LLVM_OVERRIDE override +#else +#define LLVM_OVERRIDE +#endif + +#if __has_feature(cxx_constexpr) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define LLVM_CONSTEXPR constexpr +#else +# define LLVM_CONSTEXPR +#endif + +/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked +/// into a shared library, then the class should be private to the library and +/// not accessible from outside it. Can also be used to mark variables and +/// functions, making them private to any shared library they are linked into. +/// On PE/COFF targets, library visibility is the default, so this isn't needed. +#if (__has_attribute(visibility) || __GNUC_PREREQ(4, 0)) && \ + !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(LLVM_ON_WIN32) +#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden"))) +#else +#define LLVM_LIBRARY_VISIBILITY +#endif + +#if __has_attribute(used) || __GNUC_PREREQ(3, 1) +#define LLVM_ATTRIBUTE_USED __attribute__((__used__)) +#else +#define LLVM_ATTRIBUTE_USED +#endif + +#if __has_attribute(warn_unused_result) || __GNUC_PREREQ(3, 4) +#define LLVM_ATTRIBUTE_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#else +#define LLVM_ATTRIBUTE_UNUSED_RESULT +#endif + +// Some compilers warn about unused functions. When a function is sometimes +// used or not depending on build settings (e.g. a function only called from +// within "assert"), this attribute can be used to suppress such warnings. +// +// However, it shouldn't be used for unused *variables*, as those have a much +// more portable solution: +// (void)unused_var_name; +// Prefer cast-to-void wherever it is sufficient. +#if __has_attribute(unused) || __GNUC_PREREQ(3, 1) +#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#else +#define LLVM_ATTRIBUTE_UNUSED +#endif + +// FIXME: Provide this for PE/COFF targets. +#if (__has_attribute(weak) || __GNUC_PREREQ(4, 0)) && \ + (!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(LLVM_ON_WIN32)) +#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__)) +#else +#define LLVM_ATTRIBUTE_WEAK +#endif + +// Prior to clang 3.2, clang did not accept any spelling of +// __has_attribute(const), so assume it is supported. +#if defined(__clang__) || defined(__GNUC__) +// aka 'CONST' but following LLVM Conventions. +#define LLVM_READNONE __attribute__((__const__)) +#else +#define LLVM_READNONE +#endif + +#if __has_attribute(pure) || defined(__GNUC__) +// aka 'PURE' but following LLVM Conventions. +#define LLVM_READONLY __attribute__((__pure__)) +#else +#define LLVM_READONLY +#endif + +#if __has_builtin(__builtin_expect) || __GNUC_PREREQ(4, 0) +#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) +#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) +#else +#define LLVM_LIKELY(EXPR) (EXPR) +#define LLVM_UNLIKELY(EXPR) (EXPR) +#endif + +// C++ doesn't support 'extern template' of template specializations. GCC does, +// but requires __extension__ before it. In the header, use this: +// EXTERN_TEMPLATE_INSTANTIATION(class foo); +// in the .cpp file, use this: +// TEMPLATE_INSTANTIATION(class foo); +#ifdef __GNUC__ +#define EXTERN_TEMPLATE_INSTANTIATION(X) __extension__ extern template X +#define TEMPLATE_INSTANTIATION(X) template X +#else +#define EXTERN_TEMPLATE_INSTANTIATION(X) +#define TEMPLATE_INSTANTIATION(X) +#endif + +/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so, +/// mark a method "not for inlining". +#if __has_attribute(noinline) || __GNUC_PREREQ(3, 4) +#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline) +#else +#define LLVM_ATTRIBUTE_NOINLINE +#endif + +/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do +/// so, mark a method "always inline" because it is performance sensitive. GCC +/// 3.4 supported this but is buggy in various cases and produces unimplemented +/// errors, just use it in GCC 4.0 and later. +#if __has_attribute(always_inline) || __GNUC_PREREQ(4, 0) +#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline +#else +#define LLVM_ATTRIBUTE_ALWAYS_INLINE +#endif + +#ifdef __GNUC__ +#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn) +#else +#define LLVM_ATTRIBUTE_NORETURN +#endif + +/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress +/// pedantic diagnostics. +#ifdef __GNUC__ +#define LLVM_EXTENSION __extension__ +#else +#define LLVM_EXTENSION +#endif + +// LLVM_ATTRIBUTE_DEPRECATED(decl, "message") +#if __has_feature(attribute_deprecated_with_message) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl __attribute__((deprecated(message))) +#elif defined(__GNUC__) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + __declspec(deprecated(message)) decl +#else +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl +#endif + +/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands +/// to an expression which states that it is undefined behavior for the +/// compiler to reach this point. Otherwise is not defined. +#if __has_builtin(__builtin_unreachable) || __GNUC_PREREQ(4, 5) +# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +# define LLVM_BUILTIN_UNREACHABLE __assume(false) +#endif + +/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression +/// which causes the program to exit abnormally. +#if __has_builtin(__builtin_trap) || __GNUC_PREREQ(4, 3) +# define LLVM_BUILTIN_TRAP __builtin_trap() +#else +# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0 +#endif + +/// \macro LLVM_ASSUME_ALIGNED +/// \brief Returns a pointer with an assumed alignment. +#if __has_builtin(__builtin_assume_aligned) && __GNUC_PREREQ(4, 7) +# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a) +#elif defined(LLVM_BUILTIN_UNREACHABLE) +// As of today, clang does not support __builtin_assume_aligned. +# define LLVM_ASSUME_ALIGNED(p, a) \ + (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p))) +#else +# define LLVM_ASSUME_ALIGNED(p, a) (p) +#endif + +/// \macro LLVM_FUNCTION_NAME +/// \brief Expands to __func__ on compilers which support it. Otherwise, +/// expands to a compiler-dependent replacement. +#if defined(_MSC_VER) +# define LLVM_FUNCTION_NAME __FUNCTION__ +#else +# define LLVM_FUNCTION_NAME __func__ +#endif + +#if defined(HAVE_SANITIZER_MSAN_INTERFACE_H) +# include +#else +# define __msan_allocated_memory(p, size) +# define __msan_unpoison(p, size) +#endif + +/// \macro LLVM_MEMORY_SANITIZER_BUILD +/// \brief Whether LLVM itself is built with MemorySanitizer instrumentation. +#if __has_feature(memory_sanitizer) +# define LLVM_MEMORY_SANITIZER_BUILD 1 +#else +# define LLVM_MEMORY_SANITIZER_BUILD 0 +#endif + +/// \macro LLVM_ADDRESS_SANITIZER_BUILD +/// \brief Whether LLVM itself is built with AddressSanitizer instrumentation. +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define LLVM_ADDRESS_SANITIZER_BUILD 1 +#else +# define LLVM_ADDRESS_SANITIZER_BUILD 0 +#endif + +/// \macro LLVM_IS_UNALIGNED_ACCESS_FAST +/// \brief Is unaligned memory access fast on the host machine. +/// +/// Don't specialize on alignment for platforms where unaligned memory accesses +/// generates the same code as aligned memory accesses for common types. +#if defined(_M_AMD64) || defined(_M_IX86) || defined(__amd64) || \ + defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || \ + defined(_X86_) || defined(__i386) || defined(__i386__) +# define LLVM_IS_UNALIGNED_ACCESS_FAST 1 +#else +# define LLVM_IS_UNALIGNED_ACCESS_FAST 0 +#endif + +/// \macro LLVM_EXPLICIT +/// \brief Expands to explicit on compilers which support explicit conversion +/// operators. Otherwise expands to nothing. +#if __has_feature(cxx_explicit_conversions) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1800) +#define LLVM_EXPLICIT explicit +#else +#define LLVM_EXPLICIT +#endif + +/// \macro LLVM_STATIC_ASSERT +/// \brief Expands to C/C++'s static_assert on compilers which support it. +#if __has_feature(cxx_static_assert) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1600) +# define LLVM_STATIC_ASSERT(expr, msg) static_assert(expr, msg) +#elif __has_feature(c_static_assert) +# define LLVM_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg) +#elif __has_extension(c_static_assert) +# define LLVM_STATIC_ASSERT(expr, msg) LLVM_EXTENSION _Static_assert(expr, msg) +#else +# define LLVM_STATIC_ASSERT(expr, msg) +#endif + +/// \macro LLVM_ENUM_INT_TYPE +/// \brief Expands to colon followed by the given integral type on compilers +/// which support C++11 strong enums. This can be used to make enums unsigned +/// with MSVC. +#if __has_feature(cxx_strong_enums) || LLVM_MSC_PREREQ(1600) +# define LLVM_ENUM_INT_TYPE(intty) : intty +#else +# define LLVM_ENUM_INT_TYPE(intty) +#endif + +/// \brief Does the compiler support C++11 semantics for strongly typed forward +/// declared enums? +#if __has_feature(cxx_strong_enums) || LLVM_MSC_PREREQ(1700) +#define LLVM_HAS_STRONG_ENUMS 1 +#else +#define LLVM_HAS_STRONG_ENUMS 0 +#endif + +/// \brief Does the compiler support generalized initializers (using braced +/// lists and std::initializer_list). While clang may claim it supports general +/// initializers, if we're using MSVC's headers, we might not have a usable +/// std::initializer list type from the STL. Disable this for now. +#if __has_feature(cxx_generalized_initializers) && !defined(_MSC_VER) +#define LLVM_HAS_INITIALIZER_LISTS 1 +#else +#define LLVM_HAS_INITIALIZER_LISTS 0 +#endif + +/// \brief Mark debug helper function definitions like dump() that should not be +/// stripped from debug builds. +// FIXME: Move this to a private config.h as it's not usable in public headers. +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED +#else +#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE +#endif + +#endif diff --git a/third_party/llvm/include/llvm/Support/MathExtras.h b/third_party/llvm/include/llvm/Support/MathExtras.h new file mode 100644 index 000000000..4d2ff0989 --- /dev/null +++ b/third_party/llvm/include/llvm/Support/MathExtras.h @@ -0,0 +1,626 @@ +//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains some functions that are useful for math stuff. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MATHEXTRAS_H +#define LLVM_SUPPORT_MATHEXTRAS_H + +#include "llvm/Support/Compiler.h" +#ifdef IGNORED_LLVM_XENIA +#include "llvm/Support/SwapByteOrder.h" +#endif // IGNORED_LLVM_XENIA +#include "llvm/Support/type_traits.h" +#include + +#ifdef _MSC_VER +#include +#include +#endif + +namespace llvm { +/// \brief The behavior an operation has on an input of 0. +enum ZeroBehavior { + /// \brief The returned value is undefined. + ZB_Undefined, + /// \brief The returned value is numeric_limits::max() + ZB_Max, + /// \brief The returned value is numeric_limits::digits + ZB_Width +}; + +/// \brief Count number of 0's from the least significant bit to the most +/// stopping at the first 1. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are +/// valid arguments. +template +typename enable_if_c::is_integer && + !std::numeric_limits::is_signed, std::size_t>::type +countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) { + (void)ZB; + + if (!Val) + return std::numeric_limits::digits; + if (Val & 0x1) + return 0; + + // Bisection method. + std::size_t ZeroBits = 0; + T Shift = std::numeric_limits::digits >> 1; + T Mask = std::numeric_limits::max() >> Shift; + while (Shift) { + if ((Val & Mask) == 0) { + Val >>= Shift; + ZeroBits |= Shift; + } + Shift >>= 1; + Mask >>= Shift; + } + return ZeroBits; +} + +// Disable signed. +template +typename enable_if_c::is_integer && + std::numeric_limits::is_signed, std::size_t>::type +countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) LLVM_DELETED_FUNCTION; + +#if __GNUC__ >= 4 || _MSC_VER +template <> +inline std::size_t countTrailingZeros(uint32_t Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 32; + +#if __has_builtin(__builtin_ctz) || __GNUC_PREREQ(4, 0) + return __builtin_ctz(Val); +#elif _MSC_VER + unsigned long Index; + _BitScanForward(&Index, Val); + return Index; +#endif +} + +#if !defined(_MSC_VER) || defined(_M_X64) +template <> +inline std::size_t countTrailingZeros(uint64_t Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 64; + +#if __has_builtin(__builtin_ctzll) || __GNUC_PREREQ(4, 0) + return __builtin_ctzll(Val); +#elif _MSC_VER + unsigned long Index; + _BitScanForward64(&Index, Val); + return Index; +#endif +} +#endif +#endif + +/// \brief Count number of 0's from the most significant bit to the least +/// stopping at the first 1. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are +/// valid arguments. +template +typename enable_if_c::is_integer && + !std::numeric_limits::is_signed, std::size_t>::type +countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) { + (void)ZB; + + if (!Val) + return std::numeric_limits::digits; + + // Bisection method. + std::size_t ZeroBits = 0; + for (T Shift = std::numeric_limits::digits >> 1; Shift; Shift >>= 1) { + T Tmp = Val >> Shift; + if (Tmp) + Val = Tmp; + else + ZeroBits |= Shift; + } + return ZeroBits; +} + +// Disable signed. +template +typename enable_if_c::is_integer && + std::numeric_limits::is_signed, std::size_t>::type +countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) LLVM_DELETED_FUNCTION; + +#if __GNUC__ >= 4 || _MSC_VER +template <> +inline std::size_t countLeadingZeros(uint32_t Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 32; + +#if __has_builtin(__builtin_clz) || __GNUC_PREREQ(4, 0) + return __builtin_clz(Val); +#elif _MSC_VER + unsigned long Index; + _BitScanReverse(&Index, Val); + return Index ^ 31; +#endif +} + +#if !defined(_MSC_VER) || defined(_M_X64) +template <> +inline std::size_t countLeadingZeros(uint64_t Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 64; + +#if __has_builtin(__builtin_clzll) || __GNUC_PREREQ(4, 0) + return __builtin_clzll(Val); +#elif _MSC_VER + unsigned long Index; + _BitScanReverse64(&Index, Val); + return Index ^ 63; +#endif +} +#endif +#endif + +/// \brief Get the index of the first set bit starting from the least +/// significant bit. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are +/// valid arguments. +template +typename enable_if_c::is_integer && + !std::numeric_limits::is_signed, T>::type +findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) { + if (ZB == ZB_Max && Val == 0) + return std::numeric_limits::max(); + + return countTrailingZeros(Val, ZB_Undefined); +} + +// Disable signed. +template +typename enable_if_c::is_integer && + std::numeric_limits::is_signed, T>::type +findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) LLVM_DELETED_FUNCTION; + +/// \brief Get the index of the last set bit starting from the least +/// significant bit. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are +/// valid arguments. +template +typename enable_if_c::is_integer && + !std::numeric_limits::is_signed, T>::type +findLastSet(T Val, ZeroBehavior ZB = ZB_Max) { + if (ZB == ZB_Max && Val == 0) + return std::numeric_limits::max(); + + // Use ^ instead of - because both gcc and llvm can remove the associated ^ + // in the __builtin_clz intrinsic on x86. + return countLeadingZeros(Val, ZB_Undefined) ^ + (std::numeric_limits::digits - 1); +} + +// Disable signed. +template +typename enable_if_c::is_integer && + std::numeric_limits::is_signed, T>::type +findLastSet(T Val, ZeroBehavior ZB = ZB_Max) LLVM_DELETED_FUNCTION; + +/// \brief Macro compressed bit reversal table for 256 bits. +/// +/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable +static const unsigned char BitReverseTable256[256] = { +#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64 +#define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16) +#define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4) + R6(0), R6(2), R6(1), R6(3) +}; + +/// \brief Reverse the bits in \p Val. +template +T reverseBits(T Val) { + unsigned char in[sizeof(Val)]; + unsigned char out[sizeof(Val)]; + std::memcpy(in, &Val, sizeof(Val)); + for (unsigned i = 0; i < sizeof(Val); ++i) + out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]]; + std::memcpy(&Val, out, sizeof(Val)); + return Val; +} + +// NOTE: The following support functions use the _32/_64 extensions instead of +// type overloading so that signed and unsigned integers can be used without +// ambiguity. + +/// Hi_32 - This function returns the high 32 bits of a 64 bit value. +inline uint32_t Hi_32(uint64_t Value) { + return static_cast(Value >> 32); +} + +/// Lo_32 - This function returns the low 32 bits of a 64 bit value. +inline uint32_t Lo_32(uint64_t Value) { + return static_cast(Value); +} + +/// isInt - Checks if an integer fits into the given bit width. +template +inline bool isInt(int64_t x) { + return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1))); +} +// Template specializations to get better code for common cases. +template<> +inline bool isInt<8>(int64_t x) { + return static_cast(x) == x; +} +template<> +inline bool isInt<16>(int64_t x) { + return static_cast(x) == x; +} +template<> +inline bool isInt<32>(int64_t x) { + return static_cast(x) == x; +} + +/// isShiftedInt - Checks if a signed integer is an N bit number shifted +/// left by S. +template +inline bool isShiftedInt(int64_t x) { + return isInt(x) && (x % (1< +inline bool isUInt(uint64_t x) { + return N >= 64 || x < (UINT64_C(1)<<(N)); +} +// Template specializations to get better code for common cases. +template<> +inline bool isUInt<8>(uint64_t x) { + return static_cast(x) == x; +} +template<> +inline bool isUInt<16>(uint64_t x) { + return static_cast(x) == x; +} +template<> +inline bool isUInt<32>(uint64_t x) { + return static_cast(x) == x; +} + +/// isShiftedUInt - Checks if a unsigned integer is an N bit number shifted +/// left by S. +template +inline bool isShiftedUInt(uint64_t x) { + return isUInt(x) && (x % (1<> (64 - N))); +} + +/// isIntN - Checks if an signed integer fits into the given (dynamic) +/// bit width. +inline bool isIntN(unsigned N, int64_t x) { + return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1))); +} + +/// isMask_32 - This function returns true if the argument is a sequence of ones +/// starting at the least significant bit with the remainder zero (32 bit +/// version). Ex. isMask_32(0x0000FFFFU) == true. +inline bool isMask_32(uint32_t Value) { + return Value && ((Value + 1) & Value) == 0; +} + +/// isMask_64 - This function returns true if the argument is a sequence of ones +/// starting at the least significant bit with the remainder zero (64 bit +/// version). +inline bool isMask_64(uint64_t Value) { + return Value && ((Value + 1) & Value) == 0; +} + +/// isShiftedMask_32 - This function returns true if the argument contains a +/// sequence of ones with the remainder zero (32 bit version.) +/// Ex. isShiftedMask_32(0x0000FF00U) == true. +inline bool isShiftedMask_32(uint32_t Value) { + return isMask_32((Value - 1) | Value); +} + +/// isShiftedMask_64 - This function returns true if the argument contains a +/// sequence of ones with the remainder zero (64 bit version.) +inline bool isShiftedMask_64(uint64_t Value) { + return isMask_64((Value - 1) | Value); +} + +/// isPowerOf2_32 - This function returns true if the argument is a power of +/// two > 0. Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.) +inline bool isPowerOf2_32(uint32_t Value) { + return Value && !(Value & (Value - 1)); +} + +/// isPowerOf2_64 - This function returns true if the argument is a power of two +/// > 0 (64 bit edition.) +inline bool isPowerOf2_64(uint64_t Value) { + return Value && !(Value & (Value - int64_t(1L))); +} + +#ifdef IGNORED_LLVM_XENIA +/// ByteSwap_16 - This function returns a byte-swapped representation of the +/// 16-bit argument, Value. +inline uint16_t ByteSwap_16(uint16_t Value) { + return sys::SwapByteOrder_16(Value); +} + +/// ByteSwap_32 - This function returns a byte-swapped representation of the +/// 32-bit argument, Value. +inline uint32_t ByteSwap_32(uint32_t Value) { + return sys::SwapByteOrder_32(Value); +} + +/// ByteSwap_64 - This function returns a byte-swapped representation of the +/// 64-bit argument, Value. +inline uint64_t ByteSwap_64(uint64_t Value) { + return sys::SwapByteOrder_64(Value); +} +#endif // IGNORED_LLVM_XENIA + +/// CountLeadingOnes_32 - this function performs the operation of +/// counting the number of ones from the most significant bit to the first zero +/// bit. Ex. CountLeadingOnes_32(0xFF0FFF00) == 8. +/// Returns 32 if the word is all ones. +inline unsigned CountLeadingOnes_32(uint32_t Value) { + return countLeadingZeros(~Value); +} + +/// CountLeadingOnes_64 - This function performs the operation +/// of counting the number of ones from the most significant bit to the first +/// zero bit (64 bit edition.) +/// Returns 64 if the word is all ones. +inline unsigned CountLeadingOnes_64(uint64_t Value) { + return countLeadingZeros(~Value); +} + +/// CountTrailingOnes_32 - this function performs the operation of +/// counting the number of ones from the least significant bit to the first zero +/// bit. Ex. CountTrailingOnes_32(0x00FF00FF) == 8. +/// Returns 32 if the word is all ones. +inline unsigned CountTrailingOnes_32(uint32_t Value) { + return countTrailingZeros(~Value); +} + +/// CountTrailingOnes_64 - This function performs the operation +/// of counting the number of ones from the least significant bit to the first +/// zero bit (64 bit edition.) +/// Returns 64 if the word is all ones. +inline unsigned CountTrailingOnes_64(uint64_t Value) { + return countTrailingZeros(~Value); +} + +/// CountPopulation_32 - this function counts the number of set bits in a value. +/// Ex. CountPopulation(0xF000F000) = 8 +/// Returns 0 if the word is zero. +inline unsigned CountPopulation_32(uint32_t Value) { +#if __GNUC__ >= 4 + return __builtin_popcount(Value); +#else + uint32_t v = Value - ((Value >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; +#endif +} + +/// CountPopulation_64 - this function counts the number of set bits in a value, +/// (64 bit edition.) +inline unsigned CountPopulation_64(uint64_t Value) { +#if __GNUC__ >= 4 + return __builtin_popcountll(Value); +#else + uint64_t v = Value - ((Value >> 1) & 0x5555555555555555ULL); + v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL); + v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL; + return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56); +#endif +} + +/// Log2_32 - This function returns the floor log base 2 of the specified value, +/// -1 if the value is zero. (32 bit edition.) +/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2 +inline unsigned Log2_32(uint32_t Value) { + return 31 - countLeadingZeros(Value); +} + +/// Log2_64 - This function returns the floor log base 2 of the specified value, +/// -1 if the value is zero. (64 bit edition.) +inline unsigned Log2_64(uint64_t Value) { + return 63 - countLeadingZeros(Value); +} + +/// Log2_32_Ceil - This function returns the ceil log base 2 of the specified +/// value, 32 if the value is zero. (32 bit edition). +/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3 +inline unsigned Log2_32_Ceil(uint32_t Value) { + return 32 - countLeadingZeros(Value - 1); +} + +/// Log2_64_Ceil - This function returns the ceil log base 2 of the specified +/// value, 64 if the value is zero. (64 bit edition.) +inline unsigned Log2_64_Ceil(uint64_t Value) { + return 64 - countLeadingZeros(Value - 1); +} + +/// GreatestCommonDivisor64 - Return the greatest common divisor of the two +/// values using Euclid's algorithm. +inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) { + while (B) { + uint64_t T = B; + B = A % B; + A = T; + } + return A; +} + +/// BitsToDouble - This function takes a 64-bit integer and returns the bit +/// equivalent double. +inline double BitsToDouble(uint64_t Bits) { + union { + uint64_t L; + double D; + } T; + T.L = Bits; + return T.D; +} + +/// BitsToFloat - This function takes a 32-bit integer and returns the bit +/// equivalent float. +inline float BitsToFloat(uint32_t Bits) { + union { + uint32_t I; + float F; + } T; + T.I = Bits; + return T.F; +} + +/// DoubleToBits - This function takes a double and returns the bit +/// equivalent 64-bit integer. Note that copying doubles around +/// changes the bits of NaNs on some hosts, notably x86, so this +/// routine cannot be used if these bits are needed. +inline uint64_t DoubleToBits(double Double) { + union { + uint64_t L; + double D; + } T; + T.D = Double; + return T.L; +} + +/// FloatToBits - This function takes a float and returns the bit +/// equivalent 32-bit integer. Note that copying floats around +/// changes the bits of NaNs on some hosts, notably x86, so this +/// routine cannot be used if these bits are needed. +inline uint32_t FloatToBits(float Float) { + union { + uint32_t I; + float F; + } T; + T.F = Float; + return T.I; +} + +/// Platform-independent wrappers for the C99 isnan() function. +int IsNAN(float f); +int IsNAN(double d); + +/// Platform-independent wrappers for the C99 isinf() function. +int IsInf(float f); +int IsInf(double d); + +/// MinAlign - A and B are either alignments or offsets. Return the minimum +/// alignment that may be assumed after adding the two together. +inline uint64_t MinAlign(uint64_t A, uint64_t B) { + // The largest power of 2 that divides both A and B. + // + // Replace "-Value" by "1+~Value" in the following commented code to avoid + // MSVC warning C4146 + // return (A | B) & -(A | B); + return (A | B) & (1 + ~(A | B)); +} + +/// NextPowerOf2 - Returns the next power of two (in 64-bits) +/// that is strictly greater than A. Returns zero on overflow. +inline uint64_t NextPowerOf2(uint64_t A) { + A |= (A >> 1); + A |= (A >> 2); + A |= (A >> 4); + A |= (A >> 8); + A |= (A >> 16); + A |= (A >> 32); + return A + 1; +} + +/// Returns the power of two which is less than or equal to the given value. +/// Essentially, it is a floor operation across the domain of powers of two. +inline uint64_t PowerOf2Floor(uint64_t A) { + if (!A) return 0; + return 1ull << (63 - countLeadingZeros(A, ZB_Undefined)); +} + +/// Returns the next integer (mod 2**64) that is greater than or equal to +/// \p Value and is a multiple of \p Align. \p Align must be non-zero. +/// +/// Examples: +/// \code +/// RoundUpToAlignment(5, 8) = 8 +/// RoundUpToAlignment(17, 8) = 24 +/// RoundUpToAlignment(~0LL, 8) = 0 +/// \endcode +inline uint64_t RoundUpToAlignment(uint64_t Value, uint64_t Align) { + return ((Value + Align - 1) / Align) * Align; +} + +/// Returns the offset to the next integer (mod 2**64) that is greater than +/// or equal to \p Value and is a multiple of \p Align. \p Align must be +/// non-zero. +inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) { + return RoundUpToAlignment(Value, Align) - Value; +} + +/// abs64 - absolute value of a 64-bit int. Not all environments support +/// "abs" on whatever their name for the 64-bit int type is. The absolute +/// value of the largest negative number is undefined, as with "abs". +inline int64_t abs64(int64_t x) { + return (x < 0) ? -x : x; +} + +/// SignExtend32 - Sign extend B-bit number x to 32-bit int. +/// Usage int32_t r = SignExtend32<5>(x); +template inline int32_t SignExtend32(uint32_t x) { + return int32_t(x << (32 - B)) >> (32 - B); +} + +/// \brief Sign extend number in the bottom B bits of X to a 32-bit int. +/// Requires 0 < B <= 32. +inline int32_t SignExtend32(uint32_t X, unsigned B) { + return int32_t(X << (32 - B)) >> (32 - B); +} + +/// SignExtend64 - Sign extend B-bit number x to 64-bit int. +/// Usage int64_t r = SignExtend64<5>(x); +template inline int64_t SignExtend64(uint64_t x) { + return int64_t(x << (64 - B)) >> (64 - B); +} + +/// \brief Sign extend number in the bottom B bits of X to a 64-bit int. +/// Requires 0 < B <= 64. +inline int64_t SignExtend64(uint64_t X, unsigned B) { + return int64_t(X << (64 - B)) >> (64 - B); +} + +#if defined(_MSC_VER) + // Visual Studio defines the HUGE_VAL class of macros using purposeful + // constant arithmetic overflow, which it then warns on when encountered. + const float huge_valf = std::numeric_limits::infinity(); +#else + const float huge_valf = HUGE_VALF; +#endif +} // End llvm namespace + +#endif diff --git a/third_party/llvm/include/llvm/Support/type_traits.h b/third_party/llvm/include/llvm/Support/type_traits.h new file mode 100644 index 000000000..ad812de98 --- /dev/null +++ b/third_party/llvm/include/llvm/Support/type_traits.h @@ -0,0 +1,244 @@ +//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a template class that determines if a type is a class or +// not. The basic mechanism, based on using the pointer to member function of +// a zero argument to a function was "boosted" from the boost type_traits +// library. See http://www.boost.org/ for all the gory details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TYPE_TRAITS_H +#define LLVM_SUPPORT_TYPE_TRAITS_H + +//#include "llvm/Support/DataTypes.h" +#include +#include + +#ifndef __has_feature +#define LLVM_DEFINED_HAS_FEATURE +#define __has_feature(x) 0 +#endif + +// This is actually the conforming implementation which works with abstract +// classes. However, enough compilers have trouble with it that most will use +// the one in boost/type_traits/object_traits.hpp. This implementation actually +// works with VC7.0, but other interactions seem to fail when we use it. + +namespace llvm { + +namespace dont_use +{ + // These two functions should never be used. They are helpers to + // the is_class template below. They cannot be located inside + // is_class because doing so causes at least GCC to think that + // the value of the "value" enumerator is not constant. Placing + // them out here (for some strange reason) allows the sizeof + // operator against them to magically be constant. This is + // important to make the is_class::value idiom zero cost. it + // evaluates to a constant 1 or 0 depending on whether the + // parameter T is a class or not (respectively). + template char is_class_helper(void(T::*)()); + template double is_class_helper(...); +} + +template +struct is_class +{ + // is_class<> metafunction due to Paul Mensonides (leavings@attbi.com). For + // more details: + // http://groups.google.com/groups?hl=en&selm=000001c1cc83%24e154d5e0%247772e50c%40c161550a&rnum=1 +public: + static const bool value = + sizeof(char) == sizeof(dont_use::is_class_helper(0)); +}; + + +/// isPodLike - This is a type trait that is used to determine whether a given +/// type can be copied around with memcpy instead of running ctors etc. +template +struct isPodLike { +#if __has_feature(is_trivially_copyable) + // If the compiler supports the is_trivially_copyable trait use it, as it + // matches the definition of isPodLike closely. + static const bool value = __is_trivially_copyable(T); +#else + // If we don't know anything else, we can (at least) assume that all non-class + // types are PODs. + static const bool value = !is_class::value; +#endif +}; + +// std::pair's are pod-like if their elements are. +template +struct isPodLike > { + static const bool value = isPodLike::value && isPodLike::value; +}; + + +template +struct integral_constant { + typedef T value_type; + static const value_type value = v; + typedef integral_constant type; + operator value_type() { return value; } +}; + +typedef integral_constant true_type; +typedef integral_constant false_type; + +/// \brief Metafunction that determines whether the two given types are +/// equivalent. +template struct is_same : public false_type {}; +template struct is_same : public true_type {}; + +/// \brief Metafunction that removes const qualification from a type. +template struct remove_const { typedef T type; }; +template struct remove_const { typedef T type; }; + +/// \brief Metafunction that removes volatile qualification from a type. +template struct remove_volatile { typedef T type; }; +template struct remove_volatile { typedef T type; }; + +/// \brief Metafunction that removes both const and volatile qualification from +/// a type. +template struct remove_cv { + typedef typename remove_const::type>::type type; +}; + +/// \brief Helper to implement is_integral metafunction. +template struct is_integral_impl : false_type {}; +template <> struct is_integral_impl< bool> : true_type {}; +template <> struct is_integral_impl< char> : true_type {}; +template <> struct is_integral_impl< signed char> : true_type {}; +template <> struct is_integral_impl : true_type {}; +template <> struct is_integral_impl< wchar_t> : true_type {}; +template <> struct is_integral_impl< short> : true_type {}; +template <> struct is_integral_impl : true_type {}; +template <> struct is_integral_impl< int> : true_type {}; +template <> struct is_integral_impl : true_type {}; +template <> struct is_integral_impl< long> : true_type {}; +template <> struct is_integral_impl : true_type {}; +template <> struct is_integral_impl< long long> : true_type {}; +template <> struct is_integral_impl : true_type {}; + +/// \brief Metafunction that determines whether the given type is an integral +/// type. +template +struct is_integral : is_integral_impl {}; + +/// \brief Metafunction to remove reference from a type. +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +/// \brief Metafunction that determines whether the given type is a pointer +/// type. +template struct is_pointer : false_type {}; +template struct is_pointer : true_type {}; +template struct is_pointer : true_type {}; +template struct is_pointer : true_type {}; +template struct is_pointer : true_type {}; + +/// \brief Metafunction that determines wheather the given type is a reference. +template struct is_reference : false_type {}; +template struct is_reference : true_type {}; + +/// \brief Metafunction that determines whether the given type is either an +/// integral type or an enumeration type. +/// +/// Note that this accepts potentially more integral types than we whitelist +/// above for is_integral because it is based on merely being convertible +/// implicitly to an integral type. +template class is_integral_or_enum { + // Provide an overload which can be called with anything implicitly + // convertible to an unsigned long long. This should catch integer types and + // enumeration types at least. We blacklist classes with conversion operators + // below. + static double check_int_convertible(unsigned long long); + static char check_int_convertible(...); + + typedef typename remove_reference::type UnderlyingT; + static UnderlyingT &nonce_instance; + +public: + static const bool + value = (!is_class::value && !is_pointer::value && + !is_same::value && + !is_same::value && + sizeof(char) != sizeof(check_int_convertible(nonce_instance))); +}; + +// enable_if_c - Enable/disable a template based on a metafunction +template +struct enable_if_c { + typedef T type; +}; + +template struct enable_if_c { }; + +// enable_if - Enable/disable a template based on a metafunction +template +struct enable_if : public enable_if_c { }; + +namespace dont_use { + template char base_of_helper(const volatile Base*); + template double base_of_helper(...); +} + +/// is_base_of - Metafunction to determine whether one type is a base class of +/// (or identical to) another type. +template +struct is_base_of { + static const bool value + = is_class::value && is_class::value && + sizeof(char) == sizeof(dont_use::base_of_helper((Derived*)0)); +}; + +// remove_pointer - Metafunction to turn Foo* into Foo. Defined in +// C++0x [meta.trans.ptr]. +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { + typedef T type; }; + +// If T is a pointer, just return it. If it is not, return T&. +template +struct add_lvalue_reference_if_not_pointer { typedef T &type; }; + +template +struct add_lvalue_reference_if_not_pointer >::type> { + typedef T type; +}; + +// If T is a pointer to X, return a pointer to const X. If it is not, return +// const T. +template +struct add_const_past_pointer { typedef const T type; }; + +template +struct add_const_past_pointer >::type> { + typedef const typename remove_pointer::type *type; +}; + +template +struct conditional { typedef T type; }; + +template +struct conditional { typedef F type; }; + +} + +#ifdef LLVM_DEFINED_HAS_FEATURE +#undef __has_feature +#endif + +#endif diff --git a/xenia.gyp b/xenia.gyp index ddcd45b2a..aea3ec75f 100644 --- a/xenia.gyp +++ b/xenia.gyp @@ -5,6 +5,7 @@ 'third_party/beaengine.gypi', 'third_party/gflags.gypi', 'third_party/jansson.gypi', + 'third_party/llvm.gypi', 'third_party/sparsehash.gypi', 'third_party/wslay.gypi', ], @@ -187,10 +188,12 @@ 'dependencies': [ 'beaengine', 'gflags', + 'llvm', ], 'export_dependent_settings': [ 'beaengine', 'gflags', + 'llvm', ], 'direct_dependent_settings': {