Skip to content

Commit ee9e786

Browse files
authored
[aarch64] Add support for the __{inc|add}x18{byte|word|dword|qword intrinsics (#117752)
Adds support for the following MSVC intrinsics: * `__addx18byte` * `__addx18word` * `__addx18dword` * `__addx18qword` * `__incx18byte` * `__incx18word` * `__incx18dword` * `__incx18qword` These are documented at: <https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=msvc-170>
1 parent 3dcc52d commit ee9e786

File tree

4 files changed

+260
-33
lines changed

4 files changed

+260
-33
lines changed

clang/include/clang/Basic/BuiltinsAArch64.def

+10
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,16 @@ TARGET_HEADER_BUILTIN(__readx18word, "UsUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
281281
TARGET_HEADER_BUILTIN(__readx18dword, "UNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
282282
TARGET_HEADER_BUILTIN(__readx18qword, "ULLiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
283283

284+
TARGET_HEADER_BUILTIN(__addx18byte, "vUNiUc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
285+
TARGET_HEADER_BUILTIN(__addx18word, "vUNiUs", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
286+
TARGET_HEADER_BUILTIN(__addx18dword, "vUNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
287+
TARGET_HEADER_BUILTIN(__addx18qword, "vUNiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
288+
289+
TARGET_HEADER_BUILTIN(__incx18byte, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
290+
TARGET_HEADER_BUILTIN(__incx18word, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
291+
TARGET_HEADER_BUILTIN(__incx18dword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
292+
TARGET_HEADER_BUILTIN(__incx18qword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
293+
284294
TARGET_HEADER_BUILTIN(_CopyDoubleFromInt64, "dSLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
285295
TARGET_HEADER_BUILTIN(_CopyFloatFromInt32, "fSi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
286296
TARGET_HEADER_BUILTIN(_CopyInt32FromFloat, "Sif", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")

clang/lib/CodeGen/CGBuiltin.cpp

+80-21
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,19 @@ static Value *handleAsDoubleBuiltin(CodeGenFunction &CGF, const CallExpr *E) {
244244
return CGF.Builder.CreateBitCast(BitVec, ResultType);
245245
}
246246

247+
/// Helper for the read/write/add/inc X18 builtins: read the X18 register and
248+
/// return it as an i8 pointer.
249+
Value *readX18AsPtr(CodeGenFunction &CGF) {
250+
LLVMContext &Context = CGF.CGM.getLLVMContext();
251+
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
252+
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
253+
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
254+
llvm::Function *F =
255+
CGF.CGM.getIntrinsic(llvm::Intrinsic::read_register, {CGF.Int64Ty});
256+
llvm::Value *X18 = CGF.Builder.CreateCall(F, Metadata);
257+
return CGF.Builder.CreateIntToPtr(X18, CGF.Int8PtrTy);
258+
}
259+
247260
/// getBuiltinLibFunction - Given a builtin id for a function like
248261
/// "__builtin_fabsf", return a Function* for "fabsf".
249262
llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
@@ -11836,47 +11849,93 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
1183611849
BuiltinID == AArch64::BI__writex18word ||
1183711850
BuiltinID == AArch64::BI__writex18dword ||
1183811851
BuiltinID == AArch64::BI__writex18qword) {
11852+
// Process the args first
11853+
Value *OffsetArg = EmitScalarExpr(E->getArg(0));
11854+
Value *DataArg = EmitScalarExpr(E->getArg(1));
11855+
1183911856
// Read x18 as i8*
11840-
LLVMContext &Context = CGM.getLLVMContext();
11841-
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
11842-
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
11843-
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
11844-
llvm::Function *F =
11845-
CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
11846-
llvm::Value *X18 = Builder.CreateCall(F, Metadata);
11847-
X18 = Builder.CreateIntToPtr(X18, Int8PtrTy);
11857+
llvm::Value *X18 = readX18AsPtr(*this);
1184811858

1184911859
// Store val at x18 + offset
11850-
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
11860+
Value *Offset = Builder.CreateZExt(OffsetArg, Int64Ty);
1185111861
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
11852-
Value *Val = EmitScalarExpr(E->getArg(1));
11853-
StoreInst *Store = Builder.CreateAlignedStore(Val, Ptr, CharUnits::One());
11862+
StoreInst *Store =
11863+
Builder.CreateAlignedStore(DataArg, Ptr, CharUnits::One());
1185411864
return Store;
1185511865
}
1185611866

1185711867
if (BuiltinID == AArch64::BI__readx18byte ||
1185811868
BuiltinID == AArch64::BI__readx18word ||
1185911869
BuiltinID == AArch64::BI__readx18dword ||
1186011870
BuiltinID == AArch64::BI__readx18qword) {
11861-
llvm::Type *IntTy = ConvertType(E->getType());
11871+
// Process the args first
11872+
Value *OffsetArg = EmitScalarExpr(E->getArg(0));
1186211873

1186311874
// Read x18 as i8*
11864-
LLVMContext &Context = CGM.getLLVMContext();
11865-
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
11866-
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
11867-
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
11868-
llvm::Function *F =
11869-
CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
11870-
llvm::Value *X18 = Builder.CreateCall(F, Metadata);
11871-
X18 = Builder.CreateIntToPtr(X18, Int8PtrTy);
11875+
llvm::Value *X18 = readX18AsPtr(*this);
1187211876

1187311877
// Load x18 + offset
11874-
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
11878+
Value *Offset = Builder.CreateZExt(OffsetArg, Int64Ty);
1187511879
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
11880+
llvm::Type *IntTy = ConvertType(E->getType());
1187611881
LoadInst *Load = Builder.CreateAlignedLoad(IntTy, Ptr, CharUnits::One());
1187711882
return Load;
1187811883
}
1187911884

11885+
if (BuiltinID == AArch64::BI__addx18byte ||
11886+
BuiltinID == AArch64::BI__addx18word ||
11887+
BuiltinID == AArch64::BI__addx18dword ||
11888+
BuiltinID == AArch64::BI__addx18qword ||
11889+
BuiltinID == AArch64::BI__incx18byte ||
11890+
BuiltinID == AArch64::BI__incx18word ||
11891+
BuiltinID == AArch64::BI__incx18dword ||
11892+
BuiltinID == AArch64::BI__incx18qword) {
11893+
llvm::Type *IntTy;
11894+
bool isIncrement;
11895+
switch (BuiltinID) {
11896+
case AArch64::BI__incx18byte:
11897+
IntTy = Int8Ty;
11898+
isIncrement = true;
11899+
break;
11900+
case AArch64::BI__incx18word:
11901+
IntTy = Int16Ty;
11902+
isIncrement = true;
11903+
break;
11904+
case AArch64::BI__incx18dword:
11905+
IntTy = Int32Ty;
11906+
isIncrement = true;
11907+
break;
11908+
case AArch64::BI__incx18qword:
11909+
IntTy = Int64Ty;
11910+
isIncrement = true;
11911+
break;
11912+
default:
11913+
IntTy = ConvertType(E->getArg(1)->getType());
11914+
isIncrement = false;
11915+
break;
11916+
}
11917+
// Process the args first
11918+
Value *OffsetArg = EmitScalarExpr(E->getArg(0));
11919+
Value *ValToAdd =
11920+
isIncrement ? ConstantInt::get(IntTy, 1) : EmitScalarExpr(E->getArg(1));
11921+
11922+
// Read x18 as i8*
11923+
llvm::Value *X18 = readX18AsPtr(*this);
11924+
11925+
// Load x18 + offset
11926+
Value *Offset = Builder.CreateZExt(OffsetArg, Int64Ty);
11927+
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
11928+
LoadInst *Load = Builder.CreateAlignedLoad(IntTy, Ptr, CharUnits::One());
11929+
11930+
// Add values
11931+
Value *AddResult = Builder.CreateAdd(Load, ValToAdd);
11932+
11933+
// Store val at x18 + offset
11934+
StoreInst *Store =
11935+
Builder.CreateAlignedStore(AddResult, Ptr, CharUnits::One());
11936+
return Store;
11937+
}
11938+
1188011939
if (BuiltinID == AArch64::BI_CopyDoubleFromInt64 ||
1188111940
BuiltinID == AArch64::BI_CopyFloatFromInt32 ||
1188211941
BuiltinID == AArch64::BI_CopyInt32FromFloat ||

clang/lib/Headers/intrin.h

+10
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,16 @@ unsigned short __readx18word(unsigned long offset);
396396
unsigned long __readx18dword(unsigned long offset);
397397
unsigned __int64 __readx18qword(unsigned long offset);
398398

399+
void __addx18byte(unsigned long offset, unsigned char data);
400+
void __addx18word(unsigned long offset, unsigned short data);
401+
void __addx18dword(unsigned long offset, unsigned long data);
402+
void __addx18qword(unsigned long offset, unsigned __int64 data);
403+
404+
void __incx18byte(unsigned long offset);
405+
void __incx18word(unsigned long offset);
406+
void __incx18dword(unsigned long offset);
407+
void __incx18qword(unsigned long offset);
408+
399409
double _CopyDoubleFromInt64(__int64);
400410
float _CopyFloatFromInt32(__int32);
401411
__int32 _CopyInt32FromFloat(float);

0 commit comments

Comments
 (0)