diff --git a/.gitattributes b/.gitattributes index 49ad3d6d41..5d8c6ee142 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14598,6 +14598,7 @@ tests/webtbs/tw2976.pp svneol=native#text/plain tests/webtbs/tw29792.pp svneol=native#text/pascal tests/webtbs/tw2983.pp svneol=native#text/plain tests/webtbs/tw2984.pp svneol=native#text/plain +tests/webtbs/tw29906.pp svneol=native#text/plain tests/webtbs/tw29923.pp svneol=native#text/plain tests/webtbs/tw29930.pp svneol=native#text/plain tests/webtbs/tw2998.pp svneol=native#text/plain diff --git a/compiler/ppcgen/ngppcset.pas b/compiler/ppcgen/ngppcset.pas index ec25b29789..a10a3bc29a 100644 --- a/compiler/ppcgen/ngppcset.pas +++ b/compiler/ppcgen/ngppcset.pas @@ -75,7 +75,6 @@ implementation last : TConstExprInt; indexreg : tregister; href : treference; - mulfactor: longint; procedure genitem(list:TAsmList;t : pcaselabel); var @@ -108,30 +107,28 @@ implementation indexreg:= cg.makeregsize(current_asmdata.CurrAsmList, hregister, OS_INT); { indexreg := hregister; } cg.a_load_reg_reg(current_asmdata.CurrAsmList, def_cgsize(opsize), OS_INT, hregister, indexreg); + { a <= x <= b <-> unsigned(x-a) <= (b-a) } + cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,aint(min_),indexreg); if not(jumptable_no_range) then begin - { use aword(value-min) goto elselabel } - cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,aint(min_),indexreg); - { this trick requires an unsigned comparison in all cases } + { case expr greater than max_ => goto elselabel } cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_A,aint(max_)-aint(min_),indexreg,elselabel); - { already taken into account now } - min_:=0; end; current_asmdata.getjumplabel(table); { create reference, indexreg := indexreg * sizeof(jtentry) (= 4) } - mulfactor:=4; - cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, mulfactor, indexreg); - reference_reset_symbol(href, table, (-aint(min_)) * mulfactor, 4); + cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, 4, indexreg); + reference_reset_symbol(href, table, 0, 4); hregister:=cg.getaddressregister(current_asmdata.CurrAsmList); cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister); reference_reset_base(href,hregister,0,4); href.index:=indexreg; indexreg:=cg.getaddressregister(current_asmdata.CurrAsmList); + { load table entry } cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,indexreg); + { add table base } cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,hregister,indexreg); - + { jump } current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_MTCTR, indexreg)); current_asmdata.CurrAsmList.concat(taicpu.op_none(A_BCTR)); diff --git a/tests/webtbs/tw29906.pp b/tests/webtbs/tw29906.pp new file mode 100644 index 0000000000..c5cac14ac1 --- /dev/null +++ b/tests/webtbs/tw29906.pp @@ -0,0 +1,70 @@ +{$mode objfpc} + +type + tsub = 1..19; + +function test(s: tsub): longint; +begin + { use different number of instructions for several cases so wrongly + calculated jump table offsets are more likely to wreak havoc } + case s of + 1: + result:=1; + 2: + begin + writeln('two'); + result:=2; + end; + 3: + begin + s:=4; + result:=3; + end; + 4: + begin + result:=4; + s:=s*s+result; + end; + 5: + result:=5; + 6: + result:=6; + 7: + begin + s:=s+s*s div s; + result:=7; + end; + 8: + result:=8; + 9: + result:=9; + 10: + result:=10; + 11: + result:=11; + 12: + result:=12; + 13: + result:=13; + 14: + result:=14; + 15: + result:=15; + 16: + result:=16; + 17: + result:=17; + 18: + result:=18; + 19: + result:=19; + end; +end; + +var + i: tsub; +begin + for i:=low(tsub) to high(tsub) do + if test(i)<>i then + halt(i); +end.