Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,12 +662,15 @@ Function *AArch64Arm64ECCallLowering::buildGuestExitThunk(Function *F) {
Function *Thunk = buildExitThunk(F->getFunctionType(), F->getAttributes());
CallInst *GuardCheck = B.CreateCall(
GuardFnType, GuardCheckLoad, {F, Thunk});
Value *GuardCheckDest = B.CreateExtractValue(GuardCheck, 0);
Value *GuardFinalDest = B.CreateExtractValue(GuardCheck, 1);

// Ensure that the first argument is passed in the correct register.
GuardCheck->setCallingConv(CallingConv::CFGuard_Check);

SmallVector<Value *> Args(llvm::make_pointer_range(GuestExit->args()));
CallInst *Call = B.CreateCall(Arm64Ty, GuardCheck, Args);
OperandBundleDef OB("cfguardtarget", GuardFinalDest);
CallInst *Call = B.CreateCall(Arm64Ty, GuardCheckDest, Args, OB);
Call->setTailCallKind(llvm::CallInst::TCK_MustTail);

if (Call->getType()->isVoidTy())
Expand Down Expand Up @@ -767,11 +770,21 @@ void AArch64Arm64ECCallLowering::lowerCall(CallBase *CB) {
CallInst *GuardCheck =
B.CreateCall(GuardFnType, GuardCheckLoad, {CalledOperand, Thunk},
Bundles);
Value *GuardCheckDest = B.CreateExtractValue(GuardCheck, 0);
Value *GuardFinalDest = B.CreateExtractValue(GuardCheck, 1);

// Ensure that the first argument is passed in the correct register.
GuardCheck->setCallingConv(CallingConv::CFGuard_Check);

CB->setCalledOperand(GuardCheck);
// Update the call: set the callee, and add a bundle with the final
// destination,
CB->setCalledOperand(GuardCheckDest);
OperandBundleDef OB("cfguardtarget", GuardFinalDest);
auto *NewCall = CallBase::addOperandBundle(CB, LLVMContext::OB_cfguardtarget,
OB, CB->getIterator());
NewCall->copyMetadata(*CB);
CB->replaceAllUsesWith(NewCall);
CB->eraseFromParent();
}

bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
Expand All @@ -789,7 +802,7 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
I64Ty = Type::getInt64Ty(M->getContext());
VoidTy = Type::getVoidTy(M->getContext());

GuardFnType = FunctionType::get(PtrTy, {PtrTy, PtrTy}, false);
GuardFnType = FunctionType::get(StructType::get(PtrTy, PtrTy), {PtrTy, PtrTy}, false);
DispatchFnType = FunctionType::get(PtrTy, {PtrTy, PtrTy, PtrTy}, false);
GuardFnCFGlobal = M->getOrInsertGlobal("__os_arm64x_check_icall_cfg", PtrTy);
GuardFnGlobal = M->getOrInsertGlobal("__os_arm64x_check_icall", PtrTy);
Expand Down
13 changes: 11 additions & 2 deletions llvm/lib/Target/AArch64/AArch64CallingConvention.td
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,13 @@ def RetCC_AArch64_AAPCS : CallingConv<[
]>;

let Entry = 1 in
def CC_AArch64_Win64PCS : CallingConv<AArch64_Common>;
def CC_AArch64_Win64PCS : CallingConv<!listconcat(
[
// 'CFGuardTarget' is used for Arm64EC; it passes its parameter in X9.
CCIfCFGuardTarget<CCAssignToReg<[X9]>>
],
AArch64_Common)
>;

// Vararg functions on windows pass floats in integer registers
let Entry = 1 in
Expand All @@ -177,6 +183,9 @@ def CC_AArch64_Win64_VarArg : CallingConv<[
// a stack layout compatible with the x64 calling convention.
let Entry = 1 in
def CC_AArch64_Arm64EC_VarArg : CallingConv<[
// 'CFGuardTarget' is used for Arm64EC; it passes its parameter in X9.
CCIfCFGuardTarget<CCAssignToReg<[X9]>>,

CCIfNest<CCAssignToReg<[X15]>>,

// Convert small floating-point values to integer.
Expand Down Expand Up @@ -345,7 +354,7 @@ def CC_AArch64_Arm64EC_CFGuard_Check : CallingConv<[

let Entry = 1 in
def RetCC_AArch64_Arm64EC_CFGuard_Check : CallingConv<[
CCIfType<[i64], CCAssignToReg<[X11]>>
CCIfType<[i64], CCAssignToReg<[X11, X9]>>
]>;


Expand Down
50 changes: 50 additions & 0 deletions llvm/test/CodeGen/AArch64/arm64ec-indirect-call.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
; RUN: llc -mtriple=arm64ec-pc-windows-msvc < %s | FileCheck %s

define void @simple(ptr %g) {
; CHECK-LABEL: "#simple":
; CHECK: str x30, [sp, #-16]!
; CHECK-NEXT: .seh_save_reg_x x30, 16
; CHECK-NEXT: .seh_endprologue
; CHECK-NEXT: adrp x8, __os_arm64x_check_icall
; CHECK-NEXT: adrp x10, $iexit_thunk$cdecl$v$v
; CHECK-NEXT: add x10, x10, :lo12:$iexit_thunk$cdecl$v$v
; CHECK-NEXT: ldr x8, [x8, :lo12:__os_arm64x_check_icall]
; CHECK-NEXT: mov x11, x0
; CHECK-NEXT: blr x8
; CHECK-NEXT: blr x11
; CHECK-NEXT: .seh_startepilogue
; CHECK-NEXT: ldr x30, [sp], #16
; CHECK-NEXT: .seh_save_reg_x x30, 16
; CHECK-NEXT: .seh_endepilogue
; CHECK-NEXT: ret

entry:
call void %g()
ret void
}

; Make sure the check for the security cookie doesn't use x9.
define void @stackguard(ptr %g) sspreq {
; CHECK-LABEL: "#stackguard":
; CHECK: adrp x8, __os_arm64x_check_icall
; CHECK-NEXT: ldr x8, [x8, :lo12:__os_arm64x_check_icall]
; CHECK-NEXT: blr x8
; CHECK-NEXT: adrp x8, __security_cookie
; CHECK-NEXT: ldr x10, [sp, #8]
; CHECK-NEXT: ldr x8, [x8, :lo12:__security_cookie]
; CHECK-NEXT: cmp x8, x10
; CHECK-NEXT: b.ne .LBB1_2
; CHECK-NEXT: // %bb.1:
; CHECK-NEXT: fmov d0, #1.00000000
; CHECK-NEXT: .seh_startepilogue
; CHECK-NEXT: ldr x30, [sp, #16]
; CHECK-NEXT: .seh_save_reg x30, 16
; CHECK-NEXT: add sp, sp, #32
; CHECK-NEXT: .seh_stackalloc 32
; CHECK-NEXT: .seh_endepilogue
; CHECK-NEXT: br x11

entry:
%call = tail call double %g(double noundef 1.000000e+00)
ret void
}
Loading