diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas index 08d953a74f..bec967a1ed 100644 --- a/compiler/x86/aasmcpu.pas +++ b/compiler/x86/aasmcpu.pas @@ -306,7 +306,14 @@ interface procedure changeopsize(siz:topsize); function GetString:string; - procedure CheckNonCommutativeOpcodes; + + { This is a workaround for the GAS non commutative fpu instruction braindamage. + Early versions of the UnixWare assembler had a bug where some fpu instructions + were reversed and GAS still keeps this "feature" for compatibility. + for details: http://sourceware.org/binutils/docs/as/i386_002dBugs.html#i386_002dBugs + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=372528 + http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax#Caveats } + function FixNonCommutativeOpcodes: tasmop; private FOperandOrder : TOperandOrder; procedure init(_size : topsize); { this need to be called by all constructor } @@ -961,8 +968,10 @@ implementation end; - procedure taicpu.CheckNonCommutativeOpcodes; + function taicpu.FixNonCommutativeOpcodes: tasmop; begin + result:=opcode; + { we need ATT order } SetOperandOrder(op_att); @@ -981,21 +990,21 @@ implementation (ops=0) then begin if opcode=A_FSUBR then - opcode:=A_FSUB + result:=A_FSUB else if opcode=A_FSUB then - opcode:=A_FSUBR + result:=A_FSUBR else if opcode=A_FDIVR then - opcode:=A_FDIV + result:=A_FDIV else if opcode=A_FDIV then - opcode:=A_FDIVR + result:=A_FDIVR else if opcode=A_FSUBRP then - opcode:=A_FSUBP + result:=A_FSUBP else if opcode=A_FSUBP then - opcode:=A_FSUBRP + result:=A_FSUBRP else if opcode=A_FDIVRP then - opcode:=A_FDIVP + result:=A_FDIVP else if opcode=A_FDIVP then - opcode:=A_FDIVRP; + result:=A_FDIVRP; end; if ( (ops=1) and @@ -1005,13 +1014,13 @@ implementation ) then begin if opcode=A_FSUBRP then - opcode:=A_FSUBP + result:=A_FSUBP else if opcode=A_FSUBP then - opcode:=A_FSUBRP + result:=A_FSUBRP else if opcode=A_FDIVRP then - opcode:=A_FDIVP + result:=A_FDIVP else if opcode=A_FDIVP then - opcode:=A_FDIVRP; + result:=A_FDIVRP; end; end; diff --git a/compiler/x86/agx86nsm.pas b/compiler/x86/agx86nsm.pas index feba676918..f76f642f9b 100644 --- a/compiler/x86/agx86nsm.pas +++ b/compiler/x86/agx86nsm.pas @@ -537,6 +537,7 @@ interface {$ifdef cpuextended} e : extended; {$endif cpuextended} + fixed_opcode: TAsmOp; begin if not assigned(p) then exit; @@ -884,12 +885,12 @@ interface ait_instruction : begin - taicpu(hp).CheckNonCommutativeOpcodes; + fixed_opcode:=taicpu(hp).FixNonCommutativeOpcodes; { We need intel order, no At&t } taicpu(hp).SetOperandOrder(op_intel); s:=''; - if ((taicpu(hp).opcode=A_FADDP) or - (taicpu(hp).opcode=A_FMULP)) + if ((fixed_opcode=A_FADDP) or + (fixed_opcode=A_FMULP)) and (taicpu(hp).ops=0) then begin taicpu(hp).allocate_oper(2); @@ -898,7 +899,7 @@ interface taicpu(hp).oper[1]^.typ:=top_reg; taicpu(hp).oper[1]^.reg:=NR_ST; end; - if taicpu(hp).opcode=A_FWAIT then + if fixed_opcode=A_FWAIT then AsmWriteln(#9#9'DB'#9'09bh') else begin @@ -906,18 +907,18 @@ interface word prefix to get selectors to be pushed in 2 bytes PM } if (taicpu(hp).opsize=S_W) and - ((taicpu(hp).opcode=A_PUSH) or - (taicpu(hp).opcode=A_POP)) and + ((fixed_opcode=A_PUSH) or + (fixed_opcode=A_POP)) and (taicpu(hp).oper[0]^.typ=top_reg) and (is_segment_reg(taicpu(hp).oper[0]^.reg)) then AsmWriteln(#9#9'DB'#9'066h'); - AsmWrite(#9#9+std_op2str[taicpu(hp).opcode]+cond2str[taicpu(hp).condition]); + AsmWrite(#9#9+std_op2str[fixed_opcode]+cond2str[taicpu(hp).condition]); if taicpu(hp).ops<>0 then begin - if is_calljmp(taicpu(hp).opcode) then + if is_calljmp(fixed_opcode) then begin AsmWrite(#9); - WriteOper_jmp(taicpu(hp).oper[0]^,taicpu(hp).opcode); + WriteOper_jmp(taicpu(hp).oper[0]^,fixed_opcode); end else begin @@ -927,7 +928,7 @@ interface AsmWrite(#9) else AsmWrite(','); - WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,taicpu(hp).opcode,taicpu(hp).ops,(i=2)); + WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,fixed_opcode,taicpu(hp).ops,(i=2)); end; end; end;