From 0b42c72ec59b9eb4c4a1373172526201aa7c4c12 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Fri, 30 May 2014 20:09:00 -0700 Subject: [PATCH] Fixing const propagated DID_CARRY. --- src/alloy/backend/x64/x64_sequences.cc | 11 +++-- .../passes/constant_propagation_pass.cc | 49 +++++++++++++++++-- .../passes/constant_propagation_pass.h | 1 + src/alloy/hir/value.cc | 19 ++++++- src/alloy/hir/value.h | 4 +- 5 files changed, 74 insertions(+), 10 deletions(-) diff --git a/src/alloy/backend/x64/x64_sequences.cc b/src/alloy/backend/x64/x64_sequences.cc index 3b7d386f0..629c5bf33 100644 --- a/src/alloy/backend/x64/x64_sequences.cc +++ b/src/alloy/backend/x64/x64_sequences.cc @@ -2329,24 +2329,28 @@ EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(UGE, setae); // https://code.google.com/p/corkami/wiki/x86oddities EMITTER(DID_CARRY_I8, MATCH(I, I8<>>)) { static void Emit(X64Emitter& e, const EmitArgType& i) { + XEASSERT(!i.src1.is_constant); e.LoadEflags(); e.setc(i.dest); } }; EMITTER(DID_CARRY_I16, MATCH(I, I16<>>)) { static void Emit(X64Emitter& e, const EmitArgType& i) { + XEASSERT(!i.src1.is_constant); e.LoadEflags(); e.setc(i.dest); } }; EMITTER(DID_CARRY_I32, MATCH(I, I32<>>)) { static void Emit(X64Emitter& e, const EmitArgType& i) { + XEASSERT(!i.src1.is_constant); e.LoadEflags(); e.setc(i.dest); } }; EMITTER(DID_CARRY_I64, MATCH(I, I64<>>)) { static void Emit(X64Emitter& e, const EmitArgType& i) { + XEASSERT(!i.src1.is_constant); e.LoadEflags(); e.setc(i.dest); } @@ -4414,8 +4418,8 @@ EMITTER(EXTRACT_I8, MATCH(I, V128<>, I8<>>)) { } else { XEASSERTALWAYS(); // TODO(benvanik): try out hlide's version: - // mov eax, 0x80808080 - // mov al, i.src2 + // mov eax, 0x80808003 + // xor al, i.src2.cvt8() // vmovd xmm0, eax // vpshufb xmm0, i.src1, xmm0 // vmovd i.dest.reg().cvt32(), xmm0 @@ -4430,6 +4434,7 @@ EMITTER(EXTRACT_I16, MATCH(I, V128<>, I8<>>)) { // TODO(benvanik): try out hlide's version: // xor eax, eax // mov al, i.src2 // eax = [i, 0, 0, 0] + // xor eax, 0x80800203 // imul eax, eax, 0x00000202 // [i*2, i*2, 0, 0] supposedly that 0<= i < 8 // add eax,0x80800100 // [i*2+0b00, i*2+0b01, 0x80, 0x80] // vmovd xmm0, eax @@ -4454,7 +4459,7 @@ EMITTER(EXTRACT_I32, MATCH(I, V128<>, I8<>>)) { // xor eax, eax // mov al, i.src2 // eax = [i, 0, 0, 0] // imul eax, eax, 0x04040404 // [i*4, i*4, i*4, i*4] supposedly that 0<= i < 4 - // add eax,0x03020100 // [i*4+0b00, i*4+0b01, i*4+0b10, i*4+0b11] + // xor/add eax, 0x00010203 // [i*4+0b00, i*4+0b01, i*4+0b10, i*4+0b11] // vmovd xmm0, eax // vpshufb xmm0, i.src1, xmm0 // vmovd i.dest.reg().cvt32(), xmm0 diff --git a/src/alloy/compiler/passes/constant_propagation_pass.cc b/src/alloy/compiler/passes/constant_propagation_pass.cc index f8430c509..140d0bf9c 100644 --- a/src/alloy/compiler/passes/constant_propagation_pass.cc +++ b/src/alloy/compiler/passes/constant_propagation_pass.cc @@ -43,6 +43,14 @@ int ConstantPropagationPass::Run(HIRBuilder* builder) { // v1 = add 1000, 1000 // store_context +200, 2000 // A DCE run after this should clean up any of the values no longer needed. + // + // Special care needs to be taken with paired instructions. For example, + // DID_CARRY needs to be set as a constant: + // v1 = sub.2 20, 1 + // v2 = did_carry v1 + // should become: + // v1 = 19 + // v2 = 0 Block* block = builder->first_block(); while (block) { @@ -252,19 +260,41 @@ int ConstantPropagationPass::Run(HIRBuilder* builder) { } break; + case OPCODE_DID_CARRY: + XEASSERT(!i->src1.value->IsConstant()); + break; + case OPCODE_DID_OVERFLOW: + XEASSERT(!i->src1.value->IsConstant()); + break; + case OPCODE_DID_SATURATE: + XEASSERT(!i->src1.value->IsConstant()); + break; + case OPCODE_ADD: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { v->set_from(i->src1.value); - v->Add(i->src2.value); + bool did_carry = v->Add(i->src2.value); + bool propagate_carry = !!(i->flags & ARITHMETIC_SET_CARRY); i->Remove(); + + // If carry is set find the DID_CARRY and fix it. + if (propagate_carry) { + PropagateCarry(v, did_carry); + } } break; - // TODO(benvanik): ADD_CARRY + // TODO(benvanik): ADD_CARRY (w/ ARITHMETIC_SET_CARRY) case OPCODE_SUB: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { v->set_from(i->src1.value); - v->Sub(i->src2.value); + bool did_carry = v->Sub(i->src2.value); + bool propagate_carry = !!(i->flags & ARITHMETIC_SET_CARRY); i->Remove(); + + // If carry is set find the DID_CARRY and fix it. + if (propagate_carry) { + PropagateCarry(v, did_carry); + } } break; case OPCODE_MUL: @@ -393,3 +423,16 @@ int ConstantPropagationPass::Run(HIRBuilder* builder) { return 0; } + +void ConstantPropagationPass::PropagateCarry(hir::Value* v, bool did_carry) { + auto next = v->use_head; + while (next) { + auto use = next; + next = use->next; + if (use->instr->opcode == &OPCODE_DID_CARRY_info) { + // Replace carry value. + use->instr->dest->set_constant(did_carry ? 1 : 0); + use->instr->Remove(); + } + } +} diff --git a/src/alloy/compiler/passes/constant_propagation_pass.h b/src/alloy/compiler/passes/constant_propagation_pass.h index ce705522b..2220394ad 100644 --- a/src/alloy/compiler/passes/constant_propagation_pass.h +++ b/src/alloy/compiler/passes/constant_propagation_pass.h @@ -26,6 +26,7 @@ public: virtual int Run(hir::HIRBuilder* builder); private: + void PropagateCarry(hir::Value* v, bool did_carry); }; diff --git a/src/alloy/hir/value.cc b/src/alloy/hir/value.cc index 10fc62cad..0f723e943 100644 --- a/src/alloy/hir/value.cc +++ b/src/alloy/hir/value.cc @@ -187,19 +187,26 @@ void Value::Round(RoundMode round_mode) { XEASSERTALWAYS(); } -void Value::Add(Value* other) { +bool Value::Add(Value* other) { + #define CHECK_DID_CARRY(v1, v2) (((uint64_t)v2) > ~((uint64_t)v1)) + #define ADD_DID_CARRY(a, b) CHECK_DID_CARRY(a, b) XEASSERT(type == other->type); + bool did_carry = false; switch (type) { case INT8_TYPE: + did_carry = ADD_DID_CARRY(constant.i8, other->constant.i8); constant.i8 += other->constant.i8; break; case INT16_TYPE: + did_carry = ADD_DID_CARRY(constant.i16, other->constant.i16); constant.i16 += other->constant.i16; break; case INT32_TYPE: + did_carry = ADD_DID_CARRY(constant.i32, other->constant.i32); constant.i32 += other->constant.i32; break; case INT64_TYPE: + did_carry = ADD_DID_CARRY(constant.i64, other->constant.i64); constant.i64 += other->constant.i64; break; case FLOAT32_TYPE: @@ -212,21 +219,28 @@ void Value::Add(Value* other) { XEASSERTALWAYS(); break; } + return did_carry; } -void Value::Sub(Value* other) { +bool Value::Sub(Value* other) { + #define SUB_DID_CARRY(a, b) (b > a) XEASSERT(type == other->type); + bool did_carry = false; switch (type) { case INT8_TYPE: + did_carry = SUB_DID_CARRY(constant.i8, other->constant.i8); constant.i8 -= other->constant.i8; break; case INT16_TYPE: + did_carry = SUB_DID_CARRY(constant.i16, other->constant.i16); constant.i16 -= other->constant.i16; break; case INT32_TYPE: + did_carry = SUB_DID_CARRY(constant.i32, other->constant.i32); constant.i32 -= other->constant.i32; break; case INT64_TYPE: + did_carry = SUB_DID_CARRY(constant.i64, other->constant.i64); constant.i64 -= other->constant.i64; break; case FLOAT32_TYPE: @@ -239,6 +253,7 @@ void Value::Sub(Value* other) { XEASSERTALWAYS(); break; } + return did_carry; } void Value::Mul(Value* other) { diff --git a/src/alloy/hir/value.h b/src/alloy/hir/value.h index 9a1f668f5..3c4e82619 100644 --- a/src/alloy/hir/value.h +++ b/src/alloy/hir/value.h @@ -375,8 +375,8 @@ public: void Truncate(TypeName target_type); void Convert(TypeName target_type, RoundMode round_mode); void Round(RoundMode round_mode); - void Add(Value* other); - void Sub(Value* other); + bool Add(Value* other); + bool Sub(Value* other); void Mul(Value* other); void Div(Value* other); static void MulAdd(Value* dest, Value* value1, Value* value2, Value* value3);