mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-10 01:12:43 +02:00
tcginnode.pass_generate_code: use tlhcgobj.g_undefined_ok
Also override the code that uses this for LLVM with a variant that does not need it for LLVM versions that do not support the freeze instruction.
This commit is contained in:
parent
ab581c5c30
commit
29bae2297f
@ -26,9 +26,16 @@ unit nllvmset;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
nset, ncgset;
|
nset, ncgset,
|
||||||
|
symtype,
|
||||||
|
cgbase;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
tllvminnode = class(tcginnode)
|
||||||
|
protected
|
||||||
|
procedure in_reg_const(uopdef: tdef; opsize: tcgsize); override;
|
||||||
|
end;
|
||||||
|
|
||||||
tllvmcasenode = class(tcgcasenode)
|
tllvmcasenode = class(tcgcasenode)
|
||||||
protected
|
protected
|
||||||
procedure genlinearlist(hp: pcaselabel); override;
|
procedure genlinearlist(hp: pcaselabel); override;
|
||||||
@ -37,6 +44,42 @@ interface
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
globals,
|
||||||
|
aasmbase, aasmdata,
|
||||||
|
hlcgobj,
|
||||||
|
llvminfo;
|
||||||
|
|
||||||
|
procedure tllvminnode.in_reg_const(uopdef: tdef; opsize: tcgsize);
|
||||||
|
var
|
||||||
|
hl,hlend: TAsmLabel;
|
||||||
|
begin
|
||||||
|
if not(llvmflag_no_freeze in llvmversion_properties[current_settings.llvmversion]) then
|
||||||
|
begin
|
||||||
|
{ if we have the freeze instruction, we can mark the poison value
|
||||||
|
potentially generated by the shift as "replace with a fixed value
|
||||||
|
if it's poison, we don't care since we'll mask it anyway" }
|
||||||
|
inherited;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
{ don't perform the bit test if the register's value can be >=
|
||||||
|
"number of bits in right.location", because that generates a poison
|
||||||
|
value in LLVM (and even anding it will 0 will keep it a poison value),
|
||||||
|
and calculations using poison as input result in undefined behaviour }
|
||||||
|
current_asmdata.getjumplabel(hl);
|
||||||
|
current_asmdata.getjumplabel(hlend);
|
||||||
|
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,uopdef,OC_AE,
|
||||||
|
right.resultdef.packedbitsize,left.location.register,hl);
|
||||||
|
hlcg.a_bit_test_reg_loc_reg(current_asmdata.CurrAsmList,
|
||||||
|
uopdef,right.resultdef,uopdef,
|
||||||
|
left.location.register,right.location,location.register);
|
||||||
|
hlcg.a_jmp_always(current_asmdata.CurrAsmList,hlend);
|
||||||
|
hlcg.a_label(current_asmdata.CurrAsmList,hl);
|
||||||
|
hlcg.a_load_const_reg(current_asmdata.CurrAsmList,uopdef,0,location.register);
|
||||||
|
hlcg.a_label(current_asmdata.CurrAsmList,hlend);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure tllvmcasenode.genlinearlist(hp: pcaselabel);
|
procedure tllvmcasenode.genlinearlist(hp: pcaselabel);
|
||||||
begin
|
begin
|
||||||
{ genlinearlist constantly updates the case value in the register,
|
{ genlinearlist constantly updates the case value in the register,
|
||||||
@ -48,6 +91,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
cinnode:=tllvminnode;
|
||||||
ccasenode:=tllvmcasenode;
|
ccasenode:=tllvmcasenode;
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ interface
|
|||||||
protected
|
protected
|
||||||
function checkgenjumps(out setparts: Tsetparts; out numparts: byte; out use_small: boolean): boolean; virtual;
|
function checkgenjumps(out setparts: Tsetparts; out numparts: byte; out use_small: boolean): boolean; virtual;
|
||||||
function analizeset(const Aset:Tconstset;out setparts: Tsetparts; out numparts: byte;is_small:boolean):boolean;virtual;
|
function analizeset(const Aset:Tconstset;out setparts: Tsetparts; out numparts: byte;is_small:boolean):boolean;virtual;
|
||||||
|
procedure in_reg_const(uopdef: tdef; opsize: tcgsize);virtual;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
tcgcasenode = class(tcasenode)
|
tcgcasenode = class(tcasenode)
|
||||||
@ -183,6 +184,45 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure tcginnode.in_reg_const(uopdef: tdef; opsize: tcgsize);
|
||||||
|
var
|
||||||
|
hr: tregister;
|
||||||
|
begin
|
||||||
|
{ emit bit test operation -- warning: do not use
|
||||||
|
location_force_reg() to force a set into a register, except
|
||||||
|
to a register of the same size as the set. The reason is
|
||||||
|
that on big endian systems, this would require moving the
|
||||||
|
set to the most significant part of the new register,
|
||||||
|
and location_force_register can't do that (it does not
|
||||||
|
know the type).
|
||||||
|
|
||||||
|
a_bit_test_reg_loc_reg() properly takes into account the
|
||||||
|
size of the set to adjust the register index to test }
|
||||||
|
hlcg.a_bit_test_reg_loc_reg(current_asmdata.CurrAsmList,
|
||||||
|
uopdef, right.resultdef, uopdef,
|
||||||
|
left.location.register, right.location, location.register);
|
||||||
|
|
||||||
|
{ this may have resulted in an undefined value if left.location.register
|
||||||
|
was >= size of right.location, but we'll mask the value to zero below
|
||||||
|
in that case -> okay }
|
||||||
|
hlcg.g_undefined_ok(current_asmdata.CurrAsmList,uopdef,location.register);
|
||||||
|
|
||||||
|
{ now zero the result if left > nr_of_bits_in_right_register }
|
||||||
|
hr := hlcg.getintregister(current_asmdata.CurrAsmList, uopdef);
|
||||||
|
{ if left > tcgsize2size[opsize]*8 then hr := 0 else hr := $ffffffff }
|
||||||
|
{ (left.location.size = location.size at this point) }
|
||||||
|
hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SUB, uopdef,
|
||||||
|
tcgsize2size[opsize]*8, left.location.register, hr);
|
||||||
|
hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SAR, uopdef, (tcgsize2size
|
||||||
|
[opsize]*8)-1, hr);
|
||||||
|
|
||||||
|
|
||||||
|
{ if left > tcgsize2size[opsize]*8-1, then result := 0 else result := result of bit test }
|
||||||
|
hlcg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_AND, uopdef, hr,
|
||||||
|
location.register);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure tcginnode.in_smallset(opdef: tdef; setbase: aint);
|
procedure tcginnode.in_smallset(opdef: tdef; setbase: aint);
|
||||||
begin
|
begin
|
||||||
{ location is always LOC_REGISTER }
|
{ location is always LOC_REGISTER }
|
||||||
@ -445,29 +485,7 @@ implementation
|
|||||||
{ load left in register }
|
{ load left in register }
|
||||||
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,uopdef,true);
|
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,uopdef,true);
|
||||||
register_maybe_adjust_setbase(current_asmdata.CurrAsmList,uopdef,left.location,setbase);
|
register_maybe_adjust_setbase(current_asmdata.CurrAsmList,uopdef,left.location,setbase);
|
||||||
{ emit bit test operation -- warning: do not use
|
in_reg_const(uopdef, opsize);
|
||||||
location_force_reg() to force a set into a register, except
|
|
||||||
to a register of the same size as the set. The reason is
|
|
||||||
that on big endian systems, this would require moving the
|
|
||||||
set to the most significant part of the new register,
|
|
||||||
and location_force_register can't do that (it does not
|
|
||||||
know the type).
|
|
||||||
|
|
||||||
a_bit_test_reg_loc_reg() properly takes into account the
|
|
||||||
size of the set to adjust the register index to test }
|
|
||||||
hlcg.a_bit_test_reg_loc_reg(current_asmdata.CurrAsmList,
|
|
||||||
uopdef,right.resultdef,uopdef,
|
|
||||||
left.location.register,right.location,location.register);
|
|
||||||
|
|
||||||
{ now zero the result if left > nr_of_bits_in_right_register }
|
|
||||||
hr := hlcg.getintregister(current_asmdata.CurrAsmList,uopdef);
|
|
||||||
{ if left > tcgsize2size[opsize]*8 then hr := 0 else hr := $ffffffff }
|
|
||||||
{ (left.location.size = location.size at this point) }
|
|
||||||
hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SUB, uopdef, tcgsize2size[opsize]*8, left.location.register, hr);
|
|
||||||
hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SAR, uopdef, (tcgsize2size[opsize]*8)-1, hr);
|
|
||||||
|
|
||||||
{ if left > tcgsize2size[opsize]*8-1, then result := 0 else result := result of bit test }
|
|
||||||
hlcg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_AND, uopdef, hr, location.register);
|
|
||||||
end { of right.location.loc=LOC_CONSTANT }
|
end { of right.location.loc=LOC_CONSTANT }
|
||||||
{ do search in a normal set which could have >32 elements
|
{ do search in a normal set which could have >32 elements
|
||||||
but also used if the left side contains higher values > 32 }
|
but also used if the left side contains higher values > 32 }
|
||||||
|
Loading…
Reference in New Issue
Block a user