mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 08:38:14 +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
|
||||
|
||||
uses
|
||||
nset, ncgset;
|
||||
nset, ncgset,
|
||||
symtype,
|
||||
cgbase;
|
||||
|
||||
type
|
||||
tllvminnode = class(tcginnode)
|
||||
protected
|
||||
procedure in_reg_const(uopdef: tdef; opsize: tcgsize); override;
|
||||
end;
|
||||
|
||||
tllvmcasenode = class(tcgcasenode)
|
||||
protected
|
||||
procedure genlinearlist(hp: pcaselabel); override;
|
||||
@ -37,6 +44,42 @@ interface
|
||||
|
||||
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);
|
||||
begin
|
||||
{ genlinearlist constantly updates the case value in the register,
|
||||
@ -48,6 +91,7 @@ implementation
|
||||
end;
|
||||
|
||||
begin
|
||||
cinnode:=tllvminnode;
|
||||
ccasenode:=tllvmcasenode;
|
||||
end.
|
||||
|
||||
|
@ -51,6 +51,7 @@ interface
|
||||
protected
|
||||
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;
|
||||
procedure in_reg_const(uopdef: tdef; opsize: tcgsize);virtual;
|
||||
end;
|
||||
|
||||
tcgcasenode = class(tcasenode)
|
||||
@ -183,6 +184,45 @@ implementation
|
||||
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);
|
||||
begin
|
||||
{ location is always LOC_REGISTER }
|
||||
@ -445,29 +485,7 @@ implementation
|
||||
{ load left in register }
|
||||
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,uopdef,true);
|
||||
register_maybe_adjust_setbase(current_asmdata.CurrAsmList,uopdef,left.location,setbase);
|
||||
{ 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);
|
||||
|
||||
{ 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);
|
||||
in_reg_const(uopdef, opsize);
|
||||
end { of right.location.loc=LOC_CONSTANT }
|
||||
{ do search in a normal set which could have >32 elements
|
||||
but also used if the left side contains higher values > 32 }
|
||||
|
Loading…
Reference in New Issue
Block a user