1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 20:23:11 +01:00

[Sparc] Add long double (f128) instructions to sparc backend.

llvm-svn: 189198
This commit is contained in:
Venkatraman Govindaraju 2013-08-25 18:30:06 +00:00
parent 1d08468931
commit a3fc2b00cc
6 changed files with 277 additions and 1 deletions

View File

@ -30,6 +30,10 @@ def FeatureVIS
: SubtargetFeature<"vis", "IsVIS", "true",
"Enable UltraSPARC Visual Instruction Set extensions">;
def FeatureHardQuad
: SubtargetFeature<"hard-quad-float", "HasHardQuad", "true",
"Enable quad-word floating point instructions">;
//===----------------------------------------------------------------------===//
// Register File, Calling Conv, Instruction Descriptions
//===----------------------------------------------------------------------===//

View File

@ -1257,15 +1257,21 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
addRegisterClass(MVT::i32, &SP::IntRegsRegClass);
addRegisterClass(MVT::f32, &SP::FPRegsRegClass);
addRegisterClass(MVT::f64, &SP::DFPRegsRegClass);
addRegisterClass(MVT::f128, &SP::QFPRegsRegClass);
if (Subtarget->is64Bit())
addRegisterClass(MVT::i64, &SP::I64RegsRegClass);
// Turn FP extload into load/fextend
setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand);
setLoadExtAction(ISD::EXTLOAD, MVT::f64, Expand);
// Sparc doesn't have i1 sign extending load
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
// Turn FP truncstore into trunc + store.
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
setTruncStoreAction(MVT::f128, MVT::f32, Expand);
setTruncStoreAction(MVT::f128, MVT::f64, Expand);
// Custom legalize GlobalAddress nodes into LO/HI parts.
setOperationAction(ISD::GlobalAddress, getPointerTy(), Custom);
@ -1299,9 +1305,12 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
setOperationAction(ISD::SELECT, MVT::i32, Expand);
setOperationAction(ISD::SELECT, MVT::f32, Expand);
setOperationAction(ISD::SELECT, MVT::f64, Expand);
setOperationAction(ISD::SELECT, MVT::f128, Expand);
setOperationAction(ISD::SETCC, MVT::i32, Expand);
setOperationAction(ISD::SETCC, MVT::f32, Expand);
setOperationAction(ISD::SETCC, MVT::f64, Expand);
setOperationAction(ISD::SETCC, MVT::f128, Expand);
// Sparc doesn't have BRCOND either, it has BR_CC.
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
@ -1310,10 +1319,12 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
setOperationAction(ISD::BR_CC, MVT::f32, Custom);
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
setOperationAction(ISD::BR_CC, MVT::f128, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f128, Custom);
if (Subtarget->is64Bit()) {
setOperationAction(ISD::BITCAST, MVT::f64, Expand);
@ -1334,6 +1345,11 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
setOperationAction(ISD::FABS, MVT::f64, Custom);
}
setOperationAction(ISD::FSIN , MVT::f128, Expand);
setOperationAction(ISD::FCOS , MVT::f128, Expand);
setOperationAction(ISD::FSINCOS, MVT::f128, Expand);
setOperationAction(ISD::FREM , MVT::f128, Expand);
setOperationAction(ISD::FMA , MVT::f128, Expand);
setOperationAction(ISD::FSIN , MVT::f64, Expand);
setOperationAction(ISD::FCOS , MVT::f64, Expand);
setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
@ -1352,8 +1368,10 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
setOperationAction(ISD::ROTL , MVT::i32, Expand);
setOperationAction(ISD::ROTR , MVT::i32, Expand);
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
setOperationAction(ISD::FCOPYSIGN, MVT::f128, Expand);
setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
setOperationAction(ISD::FPOW , MVT::f128, Expand);
setOperationAction(ISD::FPOW , MVT::f64, Expand);
setOperationAction(ISD::FPOW , MVT::f32, Expand);
@ -1387,6 +1405,31 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
if (Subtarget->isV9())
setOperationAction(ISD::CTPOP, MVT::i32, Legal);
if (Subtarget->isV9() && Subtarget->hasHardQuad()) {
setOperationAction(ISD::LOAD, MVT::f128, Legal);
setOperationAction(ISD::STORE, MVT::f128, Legal);
} else {
setOperationAction(ISD::LOAD, MVT::f128, Custom);
setOperationAction(ISD::STORE, MVT::f128, Custom);
}
if (Subtarget->hasHardQuad()) {
setOperationAction(ISD::FADD, MVT::f128, Legal);
setOperationAction(ISD::FSUB, MVT::f128, Legal);
setOperationAction(ISD::FMUL, MVT::f128, Legal);
setOperationAction(ISD::FDIV, MVT::f128, Legal);
setOperationAction(ISD::FSQRT, MVT::f128, Legal);
setOperationAction(ISD::FP_EXTEND, MVT::f128, Legal);
setOperationAction(ISD::FP_ROUND, MVT::f64, Legal);
if (Subtarget->isV9()) {
setOperationAction(ISD::FNEG, MVT::f128, Legal);
setOperationAction(ISD::FABS, MVT::f128, Legal);
} else {
setOperationAction(ISD::FNEG, MVT::f128, Custom);
setOperationAction(ISD::FABS, MVT::f128, Custom);
}
}
setMinFunctionAlignment(2);
computeRegisterProperties();
@ -1800,6 +1843,94 @@ static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG)
return DstReg64;
}
// Lower a f128 load into two f64 loads.
static SDValue LowerF128Load(SDValue Op, SelectionDAG &DAG)
{
SDLoc dl(Op);
LoadSDNode *LdNode = dyn_cast<LoadSDNode>(Op.getNode());
assert(LdNode && LdNode->getOffset().getOpcode() == ISD::UNDEF
&& "Unexpected node type");
SDValue Hi64 = DAG.getLoad(MVT::f64,
dl,
LdNode->getChain(),
LdNode->getBasePtr(),
LdNode->getPointerInfo(),
false, false, false, 8);
EVT addrVT = LdNode->getBasePtr().getValueType();
SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT,
LdNode->getBasePtr(),
DAG.getConstant(8, addrVT));
SDValue Lo64 = DAG.getLoad(MVT::f64,
dl,
LdNode->getChain(),
LoPtr,
LdNode->getPointerInfo(),
false, false, false, 8);
SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, MVT::i32);
SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, MVT::i32);
SDNode *InFP128 = DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
dl, MVT::f128);
InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl,
MVT::f128,
SDValue(InFP128, 0),
Hi64,
SubRegEven);
InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl,
MVT::f128,
SDValue(InFP128, 0),
Lo64,
SubRegOdd);
SDValue OutChains[2] = { SDValue(Hi64.getNode(), 1),
SDValue(Lo64.getNode(), 1) };
SDValue OutChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
&OutChains[0], 2);
SDValue Ops[2] = {SDValue(InFP128,0), OutChain};
return DAG.getMergeValues(Ops, 2, dl);
}
// Lower a f128 store into two f64 stores.
static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) {
SDLoc dl(Op);
StoreSDNode *StNode = dyn_cast<StoreSDNode>(Op.getNode());
assert(StNode && StNode->getOffset().getOpcode() == ISD::UNDEF
&& "Unexpected node type");
SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, MVT::i32);
SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, MVT::i32);
SDNode *Hi64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG,
dl,
MVT::f64,
StNode->getValue(),
SubRegEven);
SDNode *Lo64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG,
dl,
MVT::f64,
StNode->getValue(),
SubRegOdd);
SDValue OutChains[2];
OutChains[0] = DAG.getStore(StNode->getChain(),
dl,
SDValue(Hi64, 0),
StNode->getBasePtr(),
MachinePointerInfo(),
false, false, 8);
EVT addrVT = StNode->getBasePtr().getValueType();
SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT,
StNode->getBasePtr(),
DAG.getConstant(8, addrVT));
OutChains[1] = DAG.getStore(StNode->getChain(),
dl,
SDValue(Lo64, 0),
LoPtr,
MachinePointerInfo(),
false, false, 8);
return DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
&OutChains[0], 2);
}
SDValue SparcTargetLowering::
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
@ -1822,6 +1953,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::VASTART: return LowerVASTART(Op, DAG, *this);
case ISD::VAARG: return LowerVAARG(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
case ISD::LOAD: return LowerF128Load(Op, DAG);
case ISD::STORE: return LowerF128Store(Op, DAG);
}
}

View File

@ -39,6 +39,10 @@ def HasNoV9 : Predicate<"!Subtarget.isV9()">;
// HasVIS - This is true when the target processor has VIS extensions.
def HasVIS : Predicate<"Subtarget.isVIS()">;
// HasHardQuad - This is true when the target processor supports quad floating
// point instructions.
def HasHardQuad : Predicate<"Subtarget.hasHardQuad()">;
// UseDeprecatedInsts - This predicate is true when the target processor is a
// V8, or when it is V9 but the V8 deprecated instructions are efficient enough
// to use when appropriate. In either of these cases, the instruction selector
@ -354,6 +358,16 @@ def LDDFri : F3_2<3, 0b100011,
(outs DFPRegs:$dst), (ins MEMri:$addr),
"ldd [$addr], $dst",
[(set f64:$dst, (load ADDRri:$addr))]>;
def LDQFrr : F3_1<3, 0b100010,
(outs QFPRegs:$dst), (ins MEMrr:$addr),
"ldq [$addr], $dst",
[(set f128:$dst, (load ADDRrr:$addr))]>,
Requires<[HasV9, HasHardQuad]>;
def LDQFri : F3_2<3, 0b100010,
(outs QFPRegs:$dst), (ins MEMri:$addr),
"ldq [$addr], $dst",
[(set f128:$dst, (load ADDRri:$addr))]>,
Requires<[HasV9, HasHardQuad]>;
// Section B.4 - Store Integer Instructions, p. 95
def STBrr : F3_1<3, 0b000101,
@ -398,6 +412,16 @@ def STDFri : F3_2<3, 0b100111,
(outs), (ins MEMri:$addr, DFPRegs:$src),
"std $src, [$addr]",
[(store f64:$src, ADDRri:$addr)]>;
def STQFrr : F3_1<3, 0b100110,
(outs), (ins MEMrr:$addr, QFPRegs:$src),
"stq $src, [$addr]",
[(store f128:$src, ADDRrr:$addr)]>,
Requires<[HasV9, HasHardQuad]>;
def STQFri : F3_2<3, 0b100110,
(outs), (ins MEMri:$addr, QFPRegs:$src),
"stq $src, [$addr]",
[(store f128:$src, ADDRri:$addr)]>,
Requires<[HasV9, HasHardQuad]>;
// Section B.9 - SETHI Instruction, p. 104
def SETHIi: F2_1<0b100,
@ -599,6 +623,11 @@ def FITOD : F3_3<2, 0b110100, 0b011001000,
(outs DFPRegs:$dst), (ins FPRegs:$src),
"fitod $src, $dst",
[(set DFPRegs:$dst, (SPitof FPRegs:$src))]>;
def FITOQ : F3_3<2, 0b110100, 0b011001100,
(outs QFPRegs:$dst), (ins FPRegs:$src),
"fitoq $src, $dst",
[(set QFPRegs:$dst, (SPitof FPRegs:$src))]>,
Requires<[HasHardQuad]>;
// Convert Floating-point to Integer Instructions, p. 142
def FSTOI : F3_3<2, 0b110100, 0b011010001,
@ -609,16 +638,41 @@ def FDTOI : F3_3<2, 0b110100, 0b011010010,
(outs FPRegs:$dst), (ins DFPRegs:$src),
"fdtoi $src, $dst",
[(set FPRegs:$dst, (SPftoi DFPRegs:$src))]>;
def FQTOI : F3_3<2, 0b110100, 0b011010011,
(outs FPRegs:$dst), (ins QFPRegs:$src),
"fqtoi $src, $dst",
[(set FPRegs:$dst, (SPftoi QFPRegs:$src))]>,
Requires<[HasHardQuad]>;
// Convert between Floating-point Formats Instructions, p. 143
def FSTOD : F3_3<2, 0b110100, 0b011001001,
(outs DFPRegs:$dst), (ins FPRegs:$src),
"fstod $src, $dst",
[(set f64:$dst, (fextend f32:$src))]>;
def FSTOQ : F3_3<2, 0b110100, 0b011001101,
(outs QFPRegs:$dst), (ins FPRegs:$src),
"fstoq $src, $dst",
[(set f128:$dst, (fextend f32:$src))]>,
Requires<[HasHardQuad]>;
def FDTOS : F3_3<2, 0b110100, 0b011000110,
(outs FPRegs:$dst), (ins DFPRegs:$src),
"fdtos $src, $dst",
[(set f32:$dst, (fround f64:$src))]>;
def FDTOQ : F3_3<2, 0b110100, 0b01101110,
(outs QFPRegs:$dst), (ins DFPRegs:$src),
"fdtoq $src, $dst",
[(set f128:$dst, (fextend f64:$src))]>,
Requires<[HasHardQuad]>;
def FQTOS : F3_3<2, 0b110100, 0b011000111,
(outs FPRegs:$dst), (ins QFPRegs:$src),
"fqtos $src, $dst",
[(set f32:$dst, (fround f128:$src))]>,
Requires<[HasHardQuad]>;
def FQTOD : F3_3<2, 0b110100, 0b011001011,
(outs DFPRegs:$dst), (ins QFPRegs:$src),
"fqtod $src, $dst",
[(set f64:$dst, (fround f128:$src))]>,
Requires<[HasHardQuad]>;
// Floating-point Move Instructions, p. 144
def FMOVS : F3_3<2, 0b110100, 0b000000001,
@ -643,6 +697,11 @@ def FSQRTD : F3_3<2, 0b110100, 0b000101010,
(outs DFPRegs:$dst), (ins DFPRegs:$src),
"fsqrtd $src, $dst",
[(set f64:$dst, (fsqrt f64:$src))]>;
def FSQRTQ : F3_3<2, 0b110100, 0b000101011,
(outs QFPRegs:$dst), (ins QFPRegs:$src),
"fsqrtq $src, $dst",
[(set f128:$dst, (fsqrt f128:$src))]>,
Requires<[HasHardQuad]>;
@ -655,6 +714,12 @@ def FADDD : F3_3<2, 0b110100, 0b001000010,
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"faddd $src1, $src2, $dst",
[(set f64:$dst, (fadd f64:$src1, f64:$src2))]>;
def FADDQ : F3_3<2, 0b110100, 0b001000011,
(outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
"faddq $src1, $src2, $dst",
[(set f128:$dst, (fadd f128:$src1, f128:$src2))]>,
Requires<[HasHardQuad]>;
def FSUBS : F3_3<2, 0b110100, 0b001000101,
(outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
"fsubs $src1, $src2, $dst",
@ -663,6 +728,12 @@ def FSUBD : F3_3<2, 0b110100, 0b001000110,
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"fsubd $src1, $src2, $dst",
[(set f64:$dst, (fsub f64:$src1, f64:$src2))]>;
def FSUBQ : F3_3<2, 0b110100, 0b001000111,
(outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
"fsubq $src1, $src2, $dst",
[(set f128:$dst, (fsub f128:$src1, f128:$src2))]>,
Requires<[HasHardQuad]>;
// Floating-point Multiply and Divide Instructions, p. 147
def FMULS : F3_3<2, 0b110100, 0b001001001,
@ -673,11 +744,24 @@ def FMULD : F3_3<2, 0b110100, 0b001001010,
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"fmuld $src1, $src2, $dst",
[(set f64:$dst, (fmul f64:$src1, f64:$src2))]>;
def FMULQ : F3_3<2, 0b110100, 0b001001011,
(outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
"fmulq $src1, $src2, $dst",
[(set f128:$dst, (fmul f128:$src1, f128:$src2))]>,
Requires<[HasHardQuad]>;
def FSMULD : F3_3<2, 0b110100, 0b001101001,
(outs DFPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
"fsmuld $src1, $src2, $dst",
[(set f64:$dst, (fmul (fextend f32:$src1),
(fextend f32:$src2)))]>;
def FDMULQ : F3_3<2, 0b110100, 0b001101110,
(outs QFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"fdmulq $src1, $src2, $dst",
[(set f128:$dst, (fmul (fextend f64:$src1),
(fextend f64:$src2)))]>,
Requires<[HasHardQuad]>;
def FDIVS : F3_3<2, 0b110100, 0b001001101,
(outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
"fdivs $src1, $src2, $dst",
@ -686,6 +770,11 @@ def FDIVD : F3_3<2, 0b110100, 0b001001110,
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"fdivd $src1, $src2, $dst",
[(set f64:$dst, (fdiv f64:$src1, f64:$src2))]>;
def FDIVQ : F3_3<2, 0b110100, 0b001001111,
(outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
"fdivq $src1, $src2, $dst",
[(set f128:$dst, (fdiv f128:$src1, f128:$src2))]>,
Requires<[HasHardQuad]>;
// Floating-point Compare Instructions, p. 148
// Note: the 2nd template arg is different for these guys.
@ -701,6 +790,11 @@ let Defs = [FCC] in {
(outs), (ins DFPRegs:$src1, DFPRegs:$src2),
"fcmpd $src1, $src2\n\tnop",
[(SPcmpfcc f64:$src1, f64:$src2)]>;
def FCMPQ : F3_3<2, 0b110101, 0b001010011,
(outs), (ins QFPRegs:$src1, QFPRegs:$src2),
"fcmpq $src1, $src2\n\tnop",
[(SPcmpfcc f128:$src1, f128:$src2)]>,
Requires<[HasHardQuad]>;
}
//===----------------------------------------------------------------------===//
@ -762,14 +856,28 @@ let Predicates = [HasV9] in {
def FMOVD : F3_3<2, 0b110100, 0b000000010,
(outs DFPRegs:$dst), (ins DFPRegs:$src),
"fmovd $src, $dst", []>;
def FMOVQ : F3_3<2, 0b110100, 0b000000011,
(outs QFPRegs:$dst), (ins QFPRegs:$src),
"fmovq $src, $dst", []>,
Requires<[HasHardQuad]>;
def FNEGD : F3_3<2, 0b110100, 0b000000110,
(outs DFPRegs:$dst), (ins DFPRegs:$src),
"fnegd $src, $dst",
[(set f64:$dst, (fneg f64:$src))]>;
def FNEGQ : F3_3<2, 0b110100, 0b000000111,
(outs QFPRegs:$dst), (ins QFPRegs:$src),
"fnegq $src, $dst",
[(set f128:$dst, (fneg f128:$src))]>,
Requires<[HasHardQuad]>;
def FABSD : F3_3<2, 0b110100, 0b000001010,
(outs DFPRegs:$dst), (ins DFPRegs:$src),
"fabsd $src, $dst",
[(set f64:$dst, (fabs f64:$src))]>;
def FABSQ : F3_3<2, 0b110100, 0b000001011,
(outs QFPRegs:$dst), (ins QFPRegs:$src),
"fabsq $src, $dst",
[(set f128:$dst, (fabs f128:$src))]>,
Requires<[HasHardQuad]>;
}
// POPCrr - This does a ctpop of a 64-bit register. As such, we have to clear

View File

@ -30,7 +30,8 @@ SparcSubtarget::SparcSubtarget(const std::string &TT, const std::string &CPU,
IsV9(false),
V8DeprecatedInsts(false),
IsVIS(false),
Is64Bit(is64Bit) {
Is64Bit(is64Bit),
HasHardQuad(false) {
// Determine default and user specified characteristics
std::string CPUName = CPU;

View File

@ -29,6 +29,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo {
bool V8DeprecatedInsts;
bool IsVIS;
bool Is64Bit;
bool HasHardQuad;
public:
SparcSubtarget(const std::string &TT, const std::string &CPU,
@ -37,6 +38,7 @@ public:
bool isV9() const { return IsV9; }
bool isVIS() const { return IsVIS; }
bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; }
bool hasHardQuad() const { return HasHardQuad; }
/// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen.

View File

@ -0,0 +1,27 @@
; RUN: llc < %s -march=sparc -mattr=hard-quad-float | FileCheck %s
; CHECK-LABEL: f128_ops
; CHECK: ldd
; CHECK: ldd
; CHECK: ldd
; CHECK: ldd
; CHECK: faddq [[R0:.+]], [[R1:.+]], [[R2:.+]]
; CHECK: fsubq [[R2]], [[R3:.+]], [[R4:.+]]
; CHECK: fmulq [[R4]], [[R5:.+]], [[R6:.+]]
; CHECK: fdivq [[R6]], [[R2]]
; CHECK: std
; CHECK: std
define void @f128_ops(fp128* noalias sret %scalar.result, fp128* byval %a, fp128* byval %b, fp128* byval %c, fp128* byval %d) {
entry:
%0 = load fp128* %a, align 8
%1 = load fp128* %b, align 8
%2 = load fp128* %c, align 8
%3 = load fp128* %d, align 8
%4 = fadd fp128 %0, %1
%5 = fsub fp128 %4, %2
%6 = fmul fp128 %5, %3
%7 = fdiv fp128 %6, %4
store fp128 %7, fp128* %scalar.result, align 8
ret void
}