computeRegisterProperties(Subtarget->getRegisterInfo());
setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
+ setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
setOperationAction(ISD::JumpTable, MVTPtr, Custom);
for (auto T : {MVT::f32, MVT::f64}) {
return SDValue();
case ISD::GlobalAddress:
return LowerGlobalAddress(Op, DAG);
+ case ISD::ExternalSymbol:
+ return LowerExternalSymbol(Op, DAG);
case ISD::JumpTable:
return LowerJumpTable(Op, DAG);
case ISD::BR_JT:
DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT));
}
+SDValue WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
+ SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ const auto *ES = cast<ExternalSymbolSDNode>(Op);
+ EVT VT = Op.getValueType();
+ assert(ES->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
+ return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
+ DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
+}
+
SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
SelectionDAG &DAG) const {
// There's no need for a Wrapper node because we always incorporate a jump
[(set F64:$res, fpimm:$imm)],
"f64.const\t$res, $imm">;
-def : Pat<(i32 (WebAssemblywrapper tglobaladdr :$dst)),
- (CONST_I32 tglobaladdr :$dst)>;
+def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$dst)),
+ (CONST_I32 tglobaladdr:$dst)>;
+def : Pat<(i32 (WebAssemblywrapper texternalsym:$dst)),
+ (CONST_I32 texternalsym:$dst)>;
def JUMP_TABLE : I<(outs I32:$dst), (ins tjumptable_op:$addr),
[(set I32:$dst, (WebAssemblywrapper tjumptable:$addr))],
return Printer.getSymbol(MO.getGlobal());
}
+MCSymbol *
+WebAssemblyMCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
+ return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
+}
+
MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
MCSymbol *Sym) const {
case MachineOperand::MO_GlobalAddress:
MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
break;
+ case MachineOperand::MO_ExternalSymbol:
+ MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
+ break;
}
OutMI.addOperand(MCOp);
MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const;
MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const;
+ MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const;
};
}
ret i32 %a
}
+; CHECK-LABEL: call_memcpy:
+; CHECK-NEXT: .param i32, i32, i32{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.const $push0=, memcpy{{$}}
+; CHECK-NEXT: call_indirect $pop0, $0, $1, $2{{$}}
+; CHECK-NEXT: return $0{{$}}
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1)
+define i8* @call_memcpy(i8* %p, i8* nocapture readonly %q, i32 %n) {
+ tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
+ ret i8* %p
+}
+
; CHECK: .type g,@object
; CHECK: .align 2{{$}}
; CHECK-NEXT: g: