diff --git a/src/cowbe/archpdp11.cow.ng b/src/cowbe/archpdp11.cow.ng index 3281e847..3f1c40fc 100644 --- a/src/cowbe/archpdp11.cow.ng +++ b/src/cowbe/archpdp11.cow.ng @@ -115,6 +115,27 @@ EndError(); end sub; + sub E_symref_cache_read(sym: [Symbol], off: Size, dst: RegId) is + var cache := FindFirst(RegCacheFindValue(sym, off)); + if cache != 0 then + E_reg(cache); + RegCacheCopy(cache, dst); + return; + end if; + E_symref(sym, off); + end sub; + + sub E_symref_cache_write(sym: [Symbol], off: Size) is + var cache := RegCacheFindAddress(sym, off); + if cache != 0 then + E_openp(); + E_reg(FindFirst(cache)); + E_closep(); + return; + end if; + E_symref(sym, off); + end sub; + sub E_insn(insn: string, reg: RegId) is E_tab(); E(insn); @@ -135,6 +156,20 @@ E_i32(value); end sub; + sub E_ash32(value: int8, reg: RegId) is + E_tab(); + E("ASH"); + if (reg & REGCLASS_R32) != 0 then + E_b8('C'); + end if; + E_tab(); + E_const(); + E_i8(value); + E_comma(); + E_reg(reg); + E_nl(); + end sub; + sub E_push(src: RegId) is E_insn16("MOV"); E_reg(src); @@ -169,9 +204,16 @@ E_comma(); E_reg(dest); E_nl(); + RegCacheCopy(hireg(src), dest); end sub; sub E_loadaddr(reg: RegId, sym: [Symbol], off: Size) is + var cache := RegCacheFindAddress(sym, off) & reg; + if cache != 0 then + # The value is already in the desired register. + return; + end if; + R_flush(reg); E_mov(reg); E_const(); @@ -179,6 +221,7 @@ E_comma(); E_reg(reg); E_nl(); + RegCacheLeavesAddress(reg, sym, off); end sub; sub E_loadsubref(reg: RegId, subr: [Subroutine]) is @@ -191,39 +234,33 @@ E_nl(); end sub; - sub E_load(reg: RegId, sym: [Symbol], off: Size, byte: uint8) is + sub E_load(reg: RegId, sym: [Symbol], off: Size) is var cache := RegCacheFindValue(sym, off); if (cache & reg) != 0 then # The value is already in the desired register. return; - elseif cache != 0 then - E_move(FindFirst(cache), reg); - RegCacheLeavesValue(hireg(reg), sym, off); - return; end if; R_flush(reg); - if byte == 1 then - E_mov(loreg(reg)); - else - E_mov(reg); - end if; - E_symref(sym, off); + E_mov(reg); + E_symref_cache_read(sym, off, reg); E_comma(); E_reg(reg); E_nl(); - RegCacheLeavesValue(hireg(reg), sym, off); + RegCacheLeavesValue(reg, sym, off); end sub; sub E_loadix(reg: RegId, ptr: RegId, off: Arith) is R_flush(reg); E_mov(reg); if off != 0 then + E_b8('0'); E_i32(off); end if; E_openp(); E_reg(ptr); - E("), "); + E_closep(); + E_comma(); E_reg(reg); E_nl(); end sub; @@ -240,19 +277,19 @@ E_nl(); end sub; - sub E_store(reg: RegId, sym: [Symbol], off: Size, byte: uint8) is + sub E_store(reg: RegId, sym: [Symbol], off: Size) is RegCacheFlushValue(sym, off); E_mov(reg); E_reg(reg); E_comma(); - E_symref(sym, off); + E_symref_cache_write(sym, off); E_nl(); RegCacheLeavesValue(reg, sym, off); end sub; sub E_storepop(sym: [Symbol], off: Size) is E("\tMOV\t(SP)+, "); - E_symref(sym, off); + E_symref_cache_write(sym, off); E_nl(); end sub; @@ -261,6 +298,7 @@ E_reg(reg); E_comma(); if off != 0 then + E_b8('0'); E_i32(off); end if; E_openp(); @@ -279,6 +317,12 @@ end sub; sub E_storeixc(value: Arith, ptr: RegId, off: Arith, byte: uint8) is + # flush any values loaded from ptr + var q := RegCacheGet(ptr); + if q != nil and q.state == CACHE_SLOT_WSREF then + R_flush(RegCacheFind(CACHE_SLOT_VALUE, q.subr, q.wsid, q.number as Size)); + end if; + if value == 0 then if byte == 0 then E_insn16("CLR"); @@ -300,6 +344,7 @@ E_comma(); end if; if off != 0 then + E_b8('0'); E_i32(off); end if; E_openp(); @@ -456,6 +501,42 @@ E_alu2("BIS", src, dest); end sub; + sub E_alu2ii(insn: string, reg: RegId, ptr: RegId, sym: [Symbol], off: Size) is + R_flush(reg); + E_insn(insn, reg); + E_symref(sym, off); + E_openp(); + E_reg(ptr); + E_closep(); + E_comma(); + E_reg(reg); + E_nl(); + end sub; + + sub E_alu2s(insn: string, reg: RegId, sym: [Symbol], off: Size) is + R_flush(reg); + E_insn16(insn); + E_symref_cache_read(sym, off, 0); + E_comma(); + E_reg(reg); + E_nl(); + end sub; + + sub E_alu2x(insn: string, reg: RegId, index: RegId, off: Arith) is + R_flush(reg); + E_insn16(insn); + if off != 0 then + E_b8('0'); + E_i32(off); + end if; + E_openp(); + E_reg(index); + E_closep(); + E_comma(); + E_reg(reg); + E_nl(); + end sub; + sub E_alu2i_noflush(insn: string, value: Arith, dest: RegId) is E_insn(insn, dest); E_imm(value); @@ -470,6 +551,16 @@ end sub; sub E_addi(value: Arith, dest: RegId) is + var q := RegCacheGet(dest); + if q != nil and (q.state == CACHE_SLOT_VALUE or q.state == CACHE_SLOT_WSREF) then # XXX may be slower + R_flush(dest); + case value is + when 2: E("\ttst\t("); E_reg(dest); E(")+\n"); return; + when 4: E("\tcmp\t("); E_reg(dest); E(")+, ("); E_reg(dest); E(")+\n"); return; + when -2: E("\ttst\t-("); E_reg(dest); E(")\n"); return; + when -4: E("\tcmp\t-("); E_reg(dest); E("), -("); E_reg(dest); E(")\n"); return; + end case; + end if; case value is when 1: E_inc(dest); when -1: E_dec(dest); @@ -549,6 +640,21 @@ E_nl(); end sub; + # cannot use sym.width -- sym might be an array + sub E_cmpis(value: Arith, sym: [Symbol], off: Size, byte: RegId) is + if value == 0 then + E_insn("TST", byte); + else + E_insn("CMP", byte); + end if; + E_symref_cache_read(sym, off, 0); + if value != 0 then + E_comma(); + E_imm(value); + end if; + E_nl(); + end sub; + sub E_cmpi4(value: Arith, reg: RegId) is var label := AllocPLabel(); E_cmpi(value >> 16, hireg(reg)); @@ -592,15 +698,12 @@ return; # asl,asl is faster than ash on some impls elseif value > 1 then - E_insn16("ash"); - E_b8('#'); - E_u8(value); - E_comma(); + E_ash32(value as int8, reg); else E_insn("asl", reg); + E_reg(reg); + E_nl(); end if; - E_reg(reg); - E_nl(); end sub; sub E_sar1(amount: RegId, value: RegId) is @@ -669,15 +772,37 @@ # ASH is signed, and this is unsigned sub E_shri(value: uint8, reg: RegId) is + var word := reg & REGCLASS_R16; + R_flush(reg); + + # use ROL when it's faster + if (word == 0 and value >= 4) or (word != 0 and value >= 12) then + var mask: Arith := 255; + if word != 0 then + value := value - 8; + end if; + mask := mask >> value; + value := 9 - value; + while value > 0 loop + E_insn("ROL", reg); + E_reg(reg); + E_nl(); + value := value - 1; + end loop; + E_andi(mask, reg); + return; + end if + if value > 7 then E_clr(loreg(reg)); + if word == 0 then return; end if; E_insn16("SWAB"); E_reg(reg); E_nl(); value := value - 8; end if; - if value > 0 then +# if value != 0 then while value > 0 loop E_insn16("CLC"); E_nl(); @@ -686,7 +811,7 @@ E_nl(); value := value - 1; end loop; - end if; +# end if; end sub; sub E_shl4(value: RegId, reg: RegId) is @@ -700,22 +825,26 @@ sub E_shli4(value: uint8, reg: RegId) is R_flush(reg); - E_insn16("ASHC"); - E_b8('#'); - E_u8(value); - E_comma(); - E_reg(reg); - E_nl(); + if value > 15 then + E_move(loreg(reg), hireg(reg)); + E_clr(loreg(reg)); + value := value - 16; + reg := hireg(reg); + end if; + if value > 0 then + E_ash32(value as int8, reg); + end if; end sub; sub E_sari(value: uint8, reg: RegId) is R_flush(reg); - E_insn16("ASH"); - E("#-"); - E_u8(value); - E_comma(); - E_reg(reg); - E_nl(); + if (value == 1) then + E_insn("ASR", reg); + E_reg(reg); + E_nl(); + else + E_ash32(-value as int8, reg); + end if; end sub; sub E_shr4(amount: RegId, value: RegId) is @@ -757,12 +886,15 @@ sub E_sari4(value: uint8, reg: RegId) is R_flush(reg); - E_insn16("ASHC"); - E("#-"); - E_u8(value); - E_comma(); - E_reg(reg); - E_nl(); + if value > 15 then + E_move(hireg(reg), loreg(reg)); + E_sxt(hireg(reg)); + value := value - 16; + reg := loreg(reg); + end if; + if value > 0 then + E_ash32(-value as int8, reg); + end if; end sub; sub E_shri4(value: uint8, reg: RegId) is @@ -771,7 +903,6 @@ E_move(hireg(reg), loreg(reg)); E_clr(hireg(reg)); else - R_flush(REG_R5); E_move(hireg(reg), REG_R5); E_sari4(value, reg); E_shri(value, REG_R5); @@ -788,6 +919,15 @@ E_nl(); end sub; + sub E_muli(src: RegId, dest: Arith) is + R_flush(src); + E_insn16("MUL"); + E_imm(dest); + E_comma(); + E_reg(src); + E_nl(); + end sub; + # via 2.11bsd lib/libc/pdp/crt/lmul.s sub E_mul4(dest: RegId, lhs: RegId, rhs: RegId) is var r3: RegId := loreg(rhs); @@ -878,6 +1018,12 @@ # sym is R8, dest is R16 sub E_loadext(reg: RegId, sym: [Symbol], off: Size, sext: uint8) is + var cache := RegCacheFindValue(sym, off) & REGCLASS_R8; + if cache != 0 then + E_ext(FindFirst(cache), reg, sext); + return; + end if; + R_flush(reg); if sext == 0 then E_clr(reg); @@ -979,7 +1125,6 @@ regclass r8 := r0b|r1b|r2b|r3b|r4b|r5b; regclass r16 := r0|r1|r2|r3|r4|r5; regclass r32 := r0r1|r2r3|r4r5; -regclass r8n0 := r1b|r2b|r3b|r4b|r5b; regclass r8n01 := r2b|r3b|r4b|r5b; regclass r16n0 := r1|r2|r3|r4|r5; regclass r16n01 := r2|r3|r4|r5; @@ -1065,14 +1210,14 @@ gen STARTSUB() uses all pop_return_address(); E_pop(REG_R0); end if; - E_store(REG_R0B, param as [Symbol], 0, 1); + E_store(REG_R0B, param as [Symbol], 0); when 2: if count != lastparam then pop_return_address(); E_storepop(param as [Symbol], 0); else - E_store(REG_R0, param as [Symbol], 0, 0); + E_store(REG_R0, param as [Symbol], 0); end if; when 4: @@ -1081,8 +1226,8 @@ gen STARTSUB() uses all E_storepop(param as [Symbol], 2); E_storepop(param as [Symbol], 0); else - E_store(REG_R0, param as [Symbol], 2, 0); - E_store(REG_R1, param as [Symbol], 0, 0); + E_store(REG_R0, param as [Symbol], 2); + E_store(REG_R1, param as [Symbol], 0); end if; end case; end loop; @@ -1116,22 +1261,22 @@ gen ENDSUB() uses all case param.width is when 1: - E_load(REG_R0B, param as [Symbol], 0, 1); + E_load(REG_R0B, param as [Symbol], 0); if count != (params-1) then push_return_address(); E_push(REG_R0); end if; when 2: - E_load(REG_R0, param as [Symbol], 0, 0); + E_load(REG_R0, param as [Symbol], 0); if count != (params-1) then push_return_address(); E_push(REG_R0); end if; when 4: - E_load(REG_R1, param as [Symbol], 0, 0); - E_load(REG_R0, param as [Symbol], 2, 0); + E_load(REG_R1, param as [Symbol], 0); + E_load(REG_R0, param as [Symbol], 2); if count != (params-1) then push_return_address(); E_push4(REG_R0R1); @@ -1186,8 +1331,8 @@ gen param := ARG1(param, r8:lhs) { E_push($lhs); } gen param := ARG2(param, r16:lhs) { E_push($lhs); } gen param := ARG4(param, r32:lhs) { E_push4($lhs); } -gen param := ARG1(param, DEREF1(ADDRESS():a)) { E_insn16("movb"); E_symref(&$a.sym, $a.off); E(", -(SP)\n"); } -gen param := ARG2(param, DEREF2(ADDRESS():a)) { E_insn16("mov"); E_symref(&$a.sym, $a.off); E(", -(SP)\n"); } +gen param := ARG1(param, DEREF1(ADDRESS(&sym is not_cached):a)) { E_insn16("movb"); E_symref(&$a.sym, $a.off); E(", -(SP)\n"); } +gen param := ARG2(param, DEREF2(ADDRESS(&sym is not_cached):a)) { E_insn16("mov"); E_symref(&$a.sym, $a.off); E(", -(SP)\n"); } gen r0b := POPARG1(remaining==0); gen r0 := POPARG2(remaining==0); @@ -1244,20 +1389,24 @@ gen r32 := DEREF4(r16:rhs) gen r8 := DEREF1(ADD2(r16:rhs, CONSTANT():c)) { E_loadix($$, $rhs, $c.value); } gen r16 := DEREF2(ADD2(r16:rhs, CONSTANT():c)) { E_loadix($$, $rhs, $c.value); } -gen r8 := DEREF1(ADD2(ADDRESS():a, CONSTANT():c)) { E_load($$, &$a.sym, $a.off + $c.value as uint16, 1); } +gen r8 := DEREF1(ADD2(ADDRESS():a, CONSTANT():c)) { E_load($$, &$a.sym, $a.off + $c.value as uint16); } +gen r16 := DEREF2(ADD2(ADDRESS():a, CONSTANT():c)) { E_load($$, &$a.sym, $a.off + $c.value as uint16); } gen r8 := DEREF1(ADD2(ADDRESS():a, r16:rhs)) { E_loadii($$, $rhs, &$a.sym, $a.off as uint16, 1); } -gen r16 := DEREF2(ADD2(ADDRESS():a, CONSTANT():c)) { E_load($$, &$a.sym, $a.off + $c.value as uint16, 0); } gen r16 := DEREF2(ADD2(ADDRESS():a, r16:rhs)) { E_loadii($$, $rhs, &$a.sym, $a.off as uint16, 0); } -gen r8 := DEREF1(ADDRESS():a) { E_load($$, &$a.sym, $a.off, 1); } +gen r8 := DEREF1(ADDRESS():a) { E_load($$, &$a.sym, $a.off); } gen r16 := CAST12(DEREF1(ADDRESS():a)):c { E_loadext($$, &$a.sym, $a.off, $c.sext); } -gen r16 := DEREF2(ADDRESS():a) { E_load($$, &$a.sym, $a.off, 0); } +gen r16 := DEREF2(ADDRESS():a) { E_load($$, &$a.sym, $a.off); } + +gen r16 := CAST42(DEREF4(ADDRESS():a)) { E_load($$, &$a.sym, $a.off); } +gen r16 := CAST42(DEREF4(ADD2(r16:rhs, CONSTANT():c))) { E_loadix($$, $rhs, $c.value); } +gen r16 := CAST42(DEREF4(ADD2(ADDRESS():a, CONSTANT():c))) { E_load($$, &$a.sym, $c.value as uint16 + $a.off); } gen r32 := DEREF4(ADDRESS():a) { - E_load(loreg($$), &$a.sym, $a.off, 0); - E_load(hireg($$), &$a.sym, $a.off + 2, 0); + E_load(loreg($$), &$a.sym, $a.off); + E_load(hireg($$), &$a.sym, $a.off + 2); } gen r32 := DEREF4(ADD2(r16:rhs, CONSTANT():c)) { @@ -1271,36 +1420,35 @@ gen r32 := DEREF4(ADD2(r16:rhs, CONSTANT():c)) } gen r32 := DEREF4(ADD2(ADDRESS():a, CONSTANT():c)) { - E_load(loreg($$), &$a.sym, $c.value as uint16 + $a.off, 0); - E_load(hireg($$), &$a.sym, $c.value as uint16 + $a.off + 2, 0); + E_load(loreg($$), &$a.sym, $c.value as uint16 + $a.off); + E_load(hireg($$), &$a.sym, $c.value as uint16 + $a.off + 2); } gen r16 := ADDRESS():a { E_loadaddr($$, &$a.sym, $a.off); } gen r16 := SUBREF():a { E_loadsubref($$, $a.subr); } -// XXX otherwise regs get destroyed? -//n r8 := CAST21(DEREF2(ADDRESS():a)):c { E_load($$, &$a.sym, $a.off, 0); } -//n r16 := CAST12(DEREF1(r16:rhs)):c { E_loadix($$, $rhs, 0); E_ext($$, $$, $c.sext); } // XXX bad code in FCBExt -//n r32 := CAST24(DEREF2(ADDRESS():a)):c { E_load(loreg($$), &$a.sym, $a.off, 0); if ($c.sext == 0) then E_clr(hireg($$)); else E_sxt(hireg($$)); end if; } -//n r32 := CAST14(DEREF1(ADDRESS():a)):c { E_load(loreg($$), &$a.sym, $a.off, 1); E_ext(loreg($$), loreg($$), $c.sext); if ($c.sext != 0) then E_sxt(hireg($$)); else E_clr(hireg($$)); end if; } - // --- Stores --------------------------------------------------------------- gen STORE1(CONSTANT():v, DEREF1(r16:rhs)) { E_storeixc($v.value, $rhs, 0, 1); } gen STORE1(CONSTANT():v, DEREF1(ADD2(r16:rhs, CONSTANT():c))) { E_storeixc($v.value, $rhs, $c.value, 1); } gen STORE1(r8:lhs, DEREF1(r16:rhs)) { E_storeix($lhs, $rhs, 0); } -gen STORE1(r8:lhs, DEREF1(ADDRESS():a)) { E_store($lhs, &$a.sym, $a.off, 1); } +gen STORE1(r8:lhs, DEREF1(ADDRESS():a)) { E_store($lhs, &$a.sym, $a.off); } gen STORE1(r8:lhs, DEREF1(ADD2(r16:rhs, CONSTANT():c))) { E_storeix($lhs, $rhs, $c.value); } gen STORE1(r8:lhs, DEREF1(ADD2(ADDRESS():a, r16:rhs))) { E_storeii($lhs, $rhs, &$a.sym, $a.off as uint16, 1); } gen STORE2(CONSTANT():v, DEREF2(r16:rhs)) { E_storeixc($v.value, $rhs, 0, 0); } gen STORE2(CONSTANT():v, DEREF2(ADD2(r16:rhs, CONSTANT():c))) { E_storeixc($v.value, $rhs, $c.value, 0); } gen STORE2(r16:lhs, DEREF2(r16:rhs)) { E_storeix($lhs, $rhs, 0); } -gen STORE2(r16:lhs, DEREF2(ADDRESS():a)) { E_store($lhs, &$a.sym, $a.off, 0); } +gen STORE2(r16:lhs, DEREF2(ADDRESS():a)) { E_store($lhs, &$a.sym, $a.off); } gen STORE2(r16:lhs, DEREF2(ADD2(r16:rhs, CONSTANT():c))) { E_storeix($lhs, $rhs, $c.value); } gen STORE2(r16:lhs, DEREF2(ADD2(ADDRESS():a, r16:rhs))) { E_storeii($lhs, $rhs, &$a.sym, $a.off as uint16, 0); } +gen STORE4(CONSTANT():v, DEREF4(r16:rhs)) +{ + E_storeixc($v.value & 0xffff, $rhs, 0, 0); + E_storeixc($v.value >> 16, $rhs, 2, 0); +} gen STORE4(r32:val, DEREF4(r16:rhs)) { E_storeix(loreg($val), $rhs, 0); @@ -1308,12 +1456,22 @@ gen STORE4(r32:val, DEREF4(r16:rhs)) } gen STORE4(r32:val, DEREF4(ADDRESS():a)) { - E_store(loreg($val), &$a.sym, $a.off, 0); - E_store(hireg($val), &$a.sym, $a.off + 2, 0); + E_store(loreg($val), &$a.sym, $a.off); + E_store(hireg($val), &$a.sym, $a.off + 2); } // --- Maths ---------------------------------------------------------------- +%{ + sub is_not_cached(a: [Symbol]): (result: uint8) is + if RegCacheFindValue(a, 0) != 0 then + result := 0; + else + result := 1; + end if; + end sub; +%} + gen r8 := NEG1($$) { E_neg($$); } gen r16 := NEG2($$) { E_neg($$); } gen r32 := NEG4($$) @@ -1333,6 +1491,11 @@ gen r8 := ADD1($$, CONSTANT():c) { E_addi($c.value, $$); } gen r16 := ADD2($$, r16:rhs) { E_add($rhs, $$); } gen r16 := ADD2($$, CONSTANT():c) { E_addi($c.value, $$); } +gen r16 := ADD2($$, DEREF2(r16:rhs)) { E_alu2x("ADD", $$, $rhs, 0); } +gen r16 := ADD2($$, DEREF2(ADD2(r16:rhs, CONSTANT():c))) { E_alu2x("ADD", $$, $rhs, $c.value); } +gen r16 := ADD2($$, DEREF2(ADD2(ADDRESS():a, r16:rhs))) { E_alu2ii("ADD", $$, $rhs, &$a.sym, $a.off as uint16); } +gen r16 := ADD2($$, DEREF2(ADDRESS():a)) { E_alu2s("ADD", $$, &$a.sym, $a.off); } // FIXME off==0? + gen r32 := ADD4($$, r32:rhs) { E_add(loreg($rhs), loreg($$)); @@ -1346,6 +1509,11 @@ gen r8 := SUB1($$, CONSTANT():c) { E_subi($c.value, $$); } gen r16 := SUB2($$, r16:rhs) { E_sub($rhs, $$); } gen r16 := SUB2($$, CONSTANT():c) { E_subi($c.value, $$); } +gen r16 := SUB2($$, DEREF2(r16:rhs)) { E_alu2x("SUB", $$, $rhs, 0); } +gen r16 := SUB2($$, DEREF2(ADD2(r16:rhs, CONSTANT():c))) { E_alu2x("SUB", $$, $rhs, $c.value); } +gen r16 := SUB2($$, DEREF2(ADD2(ADDRESS():a, r16:rhs))) { E_alu2ii("SUB", $$, $rhs, &$a.sym, $a.off as uint16); } +gen r16 := SUB2($$, DEREF2(ADDRESS():a)) { E_alu2s("SUB", $$, &$a.sym, $a.off); } + gen r32 := SUB4($$, r32:rhs) { E_sub(loreg($rhs), loreg($$)); @@ -1376,6 +1544,11 @@ gen r8 := OR1($$, CONSTANT():c) { E_ori($c.value, $$); } gen r16 := OR2($$, r16:rhs) { E_or($rhs, $$); } gen r16 := OR2($$, CONSTANT():c) { E_ori($c.value, $$); } +gen r16 := OR2($$, DEREF2(r16:rhs)) { E_alu2x("BIS", $$, $rhs, 0); } +gen r16 := OR2($$, DEREF2(ADD2(r16:rhs, CONSTANT():c))) { E_alu2x("BIS", $$, $rhs, $c.value); } +gen r16 := OR2($$, DEREF2(ADD2(ADDRESS():a, r16:rhs))) { E_alu2ii("BIS", $$, $rhs, &$a.sym, $a.off as uint16); } +gen r16 := OR2($$, DEREF2(ADDRESS():a)) { E_alu2s("BIS", $$, &$a.sym, $a.off); } + gen r32 := OR4($$, r32:rhs) { E_or(loreg($rhs), loreg($$)); @@ -1400,6 +1573,7 @@ gen r32 := EOR4($$, r32:rhs) // always use odd registers for 8- and 16-bit multiply and division gen r1b|r3b|r5b := MUL1($$, r8:rhs) { E_mul($$, $rhs); } // fixme sxtb? gen r1|r3|r5 := MUL2($$, r16:rhs) { E_mul($$, $rhs); } +gen r1|r3|r5 := MUL2($$, CONSTANT():c) { E_muli($$, $c.value); } gen r4r5 := MUL4(r2r3:lhs, r0r1:rhs) { E_mul4($$, $lhs, $rhs); } gen r0b := DIVU1(r1b, r8n01:rhs) { E_uxtb($rhs); E_uxtb(REG_R1); E_clr(REG_R0); E_div($rhs, REG_R0); } @@ -1416,23 +1590,27 @@ gen r1 := REMS2(r1, r16n01:rhs) { E_tst(REG_R1); E_sxt(REG_R0); gen r2r3 := DIVS4(r2r3, r0r1) uses r4r5 { E_callhelper("_divrems4"); } gen r4r5 := REMS4(r2r3, r0r1) { E_callhelper("_divrems4"); } -gen r8n0 := LSHIFT1($$:lhs, r0b:rhs) { E_shl($rhs, $lhs); } +// shift amounts are uint8 + +gen r8 := LSHIFT1($$:lhs, r8:rhs) { E_shl($rhs, $lhs); } gen r8 := LSHIFT1($$:lhs, CONSTANT():c) { E_shli($c.value as uint8, $lhs); } -gen r16n0 := LSHIFT2($$:lhs, r0b:rhs) { E_shl($rhs, $lhs); } +gen r16 := LSHIFT2($$:lhs, r8:rhs) cost -10 { E_shl($rhs, $lhs); } +gen r16n0 := LSHIFT2($$:lhs, r0b:rhs) cost -5 { E_shl($rhs, $lhs); } // or deadlock gen r16 := LSHIFT2($$:lhs, CONSTANT():c) { E_shli($c.value as uint8, $lhs); } gen r32n0 := LSHIFT4($$:lhs, r0b:rhs) { E_shl4($rhs, $lhs); } gen r32 := LSHIFT4($$:lhs, CONSTANT():c) { E_shli4($c.value as uint8, $lhs); } -gen r8n0 := RSHIFTU1($$:lhs, r0b:rhs) { E_shr1($rhs, $lhs); } +gen r8 := RSHIFTU1($$:lhs, r8:rhs) { E_shr1($rhs, $lhs); } gen r8 := RSHIFTU1($$:lhs, CONSTANT():c) { E_shri($c.value as uint8, $lhs); } gen r1|r2|r3|r4 := RSHIFTU2($$:lhs, r0b:rhs) uses r5 { E_shr($rhs, $lhs); } gen r16 := RSHIFTU2($$:lhs, CONSTANT():c) { E_shri($c.value as uint8, $lhs); } gen r2r3 := RSHIFTU4($$:lhs, r0b:rhs) uses r4r5 { E_shr4($rhs, $lhs); } gen r0r1|r2r3 := RSHIFTU4($$:lhs, CONSTANT():c) uses r5 { E_shri4($c.value as uint8, $lhs); } -gen r8n0 := RSHIFTS1($$:lhs, r0b:rhs) { E_sar1($rhs, $lhs); } +gen r8 := RSHIFTS1($$:lhs, r8:rhs) { E_sar1($rhs, $lhs); } gen r8 := RSHIFTS1($$:lhs, CONSTANT():c) { E_sari($c.value as uint8, $lhs); } -gen r16n0 := RSHIFTS2($$:lhs, r0b:rhs) { E_sar($rhs, $lhs); } +gen r16 := RSHIFTS2($$:lhs, r8:rhs) cost -10 { E_sar($rhs, $lhs); } +gen r16n0 := RSHIFTS2($$:lhs, r0b:rhs) cost -5 { E_sar($rhs, $lhs); } gen r16 := RSHIFTS2($$:lhs, CONSTANT():c) { E_sari($c.value as uint8, $lhs); } gen r32n0 := RSHIFTS4($$:lhs, r0b:rhs) { E_sar4($rhs, $lhs); } gen r32 := RSHIFTS4($$:lhs, CONSTANT():c) { E_sari4($c.value as uint8, $lhs); } @@ -1450,7 +1628,7 @@ gen r32 := RSHIFTS4($$:lhs, CONSTANT():c) { E_sari4($c.value as uint8, $l end sub; sub CmpJumpsJe(node: [Node]) is - CmpJumps("BEQ", "BNE", node); + CmpJumps("BEQ", "BNE", node); # Z=1; Z=0 end sub; # unsigned @@ -1458,11 +1636,21 @@ gen r32 := RSHIFTS4($$:lhs, CONSTANT():c) { E_sari4($c.value as uint8, $l CmpJumps("BLO", "BHIS", node); # C=1; C=0 end sub; + # unsigned + sub CmpJumpsJa(node: [Node]) is + CmpJumps("BHI", "BLOS", node); # C=0&&Z=0; C=1||Z=1 + end sub; + # signed sub CmpJumpsJl(node: [Node]) is CmpJumps("BLT", "BGE", node); # N^V=1; N^V=0 end sub; + # signed + sub CmpJumpsJg(node: [Node]) is + CmpJumps("BGT", "BLE", node); # (N^V)=0&&Z=0; (N^V)=1||Z=1 + end sub; + sub beqc(node: [Node], lhs: Arith, rhs: Arith) is var label := node.beq.falselabel; if lhs == rhs then @@ -1484,6 +1672,7 @@ gen BEQ1(AND1(r8:lhs, CONSTANT(value!=0):c), CONSTANT(value==0)):b E_alu2i("BIT", $c.value, $lhs); CmpJumpsJe(self.n[0]); } +gen BEQ1(DEREF1(ADDRESS():a), CONSTANT():c) uses all { E_cmpis($c.value, &$a.sym, $a.off, REGCLASS_R8); CmpJumpsJe(self.n[0]); } gen BEQ2(r16:lhs, r16:rhs):b uses all { E_cmp($lhs, $rhs); CmpJumpsJe(self.n[0]); } gen BEQ2(r16:lhs, CONSTANT():c):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJe(self.n[0]); } @@ -1493,20 +1682,34 @@ gen BEQ2(AND2(r16:lhs, CONSTANT(value!=0):c), CONSTANT(value==0)):b E_alu2i("BIT", $c.value, $lhs); CmpJumpsJe(self.n[0]); } +gen BEQ2(DEREF2(ADDRESS():a), CONSTANT():c) uses all { E_cmpis($c.value, &$a.sym, $a.off, REGCLASS_R16); CmpJumpsJe(self.n[0]); } + gen BEQ4(r32:lhs, r32:rhs):b uses all { E_cmpeq4($lhs, $rhs); CmpJumpsJe(self.n[0]); } -//n BEQ4(r32:lhs, CONSTANT():c):b uses all { E_cmpi4($c.value, $lhs); CmpJumpsJe(self.n[0]); } // XXX deadlock +gen BEQ4(r32:lhs, CONSTANT():c):b uses all { E_cmpi4($c.value, $lhs); CmpJumpsJe(self.n[0]); } gen BLTS1(r8:lhs, r8:rhs):b uses all { E_cmp($lhs, $rhs); CmpJumpsJl(self.n[0]); } gen BLTS1(r8:lhs, CONSTANT():c):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJl(self.n[0]); } +gen BLTS1(CONSTANT():c, r8:lhs):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJg(self.n[0]); } +gen BLTS1(DEREF1(ADDRESS():a), CONSTANT():c) uses all { E_cmpis($c.value, &$a.sym, $a.off, REGCLASS_R8); CmpJumpsJl(self.n[0]); } + gen BLTS2(r16:lhs, r16:rhs):b uses all { E_cmp($lhs, $rhs); CmpJumpsJl(self.n[0]); } gen BLTS2(r16:lhs, CONSTANT():c):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJl(self.n[0]); } +gen BLTS2(CONSTANT():c, r16:lhs):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJg(self.n[0]); } +gen BLTS2(DEREF2(ADDRESS():a), CONSTANT():c) uses all { E_cmpis($c.value, &$a.sym, $a.off, REGCLASS_R16); CmpJumpsJl(self.n[0]); } + gen BLTS4(r32:lhs, r32:rhs):b uses all { E_cmps4($lhs, $rhs); CmpJumpsJl(self.n[0]); } //gen BLTS4(r32:lhs, CONSTANT():c):b { E_cmpi4($c.value, $lhs); CmpJumpsJl(self.n[0]); } gen BLTU1(r8:lhs, r8:rhs):b uses all { E_cmp($lhs, $rhs); CmpJumpsJb(self.n[0]); } gen BLTU1(r8:lhs, CONSTANT():c):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJb(self.n[0]); } +gen BLTU1(CONSTANT():c, r8:lhs):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJa(self.n[0]); } +gen BLTU1(DEREF1(ADDRESS():a), CONSTANT():c) uses all { E_cmpis($c.value, &$a.sym, $a.off, REGCLASS_R8); CmpJumpsJb(self.n[0]); } + gen BLTU2(r16:lhs, r16:rhs):b uses all { E_cmp($lhs, $rhs); CmpJumpsJb(self.n[0]); } gen BLTU2(r16:lhs, CONSTANT():c):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJb(self.n[0]); } +gen BLTU2(CONSTANT():c, r16:lhs):b uses all { E_cmpi($c.value, $lhs); CmpJumpsJa(self.n[0]); } +gen BLTU2(DEREF2(ADDRESS():a), CONSTANT():c) uses all { E_cmpis($c.value, &$a.sym, $a.off, REGCLASS_R16); CmpJumpsJb(self.n[0]); } + gen BLTU4(r32:lhs, r32:rhs):b uses all { E_cmpu4($lhs, $rhs); CmpJumpsJb(self.n[0]); } //gen BLTU4(r32:lhs, CONSTANT():c):b { E_cmpi4($c.value, $lhs); CmpJumpsJb(self.n[0]); } diff --git a/src/cowbe/regcache.coh b/src/cowbe/regcache.coh index 24e307a7..69b3d539 100644 --- a/src/cowbe/regcache.coh +++ b/src/cowbe/regcache.coh @@ -161,3 +161,38 @@ sub RegCacheFindValue(sym: [Symbol], off: Size): (reg: RegId) is end loop; end sub; +sub RegCacheCopy(src: RegId, dst: RegId) is + var p := ®ister_cache[0]; + while p != ®ister_cache[@sizeof register_cache] loop + if (p.state != CACHE_SLOT_EMPTY) and ((src & p.reg) != 0) then + p.reg := p.reg | dst; + end if; + p := @next p; + end loop; +end sub; + +sub RegCacheGet(src: RegId): (q: [CacheSlot]) is + var p := ®ister_cache[0]; + q := nil; + while p != ®ister_cache[@sizeof register_cache] loop + if (p.state != CACHE_SLOT_EMPTY) and ((src & p.reg) != 0) then + q := p; + return; + end if; + p := @next p; + end loop; +end sub; + +sub RegCacheFind(state: uint8, subr: [Subroutine], wsid: uint8, off: Size): (reg: RegId) is + var p := ®ister_cache[0]; + reg := 0; + while p != ®ister_cache[@sizeof register_cache] loop + if (p.state == state) and (p.subr == subr) + and (p.wsid == wsid) and (p.number == (off as Word)) then + reg := p.reg; + return; + end if; + p := @next p; + end loop; +end sub; + diff --git a/tests/pointers.good b/tests/pointers.good index 07428e2b..dd109141 100644 --- a/tests/pointers.good +++ b/tests/pointers.good @@ -3,3 +3,4 @@ p.byte==4: yes direct: yes indirect: yes +minus1: yes diff --git a/tests/pointers.test.cow b/tests/pointers.test.cow index c1d6d456..93fdae61 100644 --- a/tests/pointers.test.cow +++ b/tests/pointers.test.cow @@ -31,6 +31,9 @@ sub IndexTest() is var p := &b; print("indirect"); if p.buffer[p.offset] == 42 then yes(); else no(); end if; + + var pb := &b.buffer[3]; + print("minus1"); if [pb - 1] == 42 then yes(); else no(); end if; end sub; IndexTest(); diff --git a/tests/regcache.good b/tests/regcache.good index aabcd495..8b6aee19 100644 --- a/tests/regcache.good +++ b/tests/regcache.good @@ -3,3 +3,6 @@ regcache1 sub: yes regcache1 or: yes regcache1 xor: yes regcache1 and: yes +regcache1 shl: yes +regcache1 shr: yes +regcache2: yes diff --git a/tests/regcache.test.cow b/tests/regcache.test.cow index f7859bd0..70543015 100644 --- a/tests/regcache.test.cow +++ b/tests/regcache.test.cow @@ -27,5 +27,28 @@ sub cache1() is c := a & b; d := a; print("regcache1 and"); if c == 0 and d == 2 then yes(); else no(); end if; + + c := a << b; + d := a; + print("regcache1 shl"); if c == 4 and d == 2 then yes(); else no(); end if; + + c := a >> b; + d := a; + print("regcache1 shr"); if c == 1 and d == 2 then yes(); else no(); end if; end sub; cache1(); + +# STORE should flush cached pointer value +sub cache2() is + var c: uint8; + var d: uint8; + var p: [uint8] := "ab"; + + c := [p]; + p := p + 1; + d := [p]; + + print("regcache2"); if c == 'a' and d == 'b' then yes(); else no(); end if; +end sub; +cache2(); + diff --git a/tests/shifts-16bit.good b/tests/shifts-16bit.good index f345c0db..7bf7048c 100644 --- a/tests/shifts-16bit.good +++ b/tests/shifts-16bit.good @@ -5,6 +5,7 @@ bug1<<8 == 0x8800: yes big>>zero == 0x8000: yes big>>one == 0x4000: yes big>>two == 0x2000: yes +bug1>>14 == 0x3: yes bug1>>10 == 0x30: yes bug1>>8 == 0xc3: yes mbig>>zero == 0x8000: yes diff --git a/tests/shifts-16bit.test.cow b/tests/shifts-16bit.test.cow index 1668b424..4766ba7e 100644 --- a/tests/shifts-16bit.test.cow +++ b/tests/shifts-16bit.test.cow @@ -23,6 +23,7 @@ sub rshiftu() is print("big>>zero == 0x8000"); if big>>zero == 0x8000 then yes(); else no(); end if; print("big>>one == 0x4000"); if big>>one == 0x4000 then yes(); else no(); end if; print("big>>two == 0x2000"); if big>>two == 0x2000 then yes(); else no(); end if; + print("bug1>>14 == 0x3") ; if bug1>>14 == 0x3 then yes(); else no(); end if; print("bug1>>10 == 0x30"); if bug1>>10 == 0x30 then yes(); else no(); end if; print("bug1>>8 == 0xc3"); if bug1>>8 == 0xc3 then yes(); else no(); end if; end sub; diff --git a/tests/shifts-8bit.good b/tests/shifts-8bit.good index 0cfe22b6..26197c55 100644 --- a/tests/shifts-8bit.good +++ b/tests/shifts-8bit.good @@ -1,10 +1,18 @@ one<>zero == 128: yes onetwoeight>>one == 64: yes onetwoeight>>two == 32: yes +onetwoeight>>ONE == 64: yes +onetwoeight>>TWO == 32: yes mbig>>zero == 0x80: yes mbig>>one == 0xc0: yes mbig>>two == 0xe0: yes +mbig>>ONE == 0xc0: yes +mbig>>TWO == 0xe0: yes diff --git a/tests/shifts-8bit.test.cow b/tests/shifts-8bit.test.cow index 973273d9..742e09b4 100644 --- a/tests/shifts-8bit.test.cow +++ b/tests/shifts-8bit.test.cow @@ -7,11 +7,19 @@ var one: uint8 := 1; var two: uint8 := 2; var onetwoeight: uint8 := 0x80; +const ONE := 1; +const TWO := 2; +const NINE := 9; + sub lshift() is print("one<>zero == 128"); if onetwoeight>>zero == 128 then yes(); else no(); end if; print("onetwoeight>>one == 64"); if onetwoeight>>one == 64 then yes(); else no(); end if; print("onetwoeight>>two == 32"); if onetwoeight>>two == 32 then yes(); else no(); end if; + print("onetwoeight>>ONE == 64"); if onetwoeight>>ONE == 64 then yes(); else no(); end if; + print("onetwoeight>>TWO == 32"); if onetwoeight>>TWO == 32 then yes(); else no(); end if; end sub; rshiftu(); @@ -26,6 +36,8 @@ sub rshifts() is print("mbig>>zero == 0x80"); if mbig>>zero == 0x80 then yes(); else no(); end if; print("mbig>>one == 0xc0"); if mbig>>one == 0xc0 then yes(); else no(); end if; print("mbig>>two == 0xe0"); if mbig>>two == 0xe0 then yes(); else no(); end if; + print("mbig>>ONE == 0xc0"); if mbig>>ONE == 0xc0 then yes(); else no(); end if; + print("mbig>>TWO == 0xe0"); if mbig>>TWO == 0xe0 then yes(); else no(); end if; end sub; rshifts();